Skip to content

Commit 7091373

Browse files
vk6xebecmurrant
andauthored
Add JetDirect context fallback for printer supplies (librenms#19927)
* Add JetDirect context fallback for printer supplies * Fix printer supplies context type * Refine JetDirect printer supplies context handling * Fix printer supplies context regressions * Address printer supplies context review * Refine printer supplies context types * Use SnmpQuery table walks for printer supplies * Refine printer supplies context discovery * Update JetDirect M880 supplies fixture * Remove device array from supplies discovery * Fix Brother supplies after context refactor * Restore device context for toner level checks * Refactor SNMP query for toner supplies --------- Co-authored-by: Tony Murray <murraytony@gmail.com>
1 parent 4e0da9c commit 7091373

7 files changed

Lines changed: 199 additions & 27 deletions
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/**
4+
* PrinterSuppliesContext.php
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*
19+
* @link https://www.librenms.org
20+
*/
21+
22+
namespace LibreNMS\Interfaces;
23+
24+
interface PrinterSuppliesContext
25+
{
26+
/**
27+
* @return list<string>
28+
*/
29+
public function getPrinterSuppliesContexts(): array;
30+
}

LibreNMS/Modules/PrinterSupplies.php

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@
3232
use LibreNMS\Enum\Severity;
3333
use LibreNMS\Interfaces\Data\DataStorageInterface;
3434
use LibreNMS\Interfaces\Module;
35+
use LibreNMS\Interfaces\PrinterSuppliesContext;
3536
use LibreNMS\OS;
3637
use LibreNMS\Polling\ModuleStatus;
3738
use LibreNMS\RRD\RrdDefinition;
3839
use LibreNMS\Util\Number;
3940
use LibreNMS\Util\StringHelpers;
41+
use SnmpQuery;
4042

4143
class PrinterSupplies implements Module
4244
{
@@ -63,16 +65,18 @@ public function shouldDiscover(OS $os, ModuleStatus $status): bool
6365
*/
6466
public function discover(OS $os): void
6567
{
66-
$device = $os->getDeviceArray();
68+
$device = $os->getDevice();
69+
$device_array = $os->getDeviceArray();
70+
$contexts = $os instanceof PrinterSuppliesContext ? $os->getPrinterSuppliesContexts() : [''];
6771

6872
ModuleModelObserver::observe(PrinterSupply::class, __('Printer Supplies'));
69-
$levels = $this->discoveryLevels($device);
70-
$this->syncModelsByGroup($os->getDevice(), 'printerSupplies', $levels, [['supply_type', '!=', 'input']]);
73+
$levels = $this->discoveryLevels($device_array, $contexts);
74+
$this->syncModelsByGroup($device, 'printerSupplies', $levels, [['supply_type', '!=', 'input']]);
7175
ModuleModelObserver::done();
7276

7377
ModuleModelObserver::observe(PrinterSupply::class, __('Tray Paper Level'));
74-
$papers = $this->discoveryPapers($device);
75-
$this->syncModelsByGroup($os->getDevice(), 'printerSupplies', $papers, ['supply_type' => 'input']);
78+
$papers = $this->discoveryPapers($contexts);
79+
$this->syncModelsByGroup($device, 'printerSupplies', $papers, ['supply_type' => 'input']);
7680
ModuleModelObserver::done();
7781
}
7882

@@ -97,7 +101,19 @@ public function poll(OS $os, DataStorageInterface $datastore): void
97101
return; // no data to poll
98102
}
99103

100-
$toner_snmp = snmp_get_multi_oid($device, $toner_data->pluck('supply_oid')->toArray());
104+
$toner_snmp = [];
105+
$contexts = $os instanceof PrinterSuppliesContext ? $os->getPrinterSuppliesContexts() : [''];
106+
foreach ($contexts as $context) {
107+
$toner_snmp = SnmpQuery::device($os->getDevice())
108+
->numeric()
109+
->context($context)
110+
->get($toner_data->pluck('supply_oid')->all())
111+
->values();
112+
113+
if (! empty($toner_snmp)) {
114+
break;
115+
}
116+
}
101117

102118
foreach ($toner_data as $toner) {
103119
$raw_toner = $toner_snmp[$toner['supply_oid']] ?? null;
@@ -165,18 +181,33 @@ public function dump(Device $device, string $type): ?array
165181
];
166182
}
167183

168-
private function discoveryLevels($device): Collection
184+
private function discoveryLevels(array $device, array $contexts): Collection
169185
{
170186
$levels = new Collection();
171187

172-
$oids = snmpwalk_cache_oid($device, 'prtMarkerSuppliesLevel', [], 'Printer-MIB');
173-
if (! empty($oids)) {
174-
$oids = snmpwalk_cache_oid($device, 'prtMarkerSuppliesType', $oids, 'Printer-MIB');
175-
$oids = snmpwalk_cache_oid($device, 'prtMarkerSuppliesMaxCapacity', $oids, 'Printer-MIB');
176-
$oids = snmpwalk_cache_oid($device, 'prtMarkerSuppliesDescription', $oids, 'Printer-MIB', null, '-OQUs');
188+
$oids = [];
189+
$context = '';
190+
foreach ($contexts as $context) {
191+
$oids = SnmpQuery::hideMib()
192+
->enumStrings()
193+
->context($context)
194+
->walk([
195+
'Printer-MIB::prtMarkerSuppliesLevel',
196+
'Printer-MIB::prtMarkerSuppliesType',
197+
'Printer-MIB::prtMarkerSuppliesMaxCapacity',
198+
'Printer-MIB::prtMarkerSuppliesDescription',
199+
])->valuesByIndex();
200+
201+
if (! empty($oids)) {
202+
break;
203+
}
177204
}
178205

179206
foreach ($oids as $index => $data) {
207+
if (! isset($data['prtMarkerSuppliesDescription'], $data['prtMarkerSuppliesMaxCapacity'], $data['prtMarkerSuppliesLevel'])) {
208+
continue;
209+
}
210+
180211
$last_index = substr((string) $index, strrpos((string) $index, '.') + 1);
181212

182213
$descr = $data['prtMarkerSuppliesDescription'];
@@ -206,13 +237,17 @@ private function discoveryLevels($device): Collection
206237
// Ricoh - TONERCurLevel
207238
if (empty($raw_toner)) {
208239
$supply_oid = ".1.3.6.1.4.1.367.3.2.1.2.24.1.1.5.$last_index";
209-
$raw_toner = snmp_get($device, $supply_oid, '-Oqv');
240+
$raw_toner = SnmpQuery::context($context)->get($supply_oid)->value();
241+
if ($raw_toner === '' && $device['os'] === 'brother') {
242+
// Preserve legacy Brother handling when this vendor fallback OID is absent.
243+
$raw_toner = '0';
244+
}
210245
}
211246

212247
// Ricoh - TONERNameLocal
213248
if (empty($descr)) {
214249
$descr_oid = ".1.3.6.1.4.1.367.3.2.1.2.24.1.1.3.$last_index";
215-
$descr = snmp_get($device, $descr_oid, '-Oqva');
250+
$descr = SnmpQuery::context($context)->get($descr_oid)->value();
216251
}
217252

218253
// trim part & serial number from devices that include it
@@ -225,7 +260,6 @@ private function discoveryLevels($device): Collection
225260

226261
if (is_numeric($current)) {
227262
$levels->push(new PrinterSupply([
228-
'device_id' => $device['device_id'],
229263
'supply_oid' => $supply_oid,
230264
'supply_capacity_oid' => $capacity_oid,
231265
'supply_index' => $last_index,
@@ -240,17 +274,31 @@ private function discoveryLevels($device): Collection
240274
return $levels;
241275
}
242276

243-
private function discoveryPapers($device): Collection
277+
private function discoveryPapers(array $contexts): Collection
244278
{
245279
$papers = new Collection();
246280

247-
$tray_oids = snmpwalk_cache_oid($device, 'prtInputName', [], 'Printer-MIB');
248-
if (! empty($tray_oids)) {
249-
$tray_oids = snmpwalk_cache_oid($device, 'prtInputCurrentLevel', $tray_oids, 'Printer-MIB');
250-
$tray_oids = snmpwalk_cache_oid($device, 'prtInputMaxCapacity', $tray_oids, 'Printer-MIB');
281+
$tray_oids = [];
282+
foreach ($contexts as $context) {
283+
$tray_oids = SnmpQuery::hideMib()
284+
->enumStrings()
285+
->context($context)
286+
->walk([
287+
'Printer-MIB::prtInputName',
288+
'Printer-MIB::prtInputCurrentLevel',
289+
'Printer-MIB::prtInputMaxCapacity',
290+
])->valuesByIndex();
291+
292+
if (! empty($tray_oids)) {
293+
break;
294+
}
251295
}
252296

253297
foreach ($tray_oids as $index => $data) {
298+
if (! isset($data['prtInputName'], $data['prtInputCurrentLevel'], $data['prtInputMaxCapacity'])) {
299+
continue;
300+
}
301+
254302
$last_index = substr((string) $index, strrpos((string) $index, '.') + 1);
255303

256304
$capacity = $data['prtInputMaxCapacity'];
@@ -268,7 +316,6 @@ private function discoveryPapers($device): Collection
268316
}
269317

270318
$papers->push(new PrinterSupply([
271-
'device_id' => $device['device_id'],
272319
'supply_oid' => ".1.3.6.1.2.1.43.8.2.1.10.$index",
273320
'supply_capacity_oid' => ".1.3.6.1.2.1.43.8.2.1.9.$index",
274321
'supply_index' => $last_index,
@@ -288,7 +335,7 @@ private function discoveryPapers($device): Collection
288335
* @param int $capacity the normalized capacity
289336
* @return int|float|bool the toner level as a percentage
290337
*/
291-
private static function getTonerLevel($device, $raw_value, $capacity)
338+
private static function getTonerLevel(array $device, $raw_value, $capacity)
292339
{
293340
// -3 means some toner is left
294341
if ($raw_value == '-3') {

LibreNMS/OS/Jetdirect.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,16 @@
2727
namespace LibreNMS\OS;
2828

2929
use App\Models\Device;
30+
use LibreNMS\Interfaces\PrinterSuppliesContext;
3031
use SnmpQuery;
3132

32-
class Jetdirect extends Shared\Printer
33+
class Jetdirect extends Shared\Printer implements PrinterSuppliesContext
3334
{
35+
public function getPrinterSuppliesContexts(): array
36+
{
37+
return ['', 'Jetdirect'];
38+
}
39+
3440
public function discoverOS(Device $device): void
3541
{
3642
parent::discoverOS($device); // yaml

tests/data/jetdirect_m880.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@
592592
"supply_index": 1,
593593
"supply_type": "tonerCartridge",
594594
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.1",
595-
"supply_descr": "Black Cartridge827A HP CF300A",
595+
"supply_descr": "Black Cartridge 827A HP CF300A",
596596
"supply_capacity": 100,
597597
"supply_current": 92,
598598
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.1"
@@ -610,7 +610,7 @@
610610
"supply_index": 11,
611611
"supply_type": "other",
612612
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.11",
613-
"supply_descr": "Document FeederKit HP C1P70A",
613+
"supply_descr": "Document Feeder Kit HP C1P70A",
614614
"supply_capacity": 100,
615615
"supply_current": 99,
616616
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.11"
@@ -682,7 +682,7 @@
682682
"supply_index": 5,
683683
"supply_type": "opc",
684684
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.5",
685-
"supply_descr": "Black Drum 828AHP CF358A",
685+
"supply_descr": "Black Drum 828A HP CF358A",
686686
"supply_capacity": 100,
687687
"supply_current": 53,
688688
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.5"
@@ -718,7 +718,7 @@
718718
"supply_index": 9,
719719
"supply_type": "transferUnit",
720720
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.9",
721-
"supply_descr": "Transfer Kit HPD7H14A",
721+
"supply_descr": "Transfer Kit HP D7H14A",
722722
"supply_capacity": 100,
723723
"supply_current": 89,
724724
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.9"
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"os": {
3+
"discovery": {
4+
"devices": [
5+
{
6+
"sysName": "<private>",
7+
"sysObjectID": ".1.3.6.1.4.1.11.2.3.9.1",
8+
"sysDescr": "HP ETHERNET MULTI-ENVIRONMENT,SN:TEST000000,PID:HP Color LaserJet Test",
9+
"sysContact": "<private>",
10+
"version": null,
11+
"hardware": "Color LaserJet Test",
12+
"features": null,
13+
"location": "<private>",
14+
"os": "jetdirect",
15+
"type": "printer",
16+
"serial": null,
17+
"icon": "hp.svg"
18+
}
19+
]
20+
},
21+
"poller": "matches discovery"
22+
},
23+
"printer-supplies": {
24+
"discovery": {
25+
"printer_supplies": [
26+
{
27+
"supply_index": 1,
28+
"supply_type": "toner",
29+
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.1",
30+
"supply_descr": "Black Cartridge",
31+
"supply_capacity": 100,
32+
"supply_current": 61,
33+
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.1"
34+
},
35+
{
36+
"supply_index": 2,
37+
"supply_type": "toner",
38+
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.2",
39+
"supply_descr": "Cyan Cartridge",
40+
"supply_capacity": 100,
41+
"supply_current": 47,
42+
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.2"
43+
},
44+
{
45+
"supply_index": 3,
46+
"supply_type": "toner",
47+
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.3",
48+
"supply_descr": "Magenta Cartridge",
49+
"supply_capacity": 100,
50+
"supply_current": 72,
51+
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.3"
52+
},
53+
{
54+
"supply_index": 4,
55+
"supply_type": "toner",
56+
"supply_oid": ".1.3.6.1.2.1.43.11.1.1.9.1.4",
57+
"supply_descr": "Yellow Cartridge",
58+
"supply_capacity": 100,
59+
"supply_current": 55,
60+
"supply_capacity_oid": ".1.3.6.1.2.1.43.11.1.1.8.1.4"
61+
}
62+
]
63+
},
64+
"poller": "matches discovery"
65+
}
66+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
1.3.6.1.2.1.1.1.0|4|HP ETHERNET MULTI-ENVIRONMENT,SN:TEST000000,PID:HP Color LaserJet Test
2+
1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.11.2.3.9.1
3+
1.3.6.1.2.1.1.3.0|67|12345600
4+
1.3.6.1.2.1.1.4.0|4|<private>
5+
1.3.6.1.2.1.1.5.0|4|<private>
6+
1.3.6.1.2.1.1.6.0|4|<private>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
1.3.6.1.2.1.43.11.1.1.5.1.1|2|3
2+
1.3.6.1.2.1.43.11.1.1.5.1.2|2|3
3+
1.3.6.1.2.1.43.11.1.1.5.1.3|2|3
4+
1.3.6.1.2.1.43.11.1.1.5.1.4|2|3
5+
1.3.6.1.2.1.43.11.1.1.6.1.1|4|Black Cartridge
6+
1.3.6.1.2.1.43.11.1.1.6.1.2|4|Cyan Cartridge
7+
1.3.6.1.2.1.43.11.1.1.6.1.3|4|Magenta Cartridge
8+
1.3.6.1.2.1.43.11.1.1.6.1.4|4|Yellow Cartridge
9+
1.3.6.1.2.1.43.11.1.1.8.1.1|2|100
10+
1.3.6.1.2.1.43.11.1.1.8.1.2|2|100
11+
1.3.6.1.2.1.43.11.1.1.8.1.3|2|100
12+
1.3.6.1.2.1.43.11.1.1.8.1.4|2|100
13+
1.3.6.1.2.1.43.11.1.1.9.1.1|2|61
14+
1.3.6.1.2.1.43.11.1.1.9.1.2|2|47
15+
1.3.6.1.2.1.43.11.1.1.9.1.3|2|72
16+
1.3.6.1.2.1.43.11.1.1.9.1.4|2|55
17+
1.3.6.1.4.1.11.2.3.9.1.1.7.0|4|MFG:Hewlett-Packard;MDL:HP Color LaserJet Test;CLS:PRINTER;DES:Hewlett-Packard Color LaserJet Test;

0 commit comments

Comments
 (0)