528 lines
13 KiB
Go
528 lines
13 KiB
Go
package nagios
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/influxdata/telegraf"
|
|
"github.com/influxdata/telegraf/metric"
|
|
"github.com/influxdata/telegraf/testutil"
|
|
)
|
|
|
|
func TestGetExitCode(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
errF func() error
|
|
expCode int
|
|
expErr error
|
|
}{
|
|
{
|
|
name: "nil error passed is ok",
|
|
errF: func() error {
|
|
return nil
|
|
},
|
|
expCode: 0,
|
|
expErr: nil,
|
|
},
|
|
{
|
|
name: "unexpected error type",
|
|
errF: func() error {
|
|
return errors.New("I am not *exec.ExitError")
|
|
},
|
|
expCode: 0,
|
|
expErr: errors.New("expected *exec.ExitError"),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
e := tt.errF()
|
|
code, err := getExitCode(e)
|
|
|
|
require.Equal(t, tt.expCode, code)
|
|
require.Equal(t, tt.expErr, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
type metricBuilder struct {
|
|
name string
|
|
tags map[string]string
|
|
fields map[string]interface{}
|
|
timestamp time.Time
|
|
}
|
|
|
|
func mb() *metricBuilder {
|
|
return &metricBuilder{}
|
|
}
|
|
|
|
func (b *metricBuilder) n(v string) *metricBuilder {
|
|
b.name = v
|
|
return b
|
|
}
|
|
|
|
func (b *metricBuilder) t(k, v string) *metricBuilder {
|
|
if b.tags == nil {
|
|
b.tags = make(map[string]string)
|
|
}
|
|
b.tags[k] = v
|
|
return b
|
|
}
|
|
|
|
func (b *metricBuilder) f(k string, v interface{}) *metricBuilder {
|
|
if b.fields == nil {
|
|
b.fields = make(map[string]interface{})
|
|
}
|
|
b.fields[k] = v
|
|
return b
|
|
}
|
|
|
|
func (b *metricBuilder) ts(v time.Time) *metricBuilder {
|
|
b.timestamp = v
|
|
return b
|
|
}
|
|
|
|
func (b *metricBuilder) b() telegraf.Metric {
|
|
m, err := metric.New(b.name, b.tags, b.fields, b.timestamp)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return m
|
|
}
|
|
|
|
// assertEqual asserts two slices to be equal. Note, that the order
|
|
// of the entries matters.
|
|
func assertEqual(t *testing.T, exp, actual []telegraf.Metric) {
|
|
require.Equal(t, len(exp), len(actual))
|
|
for i := 0; i < len(exp); i++ {
|
|
ok := testutil.MetricEqual(exp[i], actual[i])
|
|
require.True(t, ok)
|
|
}
|
|
}
|
|
|
|
func TestTryAddState(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
runErrF func() error
|
|
metrics []telegraf.Metric
|
|
assertF func(*testing.T, []telegraf.Metric, error)
|
|
}{
|
|
{
|
|
name: "should append state=0 field to existing metric",
|
|
runErrF: func() error {
|
|
return nil
|
|
},
|
|
metrics: []telegraf.Metric{
|
|
mb().
|
|
n("nagios").
|
|
f("perfdata", 0).b(),
|
|
mb().
|
|
n("nagios_state").
|
|
f("service_output", "OK: system working").b(),
|
|
},
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
exp := []telegraf.Metric{
|
|
mb().
|
|
n("nagios").
|
|
f("perfdata", 0).b(),
|
|
mb().
|
|
n("nagios_state").
|
|
f("service_output", "OK: system working").
|
|
f("state", 0).b(),
|
|
}
|
|
assertEqual(t, exp, metrics)
|
|
require.NoError(t, err)
|
|
},
|
|
},
|
|
{
|
|
name: "should create 'nagios_state state=0' and same timestamp as others",
|
|
runErrF: func() error {
|
|
return nil
|
|
},
|
|
metrics: []telegraf.Metric{
|
|
mb().
|
|
n("nagios").
|
|
f("perfdata", 0).b(),
|
|
},
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
exp := []telegraf.Metric{
|
|
mb().
|
|
n("nagios").
|
|
f("perfdata", 0).b(),
|
|
mb().
|
|
n("nagios_state").
|
|
f("state", 0).b(),
|
|
}
|
|
assertEqual(t, exp, metrics)
|
|
require.NoError(t, err)
|
|
},
|
|
},
|
|
{
|
|
name: "should create 'nagios_state state=0' and recent timestamp",
|
|
runErrF: func() error {
|
|
return nil
|
|
},
|
|
metrics: []telegraf.Metric{},
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.Len(t, metrics, 1)
|
|
m := metrics[0]
|
|
require.Equal(t, "nagios_state", m.Name())
|
|
s, ok := m.GetField("state")
|
|
require.True(t, ok)
|
|
require.Equal(t, int64(0), s)
|
|
require.WithinDuration(t, time.Now().UTC(), m.Time(), 10*time.Second)
|
|
require.NoError(t, err)
|
|
},
|
|
},
|
|
{
|
|
name: "should return original metrics and an error",
|
|
runErrF: func() error {
|
|
return errors.New("non parsable error")
|
|
},
|
|
metrics: []telegraf.Metric{
|
|
mb().
|
|
n("nagios").
|
|
f("perfdata", 0).b(),
|
|
},
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
exp := []telegraf.Metric{
|
|
mb().
|
|
n("nagios").
|
|
f("perfdata", 0).b(),
|
|
}
|
|
expErr := "exec: get exit code: expected *exec.ExitError"
|
|
|
|
assertEqual(t, exp, metrics)
|
|
require.Equal(t, expErr, err.Error())
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
metrics, err := TryAddState(tt.runErrF(), tt.metrics)
|
|
tt.assertF(t, metrics, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func assertNagiosState(t *testing.T, m telegraf.Metric, f map[string]interface{}) {
|
|
assert.Equal(t, map[string]string{}, m.Tags())
|
|
assert.Equal(t, f, m.Fields())
|
|
}
|
|
|
|
func TestParse(t *testing.T) {
|
|
parser := NagiosParser{
|
|
MetricName: "nagios_test",
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
assertF func(*testing.T, []telegraf.Metric, error)
|
|
}{
|
|
{
|
|
name: "valid output 1",
|
|
input: `PING OK - Packet loss = 0%, RTA = 0.30 ms|rta=0.298000ms;4000.000000;6000.000000;0.000000 pl=0%;80;90;0;100
|
|
This is a long output
|
|
with three lines
|
|
`,
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.NoError(t, err)
|
|
require.Len(t, metrics, 3)
|
|
// rta
|
|
assert.Equal(t, map[string]string{
|
|
"unit": "ms",
|
|
"perfdata": "rta",
|
|
}, metrics[0].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(0.298),
|
|
"warning_lt": float64(0),
|
|
"warning_gt": float64(4000),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(6000),
|
|
"min": float64(0),
|
|
}, metrics[0].Fields())
|
|
|
|
// pl
|
|
assert.Equal(t, map[string]string{
|
|
"unit": "%",
|
|
"perfdata": "pl",
|
|
}, metrics[1].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(0),
|
|
"warning_lt": float64(0),
|
|
"warning_gt": float64(80),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(90),
|
|
"min": float64(0),
|
|
"max": float64(100),
|
|
}, metrics[1].Fields())
|
|
|
|
assertNagiosState(t, metrics[2], map[string]interface{}{
|
|
"service_output": "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
|
"long_service_output": "This is a long output\nwith three lines",
|
|
})
|
|
},
|
|
},
|
|
{
|
|
name: "valid output 2",
|
|
input: "TCP OK - 0.008 second response time on port 80|time=0.008457s;;;0.000000;10.000000",
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.NoError(t, err)
|
|
require.Len(t, metrics, 2)
|
|
// time
|
|
assert.Equal(t, map[string]string{
|
|
"unit": "s",
|
|
"perfdata": "time",
|
|
}, metrics[0].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(0.008457),
|
|
"min": float64(0),
|
|
"max": float64(10),
|
|
}, metrics[0].Fields())
|
|
|
|
assertNagiosState(t, metrics[1], map[string]interface{}{
|
|
"service_output": "TCP OK - 0.008 second response time on port 80",
|
|
})
|
|
},
|
|
},
|
|
{
|
|
name: "valid output 3",
|
|
input: "TCP OK - 0.008 second response time on port 80|time=0.008457",
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.NoError(t, err)
|
|
require.Len(t, metrics, 2)
|
|
// time
|
|
assert.Equal(t, map[string]string{
|
|
"perfdata": "time",
|
|
}, metrics[0].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(0.008457),
|
|
}, metrics[0].Fields())
|
|
|
|
assertNagiosState(t, metrics[1], map[string]interface{}{
|
|
"service_output": "TCP OK - 0.008 second response time on port 80",
|
|
})
|
|
},
|
|
},
|
|
{
|
|
name: "valid output 4",
|
|
input: "OK: Load average: 0.00, 0.01, 0.05 | 'load1'=0.00;~:4;@0:6;0; 'load5'=0.01;3;0:5;0; 'load15'=0.05;0:2;0:4;0;",
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.NoError(t, err)
|
|
require.Len(t, metrics, 4)
|
|
// load1
|
|
assert.Equal(t, map[string]string{
|
|
"perfdata": "load1",
|
|
}, metrics[0].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(0.00),
|
|
"warning_lt": MinFloat64,
|
|
"warning_gt": float64(4),
|
|
"critical_le": float64(0),
|
|
"critical_ge": float64(6),
|
|
"min": float64(0),
|
|
}, metrics[0].Fields())
|
|
|
|
// load5
|
|
assert.Equal(t, map[string]string{
|
|
"perfdata": "load5",
|
|
}, metrics[1].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(0.01),
|
|
"warning_gt": float64(3),
|
|
"warning_lt": float64(0),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(5),
|
|
"min": float64(0),
|
|
}, metrics[1].Fields())
|
|
|
|
// load15
|
|
assert.Equal(t, map[string]string{
|
|
"perfdata": "load15",
|
|
}, metrics[2].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(0.05),
|
|
"warning_lt": float64(0),
|
|
"warning_gt": float64(2),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(4),
|
|
"min": float64(0),
|
|
}, metrics[2].Fields())
|
|
|
|
assertNagiosState(t, metrics[3], map[string]interface{}{
|
|
"service_output": "OK: Load average: 0.00, 0.01, 0.05",
|
|
})
|
|
},
|
|
},
|
|
{
|
|
name: "no perf data",
|
|
input: "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.NoError(t, err)
|
|
require.Len(t, metrics, 1)
|
|
|
|
assertNagiosState(t, metrics[0], map[string]interface{}{
|
|
"service_output": "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
|
})
|
|
},
|
|
},
|
|
{
|
|
name: "malformed perf data",
|
|
input: "PING OK - Packet loss = 0%, RTA = 0.30 ms| =3;;;; dgasdg =;;;; sff=;;;;",
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.NoError(t, err)
|
|
require.Len(t, metrics, 1)
|
|
|
|
assertNagiosState(t, metrics[0], map[string]interface{}{
|
|
"service_output": "PING OK - Packet loss = 0%, RTA = 0.30 ms",
|
|
})
|
|
},
|
|
},
|
|
{
|
|
name: "from https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html",
|
|
input: `DISK OK - free space: / 3326 MB (56%); | /=2643MB;5948;5958;0;5968
|
|
/ 15272 MB (77%);
|
|
/boot 68 MB (69%);
|
|
/home 69357 MB (27%);
|
|
/var/log 819 MB (84%); | /boot=68MB;88;93;0;98
|
|
/home=69357MB;253404;253409;0;253414
|
|
/var/log=818MB;970;975;0;980
|
|
`,
|
|
assertF: func(t *testing.T, metrics []telegraf.Metric, err error) {
|
|
require.NoError(t, err)
|
|
require.Len(t, metrics, 5)
|
|
// /=2643MB;5948;5958;0;5968
|
|
assert.Equal(t, map[string]string{
|
|
"unit": "MB",
|
|
"perfdata": "/",
|
|
}, metrics[0].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(2643),
|
|
"warning_lt": float64(0),
|
|
"warning_gt": float64(5948),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(5958),
|
|
"min": float64(0),
|
|
"max": float64(5968),
|
|
}, metrics[0].Fields())
|
|
|
|
// /boot=68MB;88;93;0;98
|
|
assert.Equal(t, map[string]string{
|
|
"unit": "MB",
|
|
"perfdata": "/boot",
|
|
}, metrics[1].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(68),
|
|
"warning_lt": float64(0),
|
|
"warning_gt": float64(88),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(93),
|
|
"min": float64(0),
|
|
"max": float64(98),
|
|
}, metrics[1].Fields())
|
|
|
|
// /home=69357MB;253404;253409;0;253414
|
|
assert.Equal(t, map[string]string{
|
|
"unit": "MB",
|
|
"perfdata": "/home",
|
|
}, metrics[2].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(69357),
|
|
"warning_lt": float64(0),
|
|
"warning_gt": float64(253404),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(253409),
|
|
"min": float64(0),
|
|
"max": float64(253414),
|
|
}, metrics[2].Fields())
|
|
|
|
// /var/log=818MB;970;975;0;980
|
|
assert.Equal(t, map[string]string{
|
|
"unit": "MB",
|
|
"perfdata": "/var/log",
|
|
}, metrics[3].Tags())
|
|
assert.Equal(t, map[string]interface{}{
|
|
"value": float64(818),
|
|
"warning_lt": float64(0),
|
|
"warning_gt": float64(970),
|
|
"critical_lt": float64(0),
|
|
"critical_gt": float64(975),
|
|
"min": float64(0),
|
|
"max": float64(980),
|
|
}, metrics[3].Fields())
|
|
|
|
assertNagiosState(t, metrics[4], map[string]interface{}{
|
|
"service_output": "DISK OK - free space: / 3326 MB (56%);",
|
|
"long_service_output": "/ 15272 MB (77%);\n/boot 68 MB (69%);\n/home 69357 MB (27%);\n/var/log 819 MB (84%);",
|
|
})
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
metrics, err := parser.Parse([]byte(tt.input))
|
|
tt.assertF(t, metrics, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseThreshold(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
eMin float64
|
|
eMax float64
|
|
eErr error
|
|
}{
|
|
{
|
|
input: "10",
|
|
eMin: 0,
|
|
eMax: 10,
|
|
eErr: nil,
|
|
},
|
|
{
|
|
input: "10:",
|
|
eMin: 10,
|
|
eMax: MaxFloat64,
|
|
eErr: nil,
|
|
},
|
|
{
|
|
input: "~:10",
|
|
eMin: MinFloat64,
|
|
eMax: 10,
|
|
eErr: nil,
|
|
},
|
|
{
|
|
input: "10:20",
|
|
eMin: 10,
|
|
eMax: 20,
|
|
eErr: nil,
|
|
},
|
|
{
|
|
input: "10:20",
|
|
eMin: 10,
|
|
eMax: 20,
|
|
eErr: nil,
|
|
},
|
|
{
|
|
input: "10:20:30",
|
|
eMin: 0,
|
|
eMax: 0,
|
|
eErr: ErrBadThresholdFormat,
|
|
},
|
|
}
|
|
|
|
for i := range tests {
|
|
min, max, err := parseThreshold(tests[i].input)
|
|
require.Equal(t, tests[i].eMin, min)
|
|
require.Equal(t, tests[i].eMax, max)
|
|
require.Equal(t, tests[i].eErr, err)
|
|
}
|
|
}
|