Network
banshee/network-collection/network/mikrotik/snmp/
health
The hardware health of a MikroTik RouterOS or SwitchOS device by SNMP: temperatures, fans, voltages, power, power supplies.
by banshee1 installation2 versions
// The hardware health of a MikroTik device, by SNMP (MIKROTIK-MIB, mtxrHealth): temperatures, fan speeds,
// voltages, currents, power, and the state of the power supplies. RouterOS 7, and the late versions of
// RouterOS 6, serve mtxrGaugeTable, one row per sensor named by the device ("cpu-temperature", "fan1-speed",
// "psu1-state"); an older RouterOS, and SwitchOS, serve the fixed objects of mtxrHealth instead, which the
// collector reads when the table is empty. A device that serves neither, such as a virtual router (CHR),
// stops the collector, rather than stay green on nothing.
need('protocol:snmp');
per('sensor', 'Sensors');
output('temperature', 'number', array('label' => 'Temperature', 'unit' => '°C', 'per' => 'sensor'));
output('fan-speed', 'number', array('label' => 'Fan speed', 'unit' => 'rpm', 'per' => 'sensor'));
output('voltage', 'number', array('label' => 'Voltage', 'unit' => 'V', 'per' => 'sensor'));
output('current', 'number', array('label' => 'Current', 'unit' => 'A', 'per' => 'sensor'));
output('power', 'number', array('label' => 'Power', 'unit' => 'W', 'per' => 'sensor'));
output('status', 'text', array('label' => 'State', 'per' => 'sensor'));
watch.above('hot', 'High temperature', 'temperature', array('warning' => 70, 'critical' => 85, 'for' => '3 runs'));
watch.state('failed', 'Power supply failed', 'status', array('critical' => array('fail')));
// Not checked by default: many MikroTik devices stop their fans while they are cool.
watch.below('fan-stopped', 'Fan stopped', 'fan-speed', array('critical' => 1, 'for' => '2 runs', 'enabled' => false));
watch.below('voltage-low', 'Low voltage', 'voltage', array(
'help' => 'Raises below the voltage set on the probe: the input voltage of a device depends on its power source.',
'enabled' => false,
));
watch.missing('missing', 'Missing sensor', 'status', array('enabled' => false));
// Returns one measure under the output of its kind, and 1, the measure counted.
function report($kind, $measure, $name) {
if ($kind == 'temperature') {
value('temperature', $measure, $name);
} elseif ($kind == 'fan-speed') {
value('fan-speed', $measure, $name);
} elseif ($kind == 'voltage') {
value('voltage', $measure, $name);
} elseif ($kind == 'current') {
value('current', $measure, $name);
} elseif ($kind == 'power') {
value('power', $measure, $name);
} else {
value('status', $measure, $name);
}
return 1;
}
// mtxrGaugeTable, by mtxrGaugeIndex: mtxrGaugeName, mtxrGaugeValue and mtxrGaugeUnit.
$gauges = snmp.table(array(
'name' => '1.3.6.1.4.1.14988.1.1.3.100.1.2',
'value' => '1.3.6.1.4.1.14988.1.1.3.100.1.3',
'unit' => '1.3.6.1.4.1.14988.1.1.3.100.1.4',
));
$read = 0;
// mtxrGaugeUnit: celsius (1), rpm (2), dV (3), dA (4), dW (5), status (6). A status reads 0 when it is ok
// and 1 when it fails, as RouterOS shows "ok" and "fail".
$kinds = array(1 => 'temperature', 2 => 'fan-speed', 3 => 'voltage', 4 => 'current', 5 => 'power', 6 => 'status');
foreach ($gauges as $index => $row) {
if (!list.has($row, 'name') || !list.has($row, 'value') || !list.has($kinds, list.get($row, 'unit', 0))) {
continue;
}
$kind = $kinds[$row['unit']];
$measure = $row['value'];
if ($row['unit'] >= 3 && $row['unit'] <= 5) {
$measure = number.round($measure / 10, 1);
}
if ($kind == 'status') {
$measure = 'state ' . $measure;
if ($row['value'] == 0) {
$measure = 'ok';
} elseif ($row['value'] == 1) {
$measure = 'fail';
}
}
$read = $read + report($kind, $measure, $row['name']);
}
// The fixed objects of mtxrHealth, read when the device serves no gauge. Each one: its name, its kind, and
// what its value is divided by. Voltage, Temperature and Power are in tenths; mtxrHlCurrent in mA;
// mtxrHlPowerSupplyState and mtxrHlBackupPowerSupplyState are true (1) when the supply is ok.
if ($read == 0) {
$health = snmp.walk('1.3.6.1.4.1.14988.1.1.3');
$objects = array(
'1' => array('name' => 'core-voltage', 'kind' => 'voltage', 'divide' => 10),
'2' => array('name' => '3.3v-voltage', 'kind' => 'voltage', 'divide' => 10),
'3' => array('name' => '5v-voltage', 'kind' => 'voltage', 'divide' => 10),
'4' => array('name' => '12v-voltage', 'kind' => 'voltage', 'divide' => 10),
'5' => array('name' => 'sensor-temperature', 'kind' => 'temperature', 'divide' => 10),
'6' => array('name' => 'cpu-temperature', 'kind' => 'temperature', 'divide' => 10),
'7' => array('name' => 'board-temperature', 'kind' => 'temperature', 'divide' => 10),
'8' => array('name' => 'voltage', 'kind' => 'voltage', 'divide' => 10),
'10' => array('name' => 'temperature', 'kind' => 'temperature', 'divide' => 10),
'11' => array('name' => 'processor-temperature', 'kind' => 'temperature', 'divide' => 10),
'12' => array('name' => 'power-consumption', 'kind' => 'power', 'divide' => 10),
'13' => array('name' => 'current', 'kind' => 'current', 'divide' => 1000),
'15' => array('name' => 'psu-state', 'kind' => 'status', 'divide' => 1),
'16' => array('name' => 'backup-psu-state', 'kind' => 'status', 'divide' => 1),
'17' => array('name' => 'fan1-speed', 'kind' => 'fan-speed', 'divide' => 1),
'18' => array('name' => 'fan2-speed', 'kind' => 'fan-speed', 'divide' => 1),
);
foreach ($objects as $number => $object) {
$raw = list.get($health, $number . '.0', '');
if ($raw == '') {
continue;
}
$measure = number.round($raw / $object['divide'], 1);
if ($object['kind'] == 'status') {
$measure = 'fail';
if ($raw == 1) {
$measure = 'ok';
}
}
$read = $read + report($object['kind'], $measure, $object['name']);
}
}
if ($read == 0) {
fail('misconfigured', 'The device serves no health value (mtxrHealth, MIKROTIK-MIB)',
'A device without sensors, such as a virtual router (CHR), or a view that does not grant MIKROTIK-MIB to the poller.');
}