src/go/plugin/go.d/modules/hpssa/charts.go
// SPDX-License-Identifier: GPL-3.0-or-later
package hpssa
import (
"fmt"
"strings"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
)
const (
prioControllerStatus = module.Priority + iota
prioControllerTemperature
prioControllerCacheModulePresenceStatus
prioControllerCacheModuleStatus
prioControllerCacheModuleTemperature
prioControllerCacheModuleBatteryStatus
prioArrayStatus
prioLogicalDriveStatus
prioPhysicalDriveStatus
prioPhysicalDriveTemperature
)
var controllerChartsTmpl = module.Charts{
controllerStatusChartTmpl.Copy(),
controllerTemperatureChartTmpl.Copy(),
controllerCacheModulePresenceStatusChartTmpl.Copy(),
controllerCacheModuleStatusChartTmpl.Copy(),
controllerCacheModuleTemperatureChartTmpl.Copy(),
controllerCacheModuleBatteryStatusChartTmpl.Copy(),
}
var (
controllerStatusChartTmpl = module.Chart{
ID: "cntrl_%s_slot_%s_status",
Title: "Controller status",
Units: "status",
Fam: "controllers",
Ctx: "hpssa.controller_status",
Type: module.Line,
Priority: prioControllerStatus,
Dims: module.Dims{
{ID: "cntrl_%s_slot_%s_status_ok", Name: "ok"},
{ID: "cntrl_%s_slot_%s_status_nok", Name: "nok"},
},
}
controllerTemperatureChartTmpl = module.Chart{
ID: "cntrl_%s_slot_%s_temperature",
Title: "Controller temperature",
Units: "Celsius",
Fam: "controllers",
Ctx: "hpssa.controller_temperature",
Type: module.Line,
Priority: prioControllerTemperature,
Dims: module.Dims{
{ID: "cntrl_%s_slot_%s_temperature", Name: "temperature"},
},
}
controllerCacheModulePresenceStatusChartTmpl = module.Chart{
ID: "cntrl_%s_slot_%s_cache_presence_status",
Title: "Controller cache module presence",
Units: "status",
Fam: "cache",
Ctx: "hpssa.controller_cache_module_presence_status",
Type: module.Line,
Priority: prioControllerCacheModulePresenceStatus,
Dims: module.Dims{
{ID: "cntrl_%s_slot_%s_cache_presence_status_present", Name: "present"},
{ID: "cntrl_%s_slot_%s_cache_presence_status_not_present", Name: "not_present"},
},
}
controllerCacheModuleStatusChartTmpl = module.Chart{
ID: "cntrl_%s_slot_%s_cache_status",
Title: "Controller cache module status",
Units: "status",
Fam: "cache",
Ctx: "hpssa.controller_cache_module_status",
Type: module.Line,
Priority: prioControllerCacheModuleStatus,
Dims: module.Dims{
{ID: "cntrl_%s_slot_%s_cache_status_ok", Name: "ok"},
{ID: "cntrl_%s_slot_%s_cache_status_nok", Name: "nok"},
},
}
controllerCacheModuleTemperatureChartTmpl = module.Chart{
ID: "cntrl_%s_slot_%s_cache_temperature",
Title: "Controller cache module temperature",
Units: "Celsius",
Fam: "cache",
Ctx: "hpssa.controller_cache_module_temperature",
Type: module.Line,
Priority: prioControllerCacheModuleTemperature,
Dims: module.Dims{
{ID: "cntrl_%s_slot_%s_cache_temperature", Name: "temperature"},
},
}
controllerCacheModuleBatteryStatusChartTmpl = module.Chart{
ID: "cntrl_%s_slot_%s_cache_battery_status",
Title: "Controller cache module battery status",
Units: "status",
Fam: "cache",
Ctx: "hpssa.controller_cache_module_battery_status",
Type: module.Line,
Priority: prioControllerCacheModuleBatteryStatus,
Dims: module.Dims{
{ID: "cntrl_%s_slot_%s_cache_battery_status_ok", Name: "ok"},
{ID: "cntrl_%s_slot_%s_cache_battery_status_nok", Name: "nok"},
},
}
)
var arrayChartsTmpl = module.Charts{
arrayStatusChartTmpl.Copy(),
}
var (
arrayStatusChartTmpl = module.Chart{
ID: "array_%s_cntrl_%s_slot_%s_status",
Title: "Array status",
Units: "status",
Fam: "arrays",
Ctx: "hpssa.array_status",
Type: module.Line,
Priority: prioArrayStatus,
Dims: module.Dims{
{ID: "array_%s_cntrl_%s_slot_%s_status_ok", Name: "ok"},
{ID: "array_%s_cntrl_%s_slot_%s_status_nok", Name: "nok"},
},
}
)
var logicalDriveChartsTmpl = module.Charts{
logicalDriveStatusChartTmpl.Copy(),
}
var (
logicalDriveStatusChartTmpl = module.Chart{
ID: "ld_%s_array_%s_cntrl_%s_slot_%s_status",
Title: "Logical Drive status",
Units: "status",
Fam: "logical drives",
Ctx: "hpssa.logical_drive_status",
Type: module.Line,
Priority: prioLogicalDriveStatus,
Dims: module.Dims{
{ID: "ld_%s_array_%s_cntrl_%s_slot_%s_status_ok", Name: "ok"},
{ID: "ld_%s_array_%s_cntrl_%s_slot_%s_status_nok", Name: "nok"},
},
}
)
var physicalDriveChartsTmpl = module.Charts{
physicalDriveStatusChartTmpl.Copy(),
physicalDriveTemperatureChartTmpl.Copy(),
}
var (
physicalDriveStatusChartTmpl = module.Chart{
ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_status",
Title: "Physical Drive status",
Units: "status",
Fam: "physical drives",
Ctx: "hpssa.physical_drive_status",
Type: module.Line,
Priority: prioPhysicalDriveStatus,
Dims: module.Dims{
{ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_status_ok", Name: "ok"},
{ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_status_nok", Name: "nok"},
},
}
physicalDriveTemperatureChartTmpl = module.Chart{
ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_temperature",
Title: "Physical Drive temperature",
Units: "Celsius",
Fam: "physical drives",
Ctx: "hpssa.physical_drive_temperature",
Type: module.Line,
Priority: prioPhysicalDriveTemperature,
Dims: module.Dims{
{ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_temperature", Name: "temperature"},
},
}
)
func (h *Hpssa) updateCharts(controllers map[string]*hpssaController) {
seenControllers := make(map[string]bool)
seenArrays := make(map[string]bool)
seenLDrives := make(map[string]bool)
seenPDrives := make(map[string]bool)
for _, cntrl := range controllers {
key := cntrl.uniqueKey()
seenControllers[key] = true
if _, ok := h.seenControllers[key]; !ok {
h.seenControllers[key] = cntrl
h.addControllerCharts(cntrl)
}
for _, pd := range cntrl.unassignedDrives {
key := pd.uniqueKey()
seenPDrives[key] = true
if _, ok := h.seenPDrives[key]; !ok {
h.seenPDrives[key] = pd
h.addPhysicalDriveCharts(pd)
}
}
for _, arr := range cntrl.arrays {
key := arr.uniqueKey()
seenArrays[key] = true
if _, ok := h.seenArrays[key]; !ok {
h.seenArrays[key] = arr
h.addArrayCharts(arr)
}
for _, ld := range arr.logicalDrives {
key := ld.uniqueKey()
seenLDrives[key] = true
if _, ok := h.seenLDrives[key]; !ok {
h.seenLDrives[key] = ld
h.addLogicalDriveCharts(ld)
}
for _, pd := range ld.physicalDrives {
key := pd.uniqueKey()
seenPDrives[key] = true
if _, ok := h.seenPDrives[key]; !ok {
h.seenPDrives[key] = pd
h.addPhysicalDriveCharts(pd)
}
}
}
}
}
for k, cntrl := range h.seenControllers {
if !seenControllers[k] {
delete(h.seenControllers, k)
h.removeControllerCharts(cntrl)
}
}
for k, arr := range h.seenArrays {
if !seenArrays[k] {
delete(h.seenArrays, k)
h.removeArrayCharts(arr)
}
}
for k, ld := range h.seenLDrives {
if !seenLDrives[k] {
delete(h.seenLDrives, k)
h.removeLogicalDriveCharts(ld)
}
}
for k, pd := range h.seenPDrives {
if !seenPDrives[k] {
delete(h.seenPDrives, k)
h.removePhysicalDriveCharts(pd)
}
}
}
func (h *Hpssa) addControllerCharts(cntrl *hpssaController) {
charts := controllerChartsTmpl.Copy()
if cntrl.controllerTemperatureC == "" {
_ = charts.Remove(controllerTemperatureChartTmpl.ID)
}
if cntrl.cacheBoardPresent != "True" {
_ = charts.Remove(controllerCacheModuleStatusChartTmpl.ID)
_ = charts.Remove(controllerCacheModuleTemperatureChartTmpl.ID)
_ = charts.Remove(controllerCacheModuleBatteryStatusChartTmpl.ID)
}
if cntrl.cacheModuleTemperatureC == "" {
_ = charts.Remove(controllerCacheModuleTemperatureChartTmpl.ID)
}
if cntrl.batteryCapacitorStatus == "" {
_ = charts.Remove(controllerCacheModuleBatteryStatusChartTmpl.ID)
}
for _, chart := range *charts {
chart.ID = fmt.Sprintf(chart.ID, strings.ToLower(cntrl.model), cntrl.slot)
chart.Labels = []module.Label{
{Key: "slot", Value: cntrl.slot},
{Key: "model", Value: cntrl.model},
}
for _, dim := range chart.Dims {
dim.ID = fmt.Sprintf(dim.ID, cntrl.model, cntrl.slot)
}
}
if err := h.Charts().Add(*charts...); err != nil {
h.Warning(err)
}
}
func (h *Hpssa) removeControllerCharts(cntrl *hpssaController) {
px := fmt.Sprintf("cntrl_%s_slot_%s_", strings.ToLower(cntrl.model), cntrl.slot)
h.removeCharts(px)
}
func (h *Hpssa) addArrayCharts(arr *hpssaArray) {
charts := arrayChartsTmpl.Copy()
for _, chart := range *charts {
chart.ID = fmt.Sprintf(chart.ID, arr.id, strings.ToLower(arr.cntrl.model), arr.cntrl.slot)
chart.Labels = []module.Label{
{Key: "slot", Value: arr.cntrl.slot},
{Key: "array_id", Value: arr.id},
{Key: "interface_type", Value: arr.interfaceType},
{Key: "array_type", Value: arr.arrayType},
}
for _, dim := range chart.Dims {
dim.ID = fmt.Sprintf(dim.ID, arr.id, arr.cntrl.model, arr.cntrl.slot)
}
}
if err := h.Charts().Add(*charts...); err != nil {
h.Warning(err)
}
}
func (h *Hpssa) removeArrayCharts(arr *hpssaArray) {
px := fmt.Sprintf("array_%s_cntrl_%s_slot_%s_", arr.id, strings.ToLower(arr.cntrl.model), arr.cntrl.slot)
h.removeCharts(px)
}
func (h *Hpssa) addLogicalDriveCharts(ld *hpssaLogicalDrive) {
charts := logicalDriveChartsTmpl.Copy()
for _, chart := range *charts {
chart.ID = fmt.Sprintf(chart.ID, ld.id, ld.arr.id, strings.ToLower(ld.cntrl.model), ld.cntrl.slot)
chart.Labels = []module.Label{
{Key: "slot", Value: ld.cntrl.slot},
{Key: "array_id", Value: ld.arr.id},
{Key: "logical_drive_id", Value: ld.id},
{Key: "disk_name", Value: ld.diskName},
{Key: "drive_type", Value: ld.driveType},
}
for _, dim := range chart.Dims {
dim.ID = fmt.Sprintf(dim.ID, ld.id, ld.arr.id, ld.cntrl.model, ld.cntrl.slot)
}
}
if err := h.Charts().Add(*charts...); err != nil {
h.Warning(err)
}
}
func (h *Hpssa) removeLogicalDriveCharts(ld *hpssaLogicalDrive) {
px := fmt.Sprintf("ld_%s_array_%s_cntrl_%s_slot_%s_", ld.id, ld.arr.id, strings.ToLower(ld.cntrl.model), ld.cntrl.slot)
h.removeCharts(px)
}
func (h *Hpssa) addPhysicalDriveCharts(pd *hpssaPhysicalDrive) {
charts := physicalDriveChartsTmpl.Copy()
if pd.currentTemperatureC == "" {
_ = charts.Remove(physicalDriveTemperatureChartTmpl.ID)
}
for _, chart := range *charts {
chart.ID = fmt.Sprintf(chart.ID, pd.location, pd.ldId(), pd.arrId(), strings.ToLower(pd.cntrl.model), pd.cntrl.slot)
chart.Labels = []module.Label{
{Key: "slot", Value: pd.cntrl.slot},
{Key: "array_id", Value: pd.arrId()},
{Key: "logical_drive_id", Value: pd.ldId()},
{Key: "location", Value: pd.location},
{Key: "interface_type", Value: pd.interfaceType},
{Key: "drive_type", Value: pd.driveType},
{Key: "model", Value: pd.model},
}
for _, dim := range chart.Dims {
dim.ID = fmt.Sprintf(dim.ID, pd.location, pd.ldId(), pd.arrId(), pd.cntrl.model, pd.cntrl.slot)
}
}
if err := h.Charts().Add(*charts...); err != nil {
h.Warning(err)
}
}
func (h *Hpssa) removePhysicalDriveCharts(pd *hpssaPhysicalDrive) {
px := fmt.Sprintf("pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_",
pd.location, pd.ldId(), pd.arrId(), strings.ToLower(pd.cntrl.model), pd.cntrl.slot)
h.removeCharts(px)
}
func (h *Hpssa) removeCharts(prefix string) {
for _, chart := range *h.Charts() {
if strings.HasPrefix(chart.ID, prefix) {
chart.MarkRemove()
chart.MarkNotCreated()
}
}
}