diff --git a/collectors/lustreMetric.go b/collectors/lustreMetric.go index 3e248fa..99b371c 100644 --- a/collectors/lustreMetric.go +++ b/collectors/lustreMetric.go @@ -3,18 +3,21 @@ package collectors import ( "encoding/json" "errors" - "io/ioutil" - "log" + "fmt" + "os/exec" "strconv" "strings" "time" + lp "github.com/ClusterCockpit/cc-metric-collector/internal/ccMetric" ) -const LUSTREFILE = `/proc/fs/lustre/llite/lnec-XXXXXX/stats` +const LUSTRE_SYSFS = `/sys/fs/lustre` +const LCTL_CMD = `lctl` +const LCTL_OPTION = `get_param` type LustreCollectorConfig struct { - Procfiles []string `json:"procfiles"` + LCtlCommand string `json:"lctl_command"` ExcludeMetrics []string `json:"exclude_metrics"` } @@ -24,6 +27,58 @@ type LustreCollector struct { matches map[string]map[string]int devices []string config LustreCollectorConfig + lctl string +} + +func (m *LustreCollector) getDevices() []string { + devices := make([]string, 0) + + // //Version reading devices from sysfs + // globPattern := filepath.Join(LUSTRE_SYSFS, "llite/*/stats") + // files, err := filepath.Glob(globPattern) + // if err != nil { + // return devices + // } + // for _, f := range files { + // pathlist := strings.Split(f, "/") + // devices = append(devices, pathlist[4]) + // } + + command := exec.Command(m.lctl, LCTL_OPTION, "llite.*.stats") + command.Wait() + stdout, err := command.Output() + if err != nil { + return devices + } + for _, line := range strings.Split(string(stdout), "\n") { + if strings.HasPrefix(line, "llite") { + linefields := strings.Split(line, ".") + if len(linefields) > 2 { + devices = append(devices, linefields[1]) + } + } + } + return devices +} + +// //Version reading the stats data of a device from sysfs +// func (m *LustreCollector) getDeviceDataSysfs(device string) []string { +// llitedir := filepath.Join(LUSTRE_SYSFS, "llite") +// devdir := filepath.Join(llitedir, device) +// statsfile := filepath.Join(devdir, "stats") +// buffer, err := ioutil.ReadFile(statsfile) +// if err != nil { +// return make([]string, 0) +// } +// return strings.Split(string(buffer), "\n") +// } + +func (m *LustreCollector) getDeviceDataCommand(device string) []string { + statsfile := fmt.Sprintf("llite.%s.stats", device) + command := exec.Command(m.lctl, LCTL_OPTION, statsfile) + command.Wait() + stdout, _ := command.Output() + return strings.Split(string(stdout), "\n") } func (m *LustreCollector) Init(config json.RawMessage) error { @@ -46,19 +101,18 @@ func (m *LustreCollector) Init(config json.RawMessage) error { "getattr": {"getattr": 1}, "statfs": {"statfs": 1}, "inode_permission": {"inode_permission": 1}} - m.devices = make([]string, 0) - for _, p := range m.config.Procfiles { - _, err := ioutil.ReadFile(p) - if err == nil { - m.devices = append(m.devices, p) - } else { - log.Print(err.Error()) - continue + p, err := exec.LookPath(m.config.LCtlCommand) + if err != nil { + p, err = exec.LookPath(LCTL_CMD) + if err != nil { + return err } } + m.lctl = p + m.devices = m.getDevices() if len(m.devices) == 0 { - return errors.New("No metrics to collect") + return errors.New("no metrics to collect") } m.init = true return nil @@ -68,15 +122,10 @@ func (m *LustreCollector) Read(interval time.Duration, output chan lp.CCMetric) if !m.init { return } - for _, p := range m.devices { - buffer, err := ioutil.ReadFile(p) + for _, device := range m.devices { + stats := m.getDeviceDataCommand(device) - if err != nil { - log.Print(err) - return - } - - for _, line := range strings.Split(string(buffer), "\n") { + for _, line := range stats { lf := strings.Fields(line) if len(lf) > 1 { for match, fields := range m.matches {