Skip to content

Commit

Permalink
Merge pull request #55 from snetsystems/release-1.23-snet-jinhyeong
Browse files Browse the repository at this point in the history
At #54 Update impi_sensor plugin to include hostname as tag value
  • Loading branch information
snetsystems committed Aug 16, 2023
2 parents 147f128 + b82e268 commit f568f73
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 58 deletions.
24 changes: 20 additions & 4 deletions plugins/inputs/ipmi_sensor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@ they're configured:
# privilege = "ADMINISTRATOR"
##
## optionally specify one or more servers via a url matching
## [username[:password]@][protocol[(address)]]
## optionally specify hostname tag
## [username[:password]@][protocol[(address),hostname]]
## e.g.
## root:passwd@lan(127.0.0.1)
## root:passwd@lan(127.0.0.1),example_host
##
## 'hostname' is an optional tag to identify the server
## if no hostname is entered, the hostname tag will not be generated
## if no servers are specified, local machine sensor stats will be queried
##
# servers = ["USERID:PASSW0RD@lan(192.168.1.1)"]
# v = ["USERID:PASSW0RD@lan(192.168.1.1),example_host"]

## Recommended: use metric 'interval' that is a multiple of 'timeout' to avoid
## gaps or overlap in pulled data
Expand Down Expand Up @@ -88,6 +91,7 @@ Version 1 schema:
- unit
- host
- server (only when retrieving stats from remote servers)
- hostname (only when hostname entered in server connect info)
- fields:
- status (int, 1=ok status_code/0=anything else)
- value (float)
Expand All @@ -103,13 +107,14 @@ Version 2 schema:
- unit (only on analog values)
- host
- server (only when retrieving stats from remote)
- hostname (only when hostname entered in server connect info)
- fields:
- value (float)

### Permissions

When gathering from the local system, Telegraf will need permission to the
ipmi device node. When using udev you can create the device node giving
ipmi device node. When using udev you can create the device node giving
`rw` permissions to the `telegraf` user by adding the following rule to
`/etc/udev/rules.d/52-telegraf-ipmi.rules`:

Expand Down Expand Up @@ -150,6 +155,17 @@ ipmi_sensor,server=10.20.2.203,name=power_supplies value=0,status=1i 15171255130
ipmi_sensor,server=10.20.2.203,name=fan_1,unit=percent status=1i,value=43.12 1517125513000000000
```

When retrieving stats from a remote server(hostname specified):

```shell
ipmi_sensor,server=10.20.2.203,hostname=example_host,name=uid_light value=0,status=1i 1517125513000000000
ipmi_sensor,server=10.20.2.203,hostname=example_host,name=sys._health_led status=1i,value=0 1517125513000000000
ipmi_sensor,server=10.20.2.203,hostname=example_host,name=power_supply_1,unit=watts status=1i,value=110 1517125513000000000
ipmi_sensor,server=10.20.2.203,hostname=example_host,name=power_supply_2,unit=watts status=1i,value=120 1517125513000000000
ipmi_sensor,server=10.20.2.203,hostname=example_host,name=power_supplies value=0,status=1i 1517125513000000000
ipmi_sensor,server=10.20.2.203,hostname=example_host,name=fan_1,unit=percent status=1i,value=43.12 1517125513000000000
```

When retrieving stats from the local machine (no server specified):

```shell
Expand Down
15 changes: 8 additions & 7 deletions plugins/inputs/ipmi_sensor/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Connection struct {
Interface string
Privilege string
HexKey string
IpmiIP string
}

func NewConnection(server, privilege, hexKey string) *Connection {
Expand Down Expand Up @@ -43,7 +44,7 @@ func NewConnection(server, privilege, hexKey string) *Connection {
inx3 := strings.Index(connstr, ")")

conn.Interface = connstr[0:inx2]
conn.Hostname = connstr[inx2+1 : inx3]
conn.IpmiIP = connstr[inx2+1 : inx3]
}

return conn
Expand All @@ -56,7 +57,7 @@ func (c *Connection) options() []string {
}

options := []string{
"-H", c.Hostname,
"-H", c.IpmiIP,
"-U", c.Username,
"-P", c.Password,
"-I", intf,
Expand All @@ -76,22 +77,22 @@ func (c *Connection) options() []string {

// 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 net.ParseIP(c.IpmiIP) == nil {
addrs, err := net.LookupHost(c.IpmiIP)
if err != nil && len(addrs) > 0 {
return addrs[0]
}
}
return c.Hostname
return c.IpmiIP
}

// 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))
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", c.IpmiIP, 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
return c.IpmiIP
}
_ = conn.Close()
host, _, _ := net.SplitHostPort(conn.LocalAddr().String())
Expand Down
14 changes: 7 additions & 7 deletions plugins/inputs/ipmi_sensor/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ func TestNewConnection(t *testing.T) {
con *Connection
}{
{
"USERID:PASSW0RD@lan(192.168.1.1)",
"USERID:PASSW0RD@lan(192.168.1.1),host",
&Connection{
Hostname: "192.168.1.1",
IpmiIP: "192.168.1.1",
Username: "USERID",
Password: "PASSW0RD",
Interface: "lan",
Expand All @@ -23,9 +23,9 @@ func TestNewConnection(t *testing.T) {
},
},
{
"USERID:PASS:!@#$%^&*(234)_+W0RD@lan(192.168.1.1)",
"USERID:PASS:!@#$%^&*(234)_+W0RD@lan(192.168.1.1),",
&Connection{
Hostname: "192.168.1.1",
IpmiIP: "192.168.1.1",
Username: "USERID",
Password: "PASS:!@#$%^&*(234)_+W0RD",
Interface: "lan",
Expand All @@ -37,7 +37,7 @@ func TestNewConnection(t *testing.T) {
{
"USERID@PASSW0RD@lan(192.168.1.1)",
&Connection{
Hostname: "192.168.1.1",
IpmiIP: "192.168.1.1",
Username: "",
Password: "",
Interface: "lan",
Expand All @@ -59,7 +59,7 @@ func TestGetCommandOptions(t *testing.T) {
}{
{
&Connection{
Hostname: "192.168.1.1",
IpmiIP: "192.168.1.1",
Username: "user",
Password: "password",
Interface: "lan",
Expand All @@ -70,7 +70,7 @@ func TestGetCommandOptions(t *testing.T) {
},
{
&Connection{
Hostname: "192.168.1.1",
IpmiIP: "192.168.1.1",
Username: "user",
Password: "password",
Interface: "lan",
Expand Down
31 changes: 22 additions & 9 deletions plugins/inputs/ipmi_sensor/ipmi_sensor.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
)

// DO NOT REMOVE THE NEXT TWO LINES! This is required to embed the sampleConfig data.
//
//go:embed sample.conf
var sampleConfig string

Expand Down Expand Up @@ -106,10 +107,16 @@ func (m *Ipmi) Gather(acc telegraf.Accumulator) error {

func (m *Ipmi) parse(acc telegraf.Accumulator, server string) error {
opts := make([]string, 0)
ipmiIP := ""
hostname := ""
if server != "" {
lastIndex := strings.LastIndex(server, ",")
if lastIndex > 1 && server[lastIndex+1:] != "" {
hostname = trim(server[lastIndex+1:])
}

conn := NewConnection(server, m.Privilege, m.HexKey)
hostname = conn.Hostname
ipmiIP = conn.IpmiIP
opts = conn.options()
}
opts = append(opts, "sdr")
Expand Down Expand Up @@ -152,16 +159,17 @@ func (m *Ipmi) parse(acc telegraf.Accumulator, server string) error {
return fmt.Errorf("failed to run command %s: %s - %s", strings.Join(sanitizeIPMICmd(cmd.Args), " "), err, string(out))
}
if m.MetricVersion == 2 {
return m.parseV2(acc, hostname, out, timestamp)
return m.parseV2(acc, ipmiIP, hostname, out, timestamp)
}
return m.parseV1(acc, hostname, out, timestamp)
return m.parseV1(acc, ipmiIP, hostname, out, timestamp)
}

func (m *Ipmi) parseV1(acc telegraf.Accumulator, hostname string, cmdOut []byte, measuredAt time.Time) error {
func (m *Ipmi) parseV1(acc telegraf.Accumulator, ipmiIP string, hostname string, cmdOut []byte, measuredAt time.Time) error {
// each line will look something like
// Planar VBAT | 3.05 Volts | ok
scanner := bufio.NewScanner(bytes.NewReader(cmdOut))
for scanner.Scan() {

ipmiFields := m.extractFieldsFromRegex(reV1ParseLine, scanner.Text())
if len(ipmiFields) != 3 {
continue
Expand All @@ -172,8 +180,11 @@ func (m *Ipmi) parseV1(acc telegraf.Accumulator, hostname string, cmdOut []byte,
}

// tag the server is we have one
if ipmiIP != "" {
tags["server"] = ipmiIP
}
if hostname != "" {
tags["server"] = hostname
tags["hostname"] = hostname
}

fields := make(map[string]interface{})
Expand All @@ -184,7 +195,6 @@ func (m *Ipmi) parseV1(acc telegraf.Accumulator, hostname string, cmdOut []byte,
}

description := ipmiFields["description"]

// handle hex description field
if strings.HasPrefix(description, "0x") {
descriptionInt, err := strconv.ParseInt(description, 0, 64)
Expand Down Expand Up @@ -214,7 +224,7 @@ func (m *Ipmi) parseV1(acc telegraf.Accumulator, hostname string, cmdOut []byte,
return scanner.Err()
}

func (m *Ipmi) parseV2(acc telegraf.Accumulator, hostname string, cmdOut []byte, measuredAt time.Time) error {
func (m *Ipmi) parseV2(acc telegraf.Accumulator, ipmiIP string, hostname string, cmdOut []byte, measuredAt time.Time) error {
// each line will look something like
// CMOS Battery | 65h | ok | 7.1 |
// Temp | 0Eh | ok | 3.1 | 55 degrees C
Expand All @@ -230,9 +240,12 @@ func (m *Ipmi) parseV2(acc telegraf.Accumulator, hostname string, cmdOut []byte,
"name": transform(ipmiFields["name"]),
}

// tag the server is we have one
// tag the server is we have oneserver
if ipmiIP != "" {
tags["server"] = ipmiIP
}
if hostname != "" {
tags["server"] = hostname
tags["hostname"] = hostname
}
tags["entity_id"] = transform(ipmiFields["entity_id"])
tags["status_code"] = trim(ipmiFields["status_code"])
Expand Down

0 comments on commit f568f73

Please sign in to comment.