netdata/netdata

View on GitHub
src/go/collectors/go.d.plugin/modules/adaptecraid/collect_pd.go

Summary

Maintainability
A
0 mins
Test Coverage
// SPDX-License-Identifier: GPL-3.0-or-later

package adaptecraid

import (
    "bufio"
    "bytes"
    "errors"
    "fmt"
    "strconv"
    "strings"
)

type physicalDevice struct {
    number        string
    state         string
    location      string
    vendor        string
    model         string
    smart         string
    smartWarnings string
    powerState    string
    temperature   string
}

func (a *AdaptecRaid) collectPhysicalDevices(mx map[string]int64) error {
    bs, err := a.exec.physicalDevicesInfo()
    if err != nil {
        return err
    }

    devices, err := parsePhysDevInfo(bs)
    if err != nil {
        return err
    }

    if len(devices) == 0 {
        return errors.New("no physical devices found")
    }

    for _, pd := range devices {
        if !a.pds[pd.number] {
            a.pds[pd.number] = true
            a.addPhysicalDeviceCharts(pd)
        }

        px := fmt.Sprintf("pd_%s_", pd.number)

        // Unfortunately, all available states are unknown.
        mx[px+"health_state_ok"] = 0
        mx[px+"health_state_critical"] = 0
        if isOkPDState(pd) {
            mx[px+"health_state_ok"] = 1
        } else {
            mx[px+"health_state_critical"] = 1
        }

        if v, err := strconv.ParseInt(pd.smartWarnings, 10, 64); err == nil {
            mx[px+"smart_warnings"] = v
        }
        if v, err := strconv.ParseInt(pd.temperature, 10, 64); err == nil {
            mx[px+"temperature"] = v
        }
    }

    return nil
}

func isOkPDState(pd *physicalDevice) bool {
    // https://github.com/thomas-krenn/check_adaptec_raid/blob/a104fd88deede87df4f07403b44394bffb30c5c3/check_adaptec_raid#L455
    switch pd.state {
    case "Online",
        "Global Hot-Spare",
        "Dedicated Hot-Spare",
        "Pooled Hot-Spare",
        "Hot Spare",
        "Ready",
        "Online (JBOD)",
        "Raw (Pass Through)":
        return true
    }
    return false
}

func parsePhysDevInfo(bs []byte) (map[string]*physicalDevice, error) {
    devices := make(map[string]*physicalDevice)

    var pd *physicalDevice

    sc := bufio.NewScanner(bytes.NewReader(bs))

    for sc.Scan() {
        line := strings.TrimSpace(sc.Text())

        if strings.HasPrefix(line, "Device #") {
            num := strings.TrimPrefix(line, "Device #")
            pd = &physicalDevice{number: num}
            devices[num] = pd
            continue
        }

        if pd == nil {
            continue
        }

        switch {
        case strings.HasPrefix(line, "State"):
            pd.state = getColonSepValue(line)
        case strings.HasPrefix(line, "Reported Location"):
            pd.location = getColonSepValue(line)
        case strings.HasPrefix(line, "Vendor"):
            pd.vendor = getColonSepValue(line)
        case strings.HasPrefix(line, "Model"):
            pd.model = getColonSepValue(line)
        case strings.HasPrefix(line, "S.M.A.R.T. warnings"):
            pd.smartWarnings = getColonSepValue(line)
        case strings.HasPrefix(line, "S.M.A.R.T."):
            pd.smart = getColonSepValue(line)
        case strings.HasPrefix(line, "Power State"):
            pd.powerState = getColonSepValue(line)
        case strings.HasPrefix(line, "Temperature"):
            v := getColonSepValue(line) // '42 C/ 107 F' or 'Not Supported'
            pd.temperature = strings.Fields(v)[0]
        }
    }

    return devices, nil
}