master
go 403 lines 11.7 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package hpssa
4
5 import (
6 "fmt"
7 "strings"
8
9 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
10 )
11
12 const (
13 prioControllerStatus = collectorapi.Priority + iota
14 prioControllerTemperature
15
16 prioControllerCacheModulePresenceStatus
17 prioControllerCacheModuleStatus
18 prioControllerCacheModuleTemperature
19 prioControllerCacheModuleBatteryStatus
20
21 prioArrayStatus
22
23 prioLogicalDriveStatus
24
25 prioPhysicalDriveStatus
26 prioPhysicalDriveTemperature
27 )
28
29 var controllerChartsTmpl = collectorapi.Charts{
30 controllerStatusChartTmpl.Copy(),
31 controllerTemperatureChartTmpl.Copy(),
32
33 controllerCacheModulePresenceStatusChartTmpl.Copy(),
34 controllerCacheModuleStatusChartTmpl.Copy(),
35 controllerCacheModuleTemperatureChartTmpl.Copy(),
36 controllerCacheModuleBatteryStatusChartTmpl.Copy(),
37 }
38
39 var (
40 controllerStatusChartTmpl = collectorapi.Chart{
41 ID: "cntrl_%s_slot_%s_status",
42 Title: "Controller status",
43 Units: "status",
44 Fam: "controllers",
45 Ctx: "hpssa.controller_status",
46 Type: collectorapi.Line,
47 Priority: prioControllerStatus,
48 Dims: collectorapi.Dims{
49 {ID: "cntrl_%s_slot_%s_status_ok", Name: "ok"},
50 {ID: "cntrl_%s_slot_%s_status_nok", Name: "nok"},
51 },
52 }
53 controllerTemperatureChartTmpl = collectorapi.Chart{
54 ID: "cntrl_%s_slot_%s_temperature",
55 Title: "Controller temperature",
56 Units: "Celsius",
57 Fam: "controllers",
58 Ctx: "hpssa.controller_temperature",
59 Type: collectorapi.Line,
60 Priority: prioControllerTemperature,
61 Dims: collectorapi.Dims{
62 {ID: "cntrl_%s_slot_%s_temperature", Name: "temperature"},
63 },
64 }
65
66 controllerCacheModulePresenceStatusChartTmpl = collectorapi.Chart{
67 ID: "cntrl_%s_slot_%s_cache_presence_status",
68 Title: "Controller cache module presence",
69 Units: "status",
70 Fam: "cache",
71 Ctx: "hpssa.controller_cache_module_presence_status",
72 Type: collectorapi.Line,
73 Priority: prioControllerCacheModulePresenceStatus,
74 Dims: collectorapi.Dims{
75 {ID: "cntrl_%s_slot_%s_cache_presence_status_present", Name: "present"},
76 {ID: "cntrl_%s_slot_%s_cache_presence_status_not_present", Name: "not_present"},
77 },
78 }
79 controllerCacheModuleStatusChartTmpl = collectorapi.Chart{
80 ID: "cntrl_%s_slot_%s_cache_status",
81 Title: "Controller cache module status",
82 Units: "status",
83 Fam: "cache",
84 Ctx: "hpssa.controller_cache_module_status",
85 Type: collectorapi.Line,
86 Priority: prioControllerCacheModuleStatus,
87 Dims: collectorapi.Dims{
88 {ID: "cntrl_%s_slot_%s_cache_status_ok", Name: "ok"},
89 {ID: "cntrl_%s_slot_%s_cache_status_nok", Name: "nok"},
90 },
91 }
92 controllerCacheModuleTemperatureChartTmpl = collectorapi.Chart{
93 ID: "cntrl_%s_slot_%s_cache_temperature",
94 Title: "Controller cache module temperature",
95 Units: "Celsius",
96 Fam: "cache",
97 Ctx: "hpssa.controller_cache_module_temperature",
98 Type: collectorapi.Line,
99 Priority: prioControllerCacheModuleTemperature,
100 Dims: collectorapi.Dims{
101 {ID: "cntrl_%s_slot_%s_cache_temperature", Name: "temperature"},
102 },
103 }
104 controllerCacheModuleBatteryStatusChartTmpl = collectorapi.Chart{
105 ID: "cntrl_%s_slot_%s_cache_battery_status",
106 Title: "Controller cache module battery status",
107 Units: "status",
108 Fam: "cache",
109 Ctx: "hpssa.controller_cache_module_battery_status",
110 Type: collectorapi.Line,
111 Priority: prioControllerCacheModuleBatteryStatus,
112 Dims: collectorapi.Dims{
113 {ID: "cntrl_%s_slot_%s_cache_battery_status_ok", Name: "ok"},
114 {ID: "cntrl_%s_slot_%s_cache_battery_status_nok", Name: "nok"},
115 },
116 }
117 )
118
119 var arrayChartsTmpl = collectorapi.Charts{
120 arrayStatusChartTmpl.Copy(),
121 }
122
123 var (
124 arrayStatusChartTmpl = collectorapi.Chart{
125 ID: "array_%s_cntrl_%s_slot_%s_status",
126 Title: "Array status",
127 Units: "status",
128 Fam: "arrays",
129 Ctx: "hpssa.array_status",
130 Type: collectorapi.Line,
131 Priority: prioArrayStatus,
132 Dims: collectorapi.Dims{
133 {ID: "array_%s_cntrl_%s_slot_%s_status_ok", Name: "ok"},
134 {ID: "array_%s_cntrl_%s_slot_%s_status_nok", Name: "nok"},
135 },
136 }
137 )
138
139 var logicalDriveChartsTmpl = collectorapi.Charts{
140 logicalDriveStatusChartTmpl.Copy(),
141 }
142
143 var (
144 logicalDriveStatusChartTmpl = collectorapi.Chart{
145 ID: "ld_%s_array_%s_cntrl_%s_slot_%s_status",
146 Title: "Logical Drive status",
147 Units: "status",
148 Fam: "logical drives",
149 Ctx: "hpssa.logical_drive_status",
150 Type: collectorapi.Line,
151 Priority: prioLogicalDriveStatus,
152 Dims: collectorapi.Dims{
153 {ID: "ld_%s_array_%s_cntrl_%s_slot_%s_status_ok", Name: "ok"},
154 {ID: "ld_%s_array_%s_cntrl_%s_slot_%s_status_nok", Name: "nok"},
155 },
156 }
157 )
158
159 var physicalDriveChartsTmpl = collectorapi.Charts{
160 physicalDriveStatusChartTmpl.Copy(),
161 physicalDriveTemperatureChartTmpl.Copy(),
162 }
163
164 var (
165 physicalDriveStatusChartTmpl = collectorapi.Chart{
166 ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_status",
167 Title: "Physical Drive status",
168 Units: "status",
169 Fam: "physical drives",
170 Ctx: "hpssa.physical_drive_status",
171 Type: collectorapi.Line,
172 Priority: prioPhysicalDriveStatus,
173 Dims: collectorapi.Dims{
174 {ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_status_ok", Name: "ok"},
175 {ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_status_nok", Name: "nok"},
176 },
177 }
178 physicalDriveTemperatureChartTmpl = collectorapi.Chart{
179 ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_temperature",
180 Title: "Physical Drive temperature",
181 Units: "Celsius",
182 Fam: "physical drives",
183 Ctx: "hpssa.physical_drive_temperature",
184 Type: collectorapi.Line,
185 Priority: prioPhysicalDriveTemperature,
186 Dims: collectorapi.Dims{
187 {ID: "pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_temperature", Name: "temperature"},
188 },
189 }
190 )
191
192 func (c *Collector) updateCharts(controllers map[string]*hpssaController) {
193 seenControllers := make(map[string]bool)
194 seenArrays := make(map[string]bool)
195 seenLDrives := make(map[string]bool)
196 seenPDrives := make(map[string]bool)
197
198 for _, cntrl := range controllers {
199 key := cntrl.uniqueKey()
200 seenControllers[key] = true
201 if _, ok := c.seenControllers[key]; !ok {
202 c.seenControllers[key] = cntrl
203 c.addControllerCharts(cntrl)
204 }
205
206 for _, pd := range cntrl.unassignedDrives {
207 key := pd.uniqueKey()
208 seenPDrives[key] = true
209 if _, ok := c.seenPDrives[key]; !ok {
210 c.seenPDrives[key] = pd
211 c.addPhysicalDriveCharts(pd)
212 }
213 }
214
215 for _, arr := range cntrl.arrays {
216 key := arr.uniqueKey()
217 seenArrays[key] = true
218 if _, ok := c.seenArrays[key]; !ok {
219 c.seenArrays[key] = arr
220 c.addArrayCharts(arr)
221 }
222
223 for _, ld := range arr.logicalDrives {
224 key := ld.uniqueKey()
225 seenLDrives[key] = true
226 if _, ok := c.seenLDrives[key]; !ok {
227 c.seenLDrives[key] = ld
228 c.addLogicalDriveCharts(ld)
229 }
230
231 for _, pd := range ld.physicalDrives {
232 key := pd.uniqueKey()
233 seenPDrives[key] = true
234 if _, ok := c.seenPDrives[key]; !ok {
235 c.seenPDrives[key] = pd
236 c.addPhysicalDriveCharts(pd)
237 }
238 }
239 }
240 }
241 }
242
243 for k, cntrl := range c.seenControllers {
244 if !seenControllers[k] {
245 delete(c.seenControllers, k)
246 c.removeControllerCharts(cntrl)
247 }
248 }
249 for k, arr := range c.seenArrays {
250 if !seenArrays[k] {
251 delete(c.seenArrays, k)
252 c.removeArrayCharts(arr)
253 }
254 }
255 for k, ld := range c.seenLDrives {
256 if !seenLDrives[k] {
257 delete(c.seenLDrives, k)
258 c.removeLogicalDriveCharts(ld)
259 }
260 }
261 for k, pd := range c.seenPDrives {
262 if !seenPDrives[k] {
263 delete(c.seenPDrives, k)
264 c.removePhysicalDriveCharts(pd)
265 }
266 }
267 }
268
269 func (c *Collector) addControllerCharts(cntrl *hpssaController) {
270 charts := controllerChartsTmpl.Copy()
271
272 if cntrl.controllerTemperatureC == "" {
273 _ = charts.Remove(controllerTemperatureChartTmpl.ID)
274 }
275
276 if cntrl.cacheBoardPresent != "True" {
277 _ = charts.Remove(controllerCacheModuleStatusChartTmpl.ID)
278 _ = charts.Remove(controllerCacheModuleTemperatureChartTmpl.ID)
279 _ = charts.Remove(controllerCacheModuleBatteryStatusChartTmpl.ID)
280 }
281 if cntrl.cacheModuleTemperatureC == "" {
282 _ = charts.Remove(controllerCacheModuleTemperatureChartTmpl.ID)
283 }
284 if cntrl.batteryCapacitorStatus == "" {
285 _ = charts.Remove(controllerCacheModuleBatteryStatusChartTmpl.ID)
286 }
287
288 for _, chart := range *charts {
289 chart.ID = fmt.Sprintf(chart.ID, strings.ToLower(cntrl.model), cntrl.slot)
290 chart.Labels = []collectorapi.Label{
291 {Key: "slot", Value: cntrl.slot},
292 {Key: "model", Value: cntrl.model},
293 }
294 for _, dim := range chart.Dims {
295 dim.ID = fmt.Sprintf(dim.ID, cntrl.model, cntrl.slot)
296 }
297 }
298
299 if err := c.Charts().Add(*charts...); err != nil {
300 c.Warning(err)
301 }
302 }
303
304 func (c *Collector) removeControllerCharts(cntrl *hpssaController) {
305 px := fmt.Sprintf("cntrl_%s_slot_%s_", strings.ToLower(cntrl.model), cntrl.slot)
306 c.removeCharts(px)
307 }
308
309 func (c *Collector) addArrayCharts(arr *hpssaArray) {
310 charts := arrayChartsTmpl.Copy()
311
312 for _, chart := range *charts {
313 chart.ID = fmt.Sprintf(chart.ID, arr.id, strings.ToLower(arr.cntrl.model), arr.cntrl.slot)
314 chart.Labels = []collectorapi.Label{
315 {Key: "slot", Value: arr.cntrl.slot},
316 {Key: "array_id", Value: arr.id},
317 {Key: "interface_type", Value: arr.interfaceType},
318 {Key: "array_type", Value: arr.arrayType},
319 }
320 for _, dim := range chart.Dims {
321 dim.ID = fmt.Sprintf(dim.ID, arr.id, arr.cntrl.model, arr.cntrl.slot)
322 }
323 }
324
325 if err := c.Charts().Add(*charts...); err != nil {
326 c.Warning(err)
327 }
328 }
329
330 func (c *Collector) removeArrayCharts(arr *hpssaArray) {
331 px := fmt.Sprintf("array_%s_cntrl_%s_slot_%s_", arr.id, strings.ToLower(arr.cntrl.model), arr.cntrl.slot)
332 c.removeCharts(px)
333 }
334
335 func (c *Collector) addLogicalDriveCharts(ld *hpssaLogicalDrive) {
336 charts := logicalDriveChartsTmpl.Copy()
337
338 for _, chart := range *charts {
339 chart.ID = fmt.Sprintf(chart.ID, ld.id, ld.arr.id, strings.ToLower(ld.cntrl.model), ld.cntrl.slot)
340 chart.Labels = []collectorapi.Label{
341 {Key: "slot", Value: ld.cntrl.slot},
342 {Key: "array_id", Value: ld.arr.id},
343 {Key: "logical_drive_id", Value: ld.id},
344 {Key: "disk_name", Value: ld.diskName},
345 {Key: "drive_type", Value: ld.driveType},
346 }
347 for _, dim := range chart.Dims {
348 dim.ID = fmt.Sprintf(dim.ID, ld.id, ld.arr.id, ld.cntrl.model, ld.cntrl.slot)
349 }
350 }
351
352 if err := c.Charts().Add(*charts...); err != nil {
353 c.Warning(err)
354 }
355 }
356
357 func (c *Collector) removeLogicalDriveCharts(ld *hpssaLogicalDrive) {
358 px := fmt.Sprintf("ld_%s_array_%s_cntrl_%s_slot_%s_", ld.id, ld.arr.id, strings.ToLower(ld.cntrl.model), ld.cntrl.slot)
359 c.removeCharts(px)
360 }
361
362 func (c *Collector) addPhysicalDriveCharts(pd *hpssaPhysicalDrive) {
363 charts := physicalDriveChartsTmpl.Copy()
364
365 if pd.currentTemperatureC == "" {
366 _ = charts.Remove(physicalDriveTemperatureChartTmpl.ID)
367 }
368
369 for _, chart := range *charts {
370 chart.ID = fmt.Sprintf(chart.ID, pd.location, pd.ldId(), pd.arrId(), strings.ToLower(pd.cntrl.model), pd.cntrl.slot)
371 chart.Labels = []collectorapi.Label{
372 {Key: "slot", Value: pd.cntrl.slot},
373 {Key: "array_id", Value: pd.arrId()},
374 {Key: "logical_drive_id", Value: pd.ldId()},
375 {Key: "location", Value: pd.location},
376 {Key: "interface_type", Value: pd.interfaceType},
377 {Key: "drive_type", Value: pd.driveType},
378 {Key: "model", Value: pd.model},
379 }
380 for _, dim := range chart.Dims {
381 dim.ID = fmt.Sprintf(dim.ID, pd.location, pd.ldId(), pd.arrId(), pd.cntrl.model, pd.cntrl.slot)
382 }
383 }
384
385 if err := c.Charts().Add(*charts...); err != nil {
386 c.Warning(err)
387 }
388 }
389
390 func (c *Collector) removePhysicalDriveCharts(pd *hpssaPhysicalDrive) {
391 px := fmt.Sprintf("pd_%s_ld_%s_array_%s_cntrl_%s_slot_%s_",
392 pd.location, pd.ldId(), pd.arrId(), strings.ToLower(pd.cntrl.model), pd.cntrl.slot)
393 c.removeCharts(px)
394 }
395
396 func (c *Collector) removeCharts(prefix string) {
397 for _, chart := range *c.Charts() {
398 if strings.HasPrefix(chart.ID, prefix) {
399 chart.MarkRemove()
400 chart.MarkNotCreated()
401 }
402 }
403 }