250 lines
5.8 KiB
Go
250 lines
5.8 KiB
Go
|
//go:generate ../../../tools/readme_config_includer/generator
|
||
|
package leofs
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
_ "embed"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"os/exec"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"github.com/influxdata/telegraf"
|
||
|
"github.com/influxdata/telegraf/internal"
|
||
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||
|
)
|
||
|
|
||
|
//go:embed sample.conf
|
||
|
var sampleConfig string
|
||
|
|
||
|
const (
|
||
|
oid = ".1.3.6.1.4.1.35450"
|
||
|
// For Manager Master
|
||
|
defaultEndpoint = "127.0.0.1:4020"
|
||
|
)
|
||
|
|
||
|
type serverType int
|
||
|
|
||
|
const (
|
||
|
serverTypeManagerMaster serverType = iota
|
||
|
serverTypeManagerSlave
|
||
|
serverTypeStorage
|
||
|
serverTypeGateway
|
||
|
)
|
||
|
|
||
|
type LeoFS struct {
|
||
|
Servers []string `toml:"servers"`
|
||
|
}
|
||
|
|
||
|
var keyMapping = map[serverType][]string{
|
||
|
serverTypeManagerMaster: {
|
||
|
"num_of_processes",
|
||
|
"total_memory_usage",
|
||
|
"system_memory_usage",
|
||
|
"processes_memory_usage",
|
||
|
"ets_memory_usage",
|
||
|
"num_of_processes_5min",
|
||
|
"total_memory_usage_5min",
|
||
|
"system_memory_usage_5min",
|
||
|
"processes_memory_usage_5min",
|
||
|
"ets_memory_usage_5min",
|
||
|
"used_allocated_memory",
|
||
|
"allocated_memory",
|
||
|
"used_allocated_memory_5min",
|
||
|
"allocated_memory_5min",
|
||
|
},
|
||
|
serverTypeManagerSlave: {
|
||
|
"num_of_processes",
|
||
|
"total_memory_usage",
|
||
|
"system_memory_usage",
|
||
|
"processes_memory_usage",
|
||
|
"ets_memory_usage",
|
||
|
"num_of_processes_5min",
|
||
|
"total_memory_usage_5min",
|
||
|
"system_memory_usage_5min",
|
||
|
"processes_memory_usage_5min",
|
||
|
"ets_memory_usage_5min",
|
||
|
"used_allocated_memory",
|
||
|
"allocated_memory",
|
||
|
"used_allocated_memory_5min",
|
||
|
"allocated_memory_5min",
|
||
|
},
|
||
|
serverTypeStorage: {
|
||
|
"num_of_processes",
|
||
|
"total_memory_usage",
|
||
|
"system_memory_usage",
|
||
|
"processes_memory_usage",
|
||
|
"ets_memory_usage",
|
||
|
"num_of_processes_5min",
|
||
|
"total_memory_usage_5min",
|
||
|
"system_memory_usage_5min",
|
||
|
"processes_memory_usage_5min",
|
||
|
"ets_memory_usage_5min",
|
||
|
"num_of_writes",
|
||
|
"num_of_reads",
|
||
|
"num_of_deletes",
|
||
|
"num_of_writes_5min",
|
||
|
"num_of_reads_5min",
|
||
|
"num_of_deletes_5min",
|
||
|
"num_of_active_objects",
|
||
|
"total_objects",
|
||
|
"total_size_of_active_objects",
|
||
|
"total_size",
|
||
|
"num_of_replication_messages",
|
||
|
"num_of_sync-vnode_messages",
|
||
|
"num_of_rebalance_messages",
|
||
|
"used_allocated_memory",
|
||
|
"allocated_memory",
|
||
|
"used_allocated_memory_5min",
|
||
|
"allocated_memory_5min",
|
||
|
// following items are since LeoFS v1.4.0
|
||
|
"mq_num_of_msg_recovery_node",
|
||
|
"mq_num_of_msg_deletion_dir",
|
||
|
"mq_num_of_msg_async_deletion_dir",
|
||
|
"mq_num_of_msg_req_deletion_dir",
|
||
|
"mq_mdcr_num_of_msg_req_comp_metadata",
|
||
|
"mq_mdcr_num_of_msg_req_sync_obj",
|
||
|
"comp_state",
|
||
|
"comp_last_start_datetime",
|
||
|
"comp_last_end_datetime",
|
||
|
"comp_num_of_pending_targets",
|
||
|
"comp_num_of_ongoing_targets",
|
||
|
"comp_num_of_out_of_targets",
|
||
|
},
|
||
|
serverTypeGateway: {
|
||
|
"num_of_processes",
|
||
|
"total_memory_usage",
|
||
|
"system_memory_usage",
|
||
|
"processes_memory_usage",
|
||
|
"ets_memory_usage",
|
||
|
"num_of_processes_5min",
|
||
|
"total_memory_usage_5min",
|
||
|
"system_memory_usage_5min",
|
||
|
"processes_memory_usage_5min",
|
||
|
"ets_memory_usage_5min",
|
||
|
"num_of_writes",
|
||
|
"num_of_reads",
|
||
|
"num_of_deletes",
|
||
|
"num_of_writes_5min",
|
||
|
"num_of_reads_5min",
|
||
|
"num_of_deletes_5min",
|
||
|
"count_of_cache-hit",
|
||
|
"count_of_cache-miss",
|
||
|
"total_of_files",
|
||
|
"total_cached_size",
|
||
|
"used_allocated_memory",
|
||
|
"allocated_memory",
|
||
|
"used_allocated_memory_5min",
|
||
|
"allocated_memory_5min",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
var serverTypeMapping = map[string]serverType{
|
||
|
"4020": serverTypeManagerMaster,
|
||
|
"4021": serverTypeManagerSlave,
|
||
|
"4010": serverTypeStorage,
|
||
|
"4011": serverTypeStorage,
|
||
|
"4012": serverTypeStorage,
|
||
|
"4013": serverTypeStorage,
|
||
|
"4000": serverTypeGateway,
|
||
|
"4001": serverTypeGateway,
|
||
|
}
|
||
|
|
||
|
func (*LeoFS) SampleConfig() string {
|
||
|
return sampleConfig
|
||
|
}
|
||
|
|
||
|
func (l *LeoFS) Gather(acc telegraf.Accumulator) error {
|
||
|
if len(l.Servers) == 0 {
|
||
|
return gatherServer(defaultEndpoint, serverTypeManagerMaster, acc)
|
||
|
}
|
||
|
var wg sync.WaitGroup
|
||
|
for _, endpoint := range l.Servers {
|
||
|
results := strings.Split(endpoint, ":")
|
||
|
|
||
|
port := "4020"
|
||
|
if len(results) > 2 {
|
||
|
acc.AddError(fmt.Errorf("unable to parse address %q", endpoint))
|
||
|
continue
|
||
|
} else if len(results) == 2 {
|
||
|
_, err := strconv.Atoi(results[1])
|
||
|
if err != nil {
|
||
|
acc.AddError(fmt.Errorf("unable to parse port from %q", endpoint))
|
||
|
continue
|
||
|
}
|
||
|
port = results[1]
|
||
|
}
|
||
|
|
||
|
st, ok := serverTypeMapping[port]
|
||
|
if !ok {
|
||
|
st = serverTypeStorage
|
||
|
}
|
||
|
wg.Add(1)
|
||
|
go func(endpoint string, st serverType) {
|
||
|
defer wg.Done()
|
||
|
acc.AddError(gatherServer(endpoint, st, acc))
|
||
|
}(endpoint, st)
|
||
|
}
|
||
|
wg.Wait()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func gatherServer(endpoint string, serverType serverType, acc telegraf.Accumulator) error {
|
||
|
cmd := exec.Command("snmpwalk", "-v2c", "-cpublic", "-On", endpoint, oid)
|
||
|
stdout, err := cmd.StdoutPipe()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := cmd.Start(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer internal.WaitTimeout(cmd, time.Second*5) //nolint:errcheck // ignore the returned error as we cannot do anything about it anyway
|
||
|
scanner := bufio.NewScanner(stdout)
|
||
|
if !scanner.Scan() {
|
||
|
return errors.New("unable to retrieve the node name")
|
||
|
}
|
||
|
nodeName, err := retrieveTokenAfterColon(scanner.Text())
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
nodeNameTrimmed := strings.Trim(nodeName, "\"")
|
||
|
tags := map[string]string{
|
||
|
"node": nodeNameTrimmed,
|
||
|
}
|
||
|
i := 0
|
||
|
|
||
|
fields := make(map[string]interface{})
|
||
|
for scanner.Scan() {
|
||
|
key := keyMapping[serverType][i]
|
||
|
val, err := retrieveTokenAfterColon(scanner.Text())
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
fVal, err := strconv.ParseFloat(val, 64)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("unable to parse the value %q: %w", val, err)
|
||
|
}
|
||
|
fields[key] = fVal
|
||
|
i++
|
||
|
}
|
||
|
acc.AddFields("leofs", fields, tags)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func retrieveTokenAfterColon(line string) (string, error) {
|
||
|
tokens := strings.Split(line, ":")
|
||
|
if len(tokens) != 2 {
|
||
|
return "", fmt.Errorf("':' not found in the line:%s", line)
|
||
|
}
|
||
|
return strings.TrimSpace(tokens[1]), nil
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
inputs.Add("leofs", func() telegraf.Input {
|
||
|
return &LeoFS{}
|
||
|
})
|
||
|
}
|