-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquery.go
106 lines (93 loc) · 2.53 KB
/
query.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package power
import (
"context"
"errors"
"fmt"
"time"
"github.com/k-sone/snmpgo"
"github.com/scjalliance/power/snmpvar"
)
// Query will attempt to retrieve the source's statistics via SNMP.
func Query(ctx context.Context, source Source, stats ...Statistic) (results []Value, err error) {
select {
case <-ctx.Done():
return
default:
}
snmp, err := snmpgo.NewSNMP(snmpgo.SNMPArguments{
Version: snmpgo.V2c,
Address: source.HostPort(),
Retries: source.Retries,
Community: source.Community,
})
if err != nil {
return nil, fmt.Errorf("failed to create snmpgo.SNMP object: %s", err)
}
if err = snmp.Open(); err != nil {
return nil, fmt.Errorf("failed to open connection: %s", err)
}
defer snmp.Close()
for _, stat := range stats {
value := Value{
Source: source,
Stat: stat,
Time: time.Now(),
}
value.Value, value.Err = query(ctx, snmp, stat.OID, stat.Mapper)
results = append(results, value)
}
return
}
// query sends an SNMP v2c request and parses the value contained in the
// response.
func query(ctx context.Context, snmp *snmpgo.SNMP, oids snmpgo.Oids, mapper snmpvar.Float64) (value float64, err error) {
select {
case <-ctx.Done():
return
default:
}
// Execute the query
pdu, err := snmp.GetRequest(oids)
if err != nil {
err = fmt.Errorf("failed to execute SNMP request: %s", err)
return
}
if pdu.ErrorStatus() != snmpgo.NoError {
err = fmt.Errorf("SNMP agent returned an error: [%d] %s", pdu.ErrorIndex(), pdu.ErrorStatus())
return
}
// Retrieve the variables (one varbind per requested object identifier)
bindings := pdu.VarBinds()
// Map the variables to a single value
return varToValue(oids, bindings, mapper)
}
// varToValue scans the returned set of variables in priority order and returns
// the first one that's valid.
//
// If none of the variables are valid it returns the last error.
func varToValue(oids snmpgo.Oids, bindings snmpgo.VarBinds, mapper snmpvar.Float64) (value float64, err error) {
for _, oid := range oids {
binding := bindings.MatchOid(oid)
if binding != nil {
v := binding.Variable
switch v.Type() {
case "NoSucheInstance":
err = ErrNoSuchInstance
case "NoSucheObject":
err = ErrNoSuchObject
default:
value, err = mapper(v)
if err == nil {
// We found a valid value, return it
return
}
err = fmt.Errorf("unable to parse returned value %s: %s", v.String(), err)
}
}
}
// No valid values were found; make sure we return an error
if err == nil {
err = errors.New("no value returned")
}
return
}