Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
69
plugins/inputs/apcupsd/README.md
Normal file
69
plugins/inputs/apcupsd/README.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
# APC UPSD Input Plugin
|
||||
|
||||
This plugin gathers data from one or more [apcupsd daemon][apcupsd_daemon] over
|
||||
the NIS network protocol. To query a server, the daemon must be running and be
|
||||
accessible.
|
||||
|
||||
⭐ Telegraf v1.12.0
|
||||
🏷️ hardware, server
|
||||
💻 all
|
||||
|
||||
[apcupsd_daemon]: https://sourceforge.net/projects/apcupsd/
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Monitor APC UPSes connected to apcupsd
|
||||
[[inputs.apcupsd]]
|
||||
# A list of running apcupsd server to connect to.
|
||||
# If not provided will default to tcp://127.0.0.1:3551
|
||||
servers = ["tcp://127.0.0.1:3551"]
|
||||
|
||||
## Timeout for dialing server.
|
||||
timeout = "5s"
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
- apcupsd
|
||||
- tags:
|
||||
- serial
|
||||
- ups_name
|
||||
- status (string representing the set status_flags)
|
||||
- model
|
||||
- fields:
|
||||
- status_flags ([status-bits][])
|
||||
- input_voltage
|
||||
- load_percent
|
||||
- battery_charge_percent
|
||||
- time_left_ns
|
||||
- output_voltage
|
||||
- internal_temp
|
||||
- battery_voltage
|
||||
- input_frequency
|
||||
- time_on_battery_ns
|
||||
- cumulative_time_on_battery_ns
|
||||
- nominal_input_voltage
|
||||
- nominal_battery_voltage
|
||||
- nominal_power
|
||||
- firmware
|
||||
- battery_date
|
||||
- last_transfer
|
||||
- number_transfers
|
||||
|
||||
## Example Output
|
||||
|
||||
```text
|
||||
apcupsd,serial=AS1231515,status=ONLINE,ups_name=name1 time_on_battery=0,load_percent=9.7,time_left_minutes=98,output_voltage=230.4,internal_temp=32.4,battery_voltage=27.4,input_frequency=50.2,input_voltage=230.4,battery_charge_percent=100,status_flags=8i 1490035922000000000
|
||||
```
|
||||
|
||||
[status-bits]: http://www.apcupsd.org/manual/manual.html#status-bits
|
117
plugins/inputs/apcupsd/apcupsd.go
Normal file
117
plugins/inputs/apcupsd/apcupsd.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package apcupsd
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mdlayher/apcupsd"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
const defaultAddress = "tcp://127.0.0.1:3551"
|
||||
|
||||
var defaultTimeout = config.Duration(5 * time.Second)
|
||||
|
||||
type ApcUpsd struct {
|
||||
Servers []string
|
||||
Timeout config.Duration
|
||||
}
|
||||
|
||||
func (*ApcUpsd) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (h *ApcUpsd) Gather(acc telegraf.Accumulator) error {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, server := range h.Servers {
|
||||
err := func(address string) error {
|
||||
addrBits, err := url.Parse(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if addrBits.Scheme == "" {
|
||||
addrBits.Scheme = "tcp"
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Duration(h.Timeout))
|
||||
defer cancel()
|
||||
|
||||
status, err := fetchStatus(ctx, addrBits)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tags := map[string]string{
|
||||
"serial": status.SerialNumber,
|
||||
"ups_name": status.UPSName,
|
||||
"status": status.Status,
|
||||
"model": status.Model,
|
||||
}
|
||||
|
||||
flags, err := strconv.ParseUint(strings.Fields(status.StatusFlags)[0], 0, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"status_flags": flags,
|
||||
"input_voltage": status.LineVoltage,
|
||||
"load_percent": status.LoadPercent,
|
||||
"battery_charge_percent": status.BatteryChargePercent,
|
||||
"time_left_ns": status.TimeLeft.Nanoseconds(),
|
||||
"output_voltage": status.OutputVoltage,
|
||||
"internal_temp": status.InternalTemp,
|
||||
"battery_voltage": status.BatteryVoltage,
|
||||
"input_frequency": status.LineFrequency,
|
||||
"time_on_battery_ns": status.TimeOnBattery.Nanoseconds(),
|
||||
"cumulative_time_on_battery_ns": status.CumulativeTimeOnBattery.Nanoseconds(),
|
||||
"nominal_input_voltage": status.NominalInputVoltage,
|
||||
"nominal_battery_voltage": status.NominalBatteryVoltage,
|
||||
"nominal_power": status.NominalPower,
|
||||
"firmware": status.Firmware,
|
||||
"battery_date": status.BatteryDate,
|
||||
"last_transfer": status.LastTransfer,
|
||||
"number_transfers": status.NumberTransfers,
|
||||
}
|
||||
|
||||
acc.AddFields("apcupsd", fields, tags)
|
||||
return nil
|
||||
}(server)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchStatus(ctx context.Context, addr *url.URL) (*apcupsd.Status, error) {
|
||||
client, err := apcupsd.DialContext(ctx, addr.Scheme, addr.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
return client.Status()
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("apcupsd", func() telegraf.Input {
|
||||
return &ApcUpsd{
|
||||
Servers: []string{defaultAddress},
|
||||
Timeout: defaultTimeout,
|
||||
}
|
||||
})
|
||||
}
|
252
plugins/inputs/apcupsd/apcupsd_test.go
Normal file
252
plugins/inputs/apcupsd/apcupsd_test.go
Normal file
|
@ -0,0 +1,252 @@
|
|||
package apcupsd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
func TestApcupsdDocs(_ *testing.T) {
|
||||
apc := &ApcUpsd{}
|
||||
apc.SampleConfig()
|
||||
}
|
||||
|
||||
func TestApcupsdInit(t *testing.T) {
|
||||
input, ok := inputs.Inputs["apcupsd"]
|
||||
if !ok {
|
||||
t.Fatal("Input not defined")
|
||||
}
|
||||
|
||||
_ = input().(*ApcUpsd)
|
||||
}
|
||||
|
||||
func listen(ctx context.Context, t *testing.T, out [][]byte) (string, error) {
|
||||
lc := net.ListenConfig{}
|
||||
ln, err := lc.Listen(ctx, "tcp4", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
|
||||
for ctx.Err() == nil {
|
||||
func() {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if err = conn.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
in := make([]byte, 128)
|
||||
n, err := conn.Read(in)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to read to connection: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
status := []byte{0, 6, 's', 't', 'a', 't', 'u', 's'}
|
||||
want, got := status, in[:n]
|
||||
if !bytes.Equal(want, got) {
|
||||
t.Errorf("expected %q, got %q", want, got)
|
||||
return
|
||||
}
|
||||
|
||||
// Run against test function and append EOF to end of output bytes
|
||||
out = append(out, []byte{0, 0})
|
||||
|
||||
for _, o := range out {
|
||||
if _, err := conn.Write(o); err != nil {
|
||||
t.Errorf("Failed to write to connection: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
|
||||
return ln.Addr().String(), nil
|
||||
}
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
apc := &ApcUpsd{Timeout: defaultTimeout}
|
||||
|
||||
var (
|
||||
tests = []struct {
|
||||
name string
|
||||
servers []string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "test listen address no scheme",
|
||||
servers: []string{"127.0.0.1:1234"},
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "test no port",
|
||||
servers: []string{"127.0.0.3"},
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
acc testutil.Accumulator
|
||||
)
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
apc.Servers = tt.servers
|
||||
|
||||
err := apc.Gather(&acc)
|
||||
if tt.err {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApcupsdGather(t *testing.T) {
|
||||
apc := &ApcUpsd{Timeout: defaultTimeout}
|
||||
|
||||
var (
|
||||
tests = []struct {
|
||||
name string
|
||||
err bool
|
||||
tags map[string]string
|
||||
fields map[string]interface{}
|
||||
out func() [][]byte
|
||||
}{
|
||||
{
|
||||
name: "test listening server with output",
|
||||
err: false,
|
||||
tags: map[string]string{
|
||||
"serial": "ABC123",
|
||||
"status": "ONLINE",
|
||||
"ups_name": "BERTHA",
|
||||
"model": "Model 12345",
|
||||
},
|
||||
fields: map[string]interface{}{
|
||||
"status_flags": uint64(8),
|
||||
"input_voltage": float64(0),
|
||||
"load_percent": float64(13),
|
||||
"battery_charge_percent": float64(0),
|
||||
"time_left_ns": int64(2790000000000),
|
||||
"output_voltage": float64(0),
|
||||
"internal_temp": float64(0),
|
||||
"battery_voltage": float64(0),
|
||||
"input_frequency": float64(0),
|
||||
"time_on_battery_ns": int64(0),
|
||||
"cumulative_time_on_battery_ns": int64(85000000000),
|
||||
"nominal_input_voltage": float64(230),
|
||||
"nominal_battery_voltage": float64(12),
|
||||
"nominal_power": 865,
|
||||
"firmware": "857.L3 .I USB FW:L3",
|
||||
"battery_date": "2016-09-06",
|
||||
"last_transfer": "Low line voltage",
|
||||
"number_transfers": 1,
|
||||
},
|
||||
out: genOutput,
|
||||
},
|
||||
{
|
||||
name: "test with bad output",
|
||||
err: true,
|
||||
out: genBadOutput,
|
||||
},
|
||||
}
|
||||
|
||||
acc testutil.Accumulator
|
||||
)
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
|
||||
lAddr, err := listen(ctx, t, tt.out())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
apc.Servers = []string{"tcp://" + lAddr}
|
||||
|
||||
err = apc.Gather(&acc)
|
||||
if tt.err {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
acc.AssertContainsTaggedFields(t, "apcupsd", tt.fields, tt.tags)
|
||||
}
|
||||
cancel()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// The following functionality is straight from apcupsd tests.
|
||||
|
||||
// kvBytes is a helper to generate length and key/value byte buffers.
|
||||
func kvBytes(kv string) (keyValLen, keyVal []byte) {
|
||||
lenb := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(lenb, uint16(len(kv)))
|
||||
|
||||
return lenb, []byte(kv)
|
||||
}
|
||||
|
||||
func genOutput() [][]byte {
|
||||
kvs := []string{
|
||||
"SERIALNO : ABC123",
|
||||
"STATUS : ONLINE",
|
||||
"STATFLAG : 0x08 Status Flag",
|
||||
"UPSNAME : BERTHA",
|
||||
"MODEL : Model 12345",
|
||||
"DATE : 2016-09-06 22:13:28 -0400",
|
||||
"HOSTNAME : example",
|
||||
"LOADPCT : 13.0 Percent Load Capacity",
|
||||
"BATTDATE : 2016-09-06",
|
||||
"TIMELEFT : 46.5 Minutes",
|
||||
"TONBATT : 0 seconds",
|
||||
"CUMONBATT: 85 seconds",
|
||||
"LASTXFER : Low line voltage",
|
||||
"NUMXFERS : 1",
|
||||
"SELFTEST : NO",
|
||||
"NOMINV : 230 Volts",
|
||||
"NOMBATTV : 12.0 Volts",
|
||||
"NOMPOWER : 865 Watts",
|
||||
"FIRMWARE : 857.L3 .I USB FW:L3",
|
||||
"ALARMDEL : Low Battery",
|
||||
}
|
||||
|
||||
out := make([][]byte, 0, 2*len(kvs))
|
||||
for _, kv := range kvs {
|
||||
lenb, kvb := kvBytes(kv)
|
||||
out = append(out, lenb, kvb)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func genBadOutput() [][]byte {
|
||||
kvs := []string{
|
||||
"STATFLAG : 0x08Status Flag",
|
||||
}
|
||||
|
||||
out := make([][]byte, 0, 2*len(kvs))
|
||||
for _, kv := range kvs {
|
||||
lenb, kvb := kvBytes(kv)
|
||||
out = append(out, lenb, kvb)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
8
plugins/inputs/apcupsd/sample.conf
Normal file
8
plugins/inputs/apcupsd/sample.conf
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Monitor APC UPSes connected to apcupsd
|
||||
[[inputs.apcupsd]]
|
||||
# A list of running apcupsd server to connect to.
|
||||
# If not provided will default to tcp://127.0.0.1:3551
|
||||
servers = ["tcp://127.0.0.1:3551"]
|
||||
|
||||
## Timeout for dialing server.
|
||||
timeout = "5s"
|
Loading…
Add table
Add a link
Reference in a new issue