NVIDIA GPU loadable plugin
Source
24
24
"sync"
25
25
26
26
"golang.zabbix.com/plugin/nvidia/pkg/nvml"
27
27
"golang.zabbix.com/plugin/nvidia/plugin/params"
28
28
"golang.zabbix.com/sdk/errs"
29
29
)
30
30
31
31
var (
32
32
_ HandlerFunc = WithJSONResponse(nil)
33
33
_ HandlerFunc = (*Handler)(nil).GetNVMLVersion
34
+
_ HandlerFunc = (*Handler)(nil).GetBAR1MemoryInfo
35
+
_ HandlerFunc = (*Handler)(nil).GetDecoderUtilisation
36
+
_ HandlerFunc = (*Handler)(nil).GetDeviceCount
37
+
_ HandlerFunc = (*Handler)(nil).GetDeviceEnergyConsumption
38
+
_ HandlerFunc = (*Handler)(nil).GetDeviceFanSpeed
39
+
_ HandlerFunc = (*Handler)(nil).GetDevicePerfState
40
+
_ HandlerFunc = (*Handler)(nil).GetDevicePowerLimit
41
+
_ HandlerFunc = (*Handler)(nil).GetDevicePowerUsage
42
+
_ HandlerFunc = (*Handler)(nil).GetDeviceSerial
43
+
_ HandlerFunc = (*Handler)(nil).GetDeviceTemperature
44
+
_ HandlerFunc = (*Handler)(nil).GetDriverVersion
45
+
_ HandlerFunc = (*Handler)(nil).GetEncoderStats
46
+
_ HandlerFunc = (*Handler)(nil).GetEncoderUtilisation
47
+
_ HandlerFunc = (*Handler)(nil).GetFBMemoryInfo
48
+
_ HandlerFunc = (*Handler)(nil).GetGraphicsFrequency
49
+
_ HandlerFunc = (*Handler)(nil).GetMemoryErrors
50
+
_ HandlerFunc = (*Handler)(nil).GetMemoryFrequency
51
+
_ HandlerFunc = (*Handler)(nil).GetPCIeThroughput
52
+
_ HandlerFunc = (*Handler)(nil).GetRegistryErrors
53
+
_ HandlerFunc = (*Handler)(nil).GetVideoFrequency
54
+
_ HandlerFunc = (*Handler)(nil).GetSMFrequency
34
55
)
35
56
36
57
// Handler hold client and syscall implementation for request functions.
37
58
type Handler struct {
38
59
nvmlRunner nvml.Runner
39
60
deviceCacheMux *sync.Mutex
40
61
deviceCache map[string]*nvml.NVMLDevice
41
62
}
42
63
43
64
// New creates a new handler with initialized clients for system and tcp calls.
60
81
h.deviceCacheMux.Lock()
61
82
defer h.deviceCacheMux.Unlock()
62
83
63
84
device, ok := h.deviceCache[uuid]
64
85
if ok {
65
86
return device, nil
66
87
}
67
88
68
89
device, err := h.nvmlRunner.GetDeviceByUUID(uuid)
69
90
if err != nil {
70
-
return nil, err
91
+
return nil, errs.Wrap(err, "error getting device by uuid")
71
92
}
72
93
73
94
h.deviceCache[uuid] = device
74
95
75
96
return device, nil
76
97
}
77
98
78
99
func (h *Handler) GetNVMLVersion(_ context.Context, _ map[string]string, _ ...string) (any, error) {
79
100
version, err := h.nvmlRunner.GetNVMLVersion()
80
101
if err != nil {
81
-
return "", err
102
+
return "", errs.Wrap(err, "failed to get NVML version")
82
103
}
83
104
84
105
return version, nil
85
106
}
86
107
87
108
func (h *Handler) GetDriverVersion(_ context.Context, _ map[string]string, _ ...string) (any, error) {
88
109
version, err := h.nvmlRunner.GetDriverVersion()
89
110
if err != nil {
90
-
return "", err
111
+
return "", errs.Wrap(err, "failed to get driver version")
91
112
}
92
113
93
114
return version, nil
94
115
}
95
116
96
117
type DiscoveryDevice struct {
97
118
UUID string `json:"device_uuid"`
98
119
Name string `json:"device_name"`
99
120
}
100
121
103
124
if err != nil {
104
125
return nil, err
105
126
}
106
127
107
128
var discovered []DiscoveryDevice
108
129
deviceCache := make(map[string]*nvml.NVMLDevice)
109
130
110
131
for i := uint(0); i < deviceCount; i++ {
111
132
device, err := h.nvmlRunner.GetDeviceByIndexV2(i)
112
133
if err != nil {
113
-
return nil, err
134
+
return nil, errs.Wrap(err, "failed to get device by index")
114
135
}
115
136
116
137
uuid, err := device.GetUUID()
117
138
if err != nil {
118
-
return nil, err
139
+
return nil, errs.Wrap(err, "failed to get device uuid")
119
140
}
120
141
121
142
name, err := device.GetName()
122
143
if err != nil {
123
-
return nil, err
144
+
return nil, errs.Wrap(err, "failed to get device name")
124
145
}
125
146
126
147
d := DiscoveryDevice{
127
148
UUID: uuid,
128
149
Name: name,
129
150
}
130
151
131
152
deviceCache[uuid] = device
132
153
discovered = append(discovered, d)
133
154
}
136
157
defer h.deviceCacheMux.Unlock()
137
158
138
159
h.deviceCache = deviceCache
139
160
140
161
return discovered, nil
141
162
}
142
163
143
164
func (h *Handler) GetDeviceCount(_ context.Context, _ map[string]string, _ ...string) (any, error) {
144
165
deviceCount, err := h.nvmlRunner.GetDeviceCountV2()
145
166
if err != nil {
146
-
return nil, err
167
+
return nil, errs.Wrap(err, "failed to get device count")
147
168
}
148
169
149
170
return deviceCount, nil
150
171
}
151
172
152
173
func (h *Handler) GetDeviceTemperature(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
153
174
uuid, ok := metricParams[params.DeviceUUIDParamName]
154
175
if !ok {
155
176
return nil, errs.New("Could not find param for uuid")
156
177
}
157
178
158
179
device, err := h.GetDeviceByUUID(uuid)
159
180
if err != nil {
160
-
return nil, err
181
+
return nil, errs.Wrap(err, "error getting device by uuid")
161
182
}
162
183
163
184
temperature, err := device.GetTemperature()
164
185
if err != nil {
165
-
return nil, err
186
+
return nil, errs.Wrap(err, "failed to get device temperature")
166
187
}
167
188
168
189
return temperature, nil
169
190
}
170
191
171
192
func (h *Handler) GetDeviceSerial(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
172
193
uuid, ok := metricParams[params.DeviceUUIDParamName]
173
194
if !ok {
174
195
return nil, errs.New("could not find param for uuid")
175
196
}
176
197
177
198
device, err := h.GetDeviceByUUID(uuid)
178
199
if err != nil {
179
-
return nil, err
200
+
return nil, errs.Wrap(err, "error getting device by uuid")
180
201
}
181
202
182
203
serial, err := device.GetSerial()
183
204
if err != nil {
184
-
return nil, err
205
+
return nil, errs.Wrap(err, "failed to get device serial")
185
206
}
186
207
187
208
return serial, nil
188
209
}
189
210
190
211
func (h *Handler) GetDeviceFanSpeed(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
191
212
uuid, ok := metricParams[params.DeviceUUIDParamName]
192
213
if !ok {
193
214
return nil, errs.New("could not find param for uuid")
194
215
}
195
216
196
217
device, err := h.GetDeviceByUUID(uuid)
197
218
if err != nil {
198
-
return nil, err
219
+
return nil, errs.Wrap(err, "error getting device by uuid")
199
220
}
200
221
201
222
fanSpeed, err := device.GetFanSpeed()
202
223
if err != nil {
203
-
return nil, err
224
+
return nil, errs.Wrap(err, "failed to get fan speed")
204
225
}
205
226
206
227
return fanSpeed, nil
207
228
}
208
229
209
230
func (h *Handler) GetDevicePerfState(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
210
231
uuid, ok := metricParams[params.DeviceUUIDParamName]
211
232
if !ok {
212
233
return nil, errs.New("could not find param for uuid")
213
234
}
214
235
215
236
device, err := h.GetDeviceByUUID(uuid)
216
237
if err != nil {
217
-
return nil, err
238
+
return nil, errs.Wrap(err, "error getting device by uuid")
218
239
}
219
240
220
241
perfState, err := device.GetPerformanceState()
221
242
if err != nil {
222
-
return nil, err
243
+
return nil, errs.Wrap(err, "failed to get performance state")
223
244
}
224
245
225
246
return perfState, nil
226
247
}
227
248
228
249
func (h *Handler) GetDeviceEnergyConsumption(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
229
250
uuid, ok := metricParams[params.DeviceUUIDParamName]
230
251
if !ok {
231
252
return nil, errs.New("could not find param for uuid")
232
253
}
233
254
234
255
device, err := h.GetDeviceByUUID(uuid)
235
256
if err != nil {
236
-
return nil, err
257
+
return nil, errs.Wrap(err, "error getting device by uuid")
237
258
}
238
259
239
260
energyCons, err := device.GetTotalEnergyConsumption()
240
261
if err != nil {
241
-
return nil, err
262
+
return nil, errs.Wrap(err, "failed to get total energy consumption")
242
263
}
243
264
244
265
return energyCons, nil
245
266
}
246
267
247
268
func (h *Handler) GetDevicePowerLimit(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
248
269
uuid, ok := metricParams[params.DeviceUUIDParamName]
249
270
if !ok {
250
271
return nil, errs.New("could not find param for uuid")
251
272
}
252
273
253
274
device, err := h.GetDeviceByUUID(uuid)
254
275
if err != nil {
255
-
return nil, err
276
+
return nil, errs.Wrap(err, "error getting device by uuid")
256
277
}
257
278
258
279
powerLimit, err := device.GetPowerManagementLimit()
259
280
if err != nil {
260
-
return nil, err
281
+
return nil, errs.Wrap(err, "failed to get device power limit")
261
282
}
262
283
263
284
return powerLimit, nil
264
285
}
265
286
266
287
func (h *Handler) GetDevicePowerUsage(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
267
288
uuid, ok := metricParams[params.DeviceUUIDParamName]
268
289
if !ok {
269
290
return nil, errs.New("could not find param for uuid")
270
291
}
271
292
272
293
device, err := h.GetDeviceByUUID(uuid)
273
294
if err != nil {
274
-
return nil, err
295
+
return nil, errs.Wrap(err, "error getting device by uuid")
275
296
}
276
297
277
298
powerUsage, err := device.GetPowerUsage()
278
299
if err != nil {
279
-
return nil, err
300
+
return nil, errs.Wrap(err, "failed to get device power usage")
280
301
}
281
302
282
303
return powerUsage, nil
283
304
}
284
305
285
306
func (h *Handler) GetBAR1MemoryInfo(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
286
307
uuid, ok := metricParams[params.DeviceUUIDParamName]
287
308
if !ok {
288
309
return nil, errs.New("could not find param for uuid")
289
310
}
290
311
291
312
device, err := h.GetDeviceByUUID(uuid)
292
313
if err != nil {
293
-
return nil, err
314
+
return nil, errs.Wrap(err, "error getting device by uuid")
294
315
}
295
316
296
317
memoryInfo, err := device.GetBAR1MemoryInfo()
297
318
if err != nil {
298
-
return nil, err
319
+
return nil, errs.Wrap(err, "failed to get BAR1 memory info")
299
320
}
300
321
301
322
return memoryInfo, nil
302
323
}
303
324
304
325
func (h *Handler) GetFBMemoryInfo(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
305
326
uuid, ok := metricParams[params.DeviceUUIDParamName]
306
327
if !ok {
307
328
return nil, errs.New("could not find param for uuid")
308
329
}
309
330
310
331
device, err := h.GetDeviceByUUID(uuid)
311
332
if err != nil {
312
-
return nil, err
333
+
return nil, errs.Wrap(err, "error getting device by uuid")
313
334
}
314
335
315
336
memoryInfo, err := device.GetMemoryInfoV2()
316
337
if err != nil {
317
-
return nil, err
338
+
return nil, errs.Wrap(err, "failed to get memory info")
318
339
}
319
340
320
341
return memoryInfo, nil
321
342
}
322
343
323
344
type EccErrors struct {
324
345
Corrected uint64 `json:"corrected"`
325
346
Uncorrected uint64 `json:"uncorrected"`
326
347
}
327
348
328
349
func (h *Handler) GetMemoryErrors(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
329
350
uuid, ok := metricParams[params.DeviceUUIDParamName]
330
351
if !ok {
331
352
return nil, errs.New("could not find param for uuid")
332
353
}
333
354
334
355
device, err := h.GetDeviceByUUID(uuid)
335
356
if err != nil {
336
-
return nil, err
357
+
return nil, errs.Wrap(err, "error getting device by uuid")
337
358
}
338
359
339
360
corrected, err := device.GetMemoryErrorCounter(
340
361
nvml.MemoryErrorTypeCorrected,
341
362
nvml.MemoryLocationDevice,
342
363
nvml.EccCounterTypeAggregate,
343
364
)
344
365
if err != nil {
345
-
return nil, err
366
+
return nil, errs.Wrap(err, "failed to get corrected memory errors")
346
367
}
347
368
348
369
uncorrected, err := device.GetMemoryErrorCounter(
349
370
nvml.MemoryErrorTypeUncorrected,
350
371
nvml.MemoryLocationDevice,
351
372
nvml.EccCounterTypeAggregate,
352
373
)
353
374
if err != nil {
354
-
return nil, err
375
+
return nil, errs.Wrap(err, "failed to get uncorrected memory errors")
355
376
}
356
377
357
378
ecc := EccErrors{
358
379
Corrected: corrected,
359
380
Uncorrected: uncorrected,
360
381
}
361
382
362
383
return ecc, nil
363
384
}
364
385
365
386
func (h *Handler) GetRegistryErrors(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
366
387
uuid, ok := metricParams[params.DeviceUUIDParamName]
367
388
if !ok {
368
389
return nil, errs.New("could not find param for uuid")
369
390
}
370
391
371
392
device, err := h.GetDeviceByUUID(uuid)
372
393
if err != nil {
373
-
return nil, err
394
+
return nil, errs.Wrap(err, "error getting device by uuid")
374
395
}
375
396
376
397
corrected, err := device.GetMemoryErrorCounter(
377
398
nvml.MemoryErrorTypeCorrected,
378
399
nvml.MemoryLocationRegisterFile,
379
400
nvml.EccCounterTypeAggregate,
380
401
)
381
402
if err != nil {
382
-
return nil, err
403
+
return nil, errs.Wrap(err, "failed to get corrected memory errors")
383
404
}
384
405
385
406
uncorrected, err := device.GetMemoryErrorCounter(
386
407
nvml.MemoryErrorTypeUncorrected,
387
408
nvml.MemoryLocationRegisterFile,
388
409
nvml.EccCounterTypeAggregate,
389
410
)
390
411
if err != nil {
391
-
return nil, err
412
+
return nil, errs.Wrap(err, "failed to get uncorrected memory errors")
392
413
}
393
414
394
415
ecc := EccErrors{
395
416
Corrected: corrected,
396
417
Uncorrected: uncorrected,
397
418
}
398
419
399
420
return ecc, nil
400
421
}
401
422
425
446
}
426
447
427
448
func (h *Handler) GetPCIeThroughput(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
428
449
uuid, ok := metricParams[params.DeviceUUIDParamName]
429
450
if !ok {
430
451
return nil, errs.New("could not find param for uuid")
431
452
}
432
453
433
454
device, err := h.GetDeviceByUUID(uuid)
434
455
if err != nil {
435
-
return nil, err
456
+
return nil, errs.Wrap(err, "error getting device by uuid")
436
457
}
437
458
438
-
rx, err := device.GetPcieThroughput(nvml.RX)
459
+
rx, err := device.GetPCIeThroughput(nvml.RX)
439
460
if err != nil {
440
-
return nil, err
461
+
return nil, errs.Wrap(err, "failed to get rx throughput")
441
462
}
442
463
443
-
tx, err := device.GetPcieThroughput(nvml.TX)
464
+
tx, err := device.GetPCIeThroughput(nvml.TX)
444
465
if err != nil {
445
-
return nil, err
466
+
return nil, errs.Wrap(err, "failed to get tx throughput")
446
467
}
447
468
448
469
util := PcieUtil{
449
470
Receive: rx,
450
471
Transmit: tx,
451
472
}
452
473
453
474
return util, nil
454
475
}
455
476
460
481
}
461
482
462
483
func (h *Handler) GetEncoderStats(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
463
484
uuid, ok := metricParams[params.DeviceUUIDParamName]
464
485
if !ok {
465
486
return nil, errs.New("could not find param for uuid")
466
487
}
467
488
468
489
device, err := h.GetDeviceByUUID(uuid)
469
490
if err != nil {
470
-
return nil, err
491
+
return nil, errs.Wrap(err, "error getting device by uuid")
471
492
}
472
493
473
494
sessions, fps, latency, err := device.GetEncoderStats()
474
495
if err != nil {
475
-
return nil, err
496
+
return nil, errs.Wrap(err, "failed to get encoder stats")
476
497
}
477
498
478
499
stats := EncoderStats{
479
500
SessionCount: sessions,
480
501
FPS: fps,
481
502
Latency: latency,
482
503
}
483
504
484
505
return stats, nil
485
506
}
486
507
487
508
func (h *Handler) GetVideoFrequency(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
488
509
uuid, ok := metricParams[params.DeviceUUIDParamName]
489
510
if !ok {
490
511
return nil, errs.New("Could not find param for uuid")
491
512
}
492
513
493
514
device, err := h.GetDeviceByUUID(uuid)
494
515
if err != nil {
495
-
return nil, err
516
+
return nil, errs.Wrap(err, "error getting device by uuid")
496
517
}
497
518
498
519
clock, err := device.GetClockInfo(nvml.Video)
499
520
if err != nil {
500
-
return nil, err
521
+
return nil, errs.Wrap(err, "failed to get clock info")
501
522
}
502
523
503
524
return clock, nil
504
525
}
505
526
506
527
func (h *Handler) GetGraphicsFrequency(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
507
528
uuid, ok := metricParams[params.DeviceUUIDParamName]
508
529
if !ok {
509
530
return nil, errs.New("Could not find param for uuid")
510
531
}
511
532
512
533
device, err := h.GetDeviceByUUID(uuid)
513
534
if err != nil {
514
-
return nil, err
535
+
return nil, errs.Wrap(err, "error getting device by uuid")
515
536
}
516
537
517
538
clock, err := device.GetClockInfo(nvml.Graphics)
518
539
if err != nil {
519
-
return nil, err
540
+
return nil, errs.Wrap(err, "failed to get clock info")
520
541
}
521
542
522
543
return clock, nil
523
544
}
524
545
525
546
func (h *Handler) GetSMFrequency(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
526
547
uuid, ok := metricParams[params.DeviceUUIDParamName]
527
548
if !ok {
528
549
return nil, errs.New("Could not find param for uuid")
529
550
}
530
551
531
552
device, err := h.GetDeviceByUUID(uuid)
532
553
if err != nil {
533
-
return nil, err
554
+
return nil, errs.Wrap(err, "error getting device by uuid")
534
555
}
535
556
536
557
clock, err := device.GetClockInfo(nvml.SM)
537
558
if err != nil {
538
-
return nil, err
559
+
return nil, errs.Wrap(err, "failed to get clock info")
539
560
}
540
561
541
562
return clock, nil
542
563
}
543
564
544
565
func (h *Handler) GetMemoryFrequency(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
545
566
uuid, ok := metricParams[params.DeviceUUIDParamName]
546
567
if !ok {
547
568
return nil, errs.New("Could not find param for uuid")
548
569
}
549
570
550
571
device, err := h.GetDeviceByUUID(uuid)
551
572
if err != nil {
552
-
return nil, err
573
+
return nil, errs.Wrap(err, "error getting device by uuid")
553
574
}
554
575
555
576
clock, err := device.GetClockInfo(nvml.Memory)
556
577
if err != nil {
557
-
return nil, err
578
+
return nil, errs.Wrap(err, "failed to get clock info")
558
579
}
559
580
560
581
return clock, nil
561
582
}
562
583
563
584
func (h *Handler) GetEncoderUtilisation(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
564
585
uuid, ok := metricParams[params.DeviceUUIDParamName]
565
586
if !ok {
566
587
return nil, errs.New("Could not find param for uuid")
567
588
}
568
589
569
590
device, err := h.GetDeviceByUUID(uuid)
570
591
if err != nil {
571
-
return nil, err
592
+
return nil, errs.Wrap(err, "error getting device by uuid")
572
593
}
573
594
574
595
utilisation, _, err := device.GetEncoderUtilization()
575
596
if err != nil {
576
-
return nil, err
597
+
return nil, errs.Wrap(err, "failed to get encoder utilisation")
577
598
}
578
599
579
600
return utilisation, nil
580
601
}
581
602
582
603
func (h *Handler) GetDecoderUtilisation(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
583
604
uuid, ok := metricParams[params.DeviceUUIDParamName]
584
605
if !ok {
585
606
return nil, errs.New("Could not find param for uuid")
586
607
}
587
608
588
609
device, err := h.GetDeviceByUUID(uuid)
589
610
if err != nil {
590
-
return nil, err
611
+
return nil, errs.Wrap(err, "error getting device by uuid")
591
612
}
592
613
593
614
utilisation, _, err := device.GetDecoderUtilization()
594
615
if err != nil {
595
-
return nil, err
616
+
return nil, errs.Wrap(err, "failed to get decoder utilisation")
596
617
}
597
618
598
619
return utilisation, nil
599
620
}
600
621
601
622
type UtilisationRates struct {
602
623
GPU uint `json:"device"`
603
624
Memory uint `json:"memory"`
604
625
}
605
626
606
627
func (h *Handler) GetDeviceUtilisation(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
607
628
uuid, ok := metricParams[params.DeviceUUIDParamName]
608
629
if !ok {
609
630
return nil, errs.New("Could not find param for uuid")
610
631
}
611
632
612
633
device, err := h.GetDeviceByUUID(uuid)
613
634
if err != nil {
614
-
return nil, err
635
+
return nil, errs.Wrap(err, "error getting device by uuid")
615
636
}
616
637
617
638
gpu, memory, err := device.GetUtilizationRates()
618
639
if err != nil {
619
-
return nil, err
640
+
return nil, errs.Wrap(err, "failed to get utilisation rates")
620
641
}
621
642
622
643
util := UtilisationRates{
623
644
GPU: gpu,
624
645
Memory: memory,
625
646
}
626
647
627
648
return util, nil
628
649
}
650
+
651
+
type EccMode struct {
652
+
Currect bool `json:"current"`
653
+
Pending bool `json:"pending"`
654
+
}
655
+
656
+
func (h *Handler) GetECCMode(_ context.Context, metricParams map[string]string, _ ...string) (any, error) {
657
+
uuid, ok := metricParams[params.DeviceUUIDParamName]
658
+
if !ok {
659
+
return nil, errs.New("Could not find param for uuid")
660
+
}
661
+
662
+
device, err := h.GetDeviceByUUID(uuid)
663
+
if err != nil {
664
+
return nil, errs.Wrap(err, "failed getting device by uuid")
665
+
}
666
+
667
+
current, pending, err := device.GetEccMode()
668
+
if err != nil {
669
+
return nil, errs.Wrap(err, "failed getting ecc mode")
670
+
}
671
+
672
+
mode := EccMode{
673
+
Currect: current,
674
+
Pending: pending,
675
+
}
676
+
677
+
return mode, nil
678
+
}