summaryrefslogtreecommitdiffstats
path: root/src/go/plugin/go.d/modules/hpssa/parse.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/plugin/go.d/modules/hpssa/parse.go364
1 files changed, 364 insertions, 0 deletions
diff --git a/src/go/plugin/go.d/modules/hpssa/parse.go b/src/go/plugin/go.d/modules/hpssa/parse.go
new file mode 100644
index 000000000..64d1c8ae9
--- /dev/null
+++ b/src/go/plugin/go.d/modules/hpssa/parse.go
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package hpssa
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+type hpssaController struct {
+ model string
+ slot string
+ serialNumber string
+ controllerStatus string
+ cacheBoardPresent string
+ cacheStatus string
+ cacheRatio string
+ batteryCapacitorCount string
+ batteryCapacitorStatus string
+ controllerTemperatureC string
+ cacheModuleTemperatureC string
+ numberOfPorts string
+ driverName string
+ arrays map[string]*hpssaArray
+ unassignedDrives map[string]*hpssaPhysicalDrive
+}
+
+func (c *hpssaController) uniqueKey() string {
+ return fmt.Sprintf("%s/%s", c.model, c.slot)
+}
+
+type hpssaArray struct {
+ cntrl *hpssaController
+
+ id string
+ interfaceType string
+ unusedSpace string
+ usedSpace string
+ status string
+ arrayType string
+ logicalDrives map[string]*hpssaLogicalDrive
+}
+
+func (a *hpssaArray) uniqueKey() string {
+ return fmt.Sprintf("%s/%s/%s", a.cntrl.model, a.cntrl.slot, a.id)
+}
+
+type hpssaLogicalDrive struct {
+ cntrl *hpssaController
+ arr *hpssaArray
+
+ id string
+ size string
+ status string
+ diskName string
+ uniqueIdentifier string
+ logicalDriveLabel string
+ driveType string
+ physicalDrives map[string]*hpssaPhysicalDrive
+}
+
+func (ld *hpssaLogicalDrive) uniqueKey() string {
+ return fmt.Sprintf("%s/%s/%s/%s", ld.cntrl.model, ld.cntrl.slot, ld.arr.id, ld.id)
+}
+
+type hpssaPhysicalDrive struct {
+ cntrl *hpssaController
+ arr *hpssaArray
+ ld *hpssaLogicalDrive
+
+ location string // port:box:bay
+ status string
+ driveType string
+ interfaceType string
+ size string
+ serialNumber string
+ wwid string
+ model string
+ currentTemperatureC string
+}
+
+func (pd *hpssaPhysicalDrive) uniqueKey() string {
+ return fmt.Sprintf("%s/%s/%s/%s/%s", pd.cntrl.model, pd.cntrl.slot, pd.arrId(), pd.ldId(), pd.location)
+}
+
+func (pd *hpssaPhysicalDrive) arrId() string {
+ if pd.arr == nil {
+ return "na"
+ }
+ return pd.arr.id
+}
+
+func (pd *hpssaPhysicalDrive) ldId() string {
+ if pd.ld == nil {
+ return "na"
+ }
+ return pd.ld.id
+}
+
+func parseSsacliControllersInfo(data []byte) (map[string]*hpssaController, error) {
+ var (
+ cntrl *hpssaController
+ arr *hpssaArray
+ ld *hpssaLogicalDrive
+ pd *hpssaPhysicalDrive
+
+ line string
+ prevLine string
+ section string
+ unassigned bool
+ )
+
+ controllers := make(map[string]*hpssaController)
+
+ sc := bufio.NewScanner(bytes.NewReader(data))
+
+ for sc.Scan() {
+ prevLine = line
+ line = sc.Text()
+
+ switch {
+ case line == "":
+ section = ""
+ continue
+ case strings.HasPrefix(line, "Smart Array"):
+ section = "controller"
+
+ v, err := parseControllerLine(line)
+ if err != nil {
+ return nil, err
+ }
+
+ cntrl = v
+ controllers[cntrl.slot] = cntrl
+
+ continue
+ case strings.HasPrefix(line, " Array:") && cntrl != nil:
+ section = "array"
+ unassigned = false
+
+ arr = parseArrayLine(line)
+ cntrl.arrays[arr.id] = arr
+
+ continue
+ case strings.HasPrefix(line, " Logical Drive:") && cntrl != nil && arr != nil:
+ section = "logical drive"
+
+ ld = parseLogicalDriveLine(line)
+ arr.logicalDrives[arr.id] = ld
+
+ continue
+ case strings.HasPrefix(line, " physicaldrive") && prevLine == "":
+ section = "physical drive"
+
+ if unassigned && cntrl == nil {
+ return nil, fmt.Errorf("unassigned drive but controller is nil (line '%s')", line)
+ }
+ if !unassigned && ld == nil {
+ return nil, fmt.Errorf("assigned drive but logical device is nil (line '%s')", line)
+ }
+
+ v, err := parsePhysicalDriveLine(line)
+ if err != nil {
+ return nil, err
+ }
+
+ pd = v
+ if unassigned {
+ cntrl.unassignedDrives[pd.location] = pd
+ } else {
+ ld.physicalDrives[pd.location] = pd
+ }
+
+ continue
+ case strings.HasPrefix(line, " Unassigned"):
+ unassigned = true
+ continue
+ }
+
+ switch section {
+ case "controller":
+ parseControllerSectionLine(line, cntrl)
+ case "array":
+ parseArraySectionLine(line, arr)
+ case "logical drive":
+ parseLogicalDriveSectionLine(line, ld)
+ case "physical drive":
+ parsePhysicalDriveSectionLine(line, pd)
+ }
+ }
+
+ if len(controllers) == 0 {
+ return nil, fmt.Errorf("no controllers found")
+ }
+
+ updateHpssaHierarchy(controllers)
+
+ return controllers, nil
+}
+
+func updateHpssaHierarchy(controllers map[string]*hpssaController) {
+ for _, cntrl := range controllers {
+ for _, pd := range cntrl.unassignedDrives {
+ pd.cntrl = cntrl
+ }
+ for _, arr := range cntrl.arrays {
+ arr.cntrl = cntrl
+ for _, ld := range arr.logicalDrives {
+ ld.cntrl = cntrl
+ ld.arr = arr
+ for _, pd := range ld.physicalDrives {
+ pd.cntrl = cntrl
+ pd.arr = arr
+ pd.ld = ld
+ }
+ }
+ }
+ }
+}
+
+func parseControllerLine(line string) (*hpssaController, error) {
+ parts := strings.Fields(strings.TrimPrefix(line, "Smart Array "))
+ if len(parts) < 4 {
+ return nil, fmt.Errorf("malformed Smart Array line: '%s'", line)
+ }
+
+ cntrl := &hpssaController{
+ model: parts[0],
+ slot: parts[3],
+ arrays: make(map[string]*hpssaArray),
+ unassignedDrives: make(map[string]*hpssaPhysicalDrive),
+ }
+
+ return cntrl, nil
+}
+
+func parseArrayLine(line string) *hpssaArray {
+ arr := &hpssaArray{
+ id: getColonSepValue(line),
+ logicalDrives: make(map[string]*hpssaLogicalDrive),
+ }
+
+ return arr
+}
+
+func parseLogicalDriveLine(line string) *hpssaLogicalDrive {
+ ld := &hpssaLogicalDrive{
+ id: getColonSepValue(line),
+ physicalDrives: make(map[string]*hpssaPhysicalDrive),
+ }
+
+ return ld
+}
+
+func parsePhysicalDriveLine(line string) (*hpssaPhysicalDrive, error) {
+ parts := strings.Fields(strings.TrimSpace(line))
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("malformed physicaldrive line: '%s'", line)
+ }
+
+ pd := &hpssaPhysicalDrive{
+ location: parts[1],
+ }
+
+ return pd, nil
+}
+
+func parseControllerSectionLine(line string, cntrl *hpssaController) {
+ indent := strings.Repeat(" ", 3)
+
+ switch {
+ case strings.HasPrefix(line, indent+"Serial Number:"):
+ cntrl.serialNumber = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Controller Status:"):
+ cntrl.controllerStatus = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Cache Board Present:"):
+ cntrl.cacheBoardPresent = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Cache Status:"):
+ cntrl.cacheStatus = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Cache Ratio:"):
+ cntrl.cacheRatio = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Controller Temperature (C):"):
+ cntrl.controllerTemperatureC = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Cache Module Temperature (C):"):
+ cntrl.cacheModuleTemperatureC = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Number of Ports:"):
+ cntrl.numberOfPorts = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Driver Name:"):
+ cntrl.driverName = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Battery/Capacitor Count:"):
+ cntrl.batteryCapacitorCount = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Battery/Capacitor Status:"):
+ cntrl.batteryCapacitorStatus = getColonSepValue(line)
+ }
+}
+
+func parseArraySectionLine(line string, arr *hpssaArray) {
+ indent := strings.Repeat(" ", 6)
+
+ switch {
+ case strings.HasPrefix(line, indent+"Interface Type:"):
+ arr.interfaceType = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Unused Space:"):
+ arr.unusedSpace = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Used Space:"):
+ arr.usedSpace = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Status:"):
+ arr.status = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Array Type:"):
+ arr.arrayType = getColonSepValue(line)
+ }
+}
+
+func parseLogicalDriveSectionLine(line string, ld *hpssaLogicalDrive) {
+ indent := strings.Repeat(" ", 9)
+
+ switch {
+ case strings.HasPrefix(line, indent+"Size:"):
+ ld.size = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Status:"):
+ ld.status = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Disk Name:"):
+ ld.diskName = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Unique Identifier:"):
+ ld.uniqueIdentifier = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Logical Drive Label:"):
+ ld.logicalDriveLabel = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Drive Type:"):
+ ld.driveType = getColonSepValue(line)
+ }
+}
+
+func parsePhysicalDriveSectionLine(line string, pd *hpssaPhysicalDrive) {
+ indent := strings.Repeat(" ", 9)
+
+ switch {
+ case strings.HasPrefix(line, indent+"Status:"):
+ pd.status = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Drive Type:"):
+ pd.driveType = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Interface Type:"):
+ pd.interfaceType = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Size:"):
+ pd.size = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Serial Number:"):
+ pd.serialNumber = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"WWID:"):
+ pd.wwid = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Model:"):
+ pd.model = getColonSepValue(line)
+ case strings.HasPrefix(line, indent+"Current Temperature (C):"):
+ pd.currentTemperatureC = getColonSepValue(line)
+ }
+}
+
+func getColonSepValue(line string) string {
+ i := strings.IndexByte(line, ':')
+ if i == -1 {
+ return ""
+ }
+ return strings.TrimSpace(line[i+1:])
+}