diff --git a/contrib/convert-mib-graphs.sh b/contrib/convert-mib-graphs.sh new file mode 100755 index 0000000000..44a554f11d --- /dev/null +++ b/contrib/convert-mib-graphs.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# Script to convert RRDs from the experimental first release of MIB-based polling. + +set -e +set -u + +for i; do + base=${i%%.rrd} + if [ -e $i.old ]; then + continue + fi + mv $i $i.old + echo "Processing $i" + rrdtool dump $i.old | sed -e 's|.*|mibval|' > $base.xml + rrdtool restore $base.xml $i + rm -f $base.xml +done + +exit 0 diff --git a/contrib/findit b/contrib/findit index 14151b2f95..09fd96359e 100755 --- a/contrib/findit +++ b/contrib/findit @@ -5,6 +5,7 @@ find . \ -path ./html/includes/geshi -prune -o \ -path ./html/includes/jpgraph -prune -o \ -path ./html/js/jqplot -prune -o \ + -path ./lib -prune -o \ -path ./junk -prune -o \ -path ./logs -prune -o \ -path ./mibs -prune -o \ diff --git a/doc/Extensions/MIB-based-polling.md b/doc/Extensions/MIB-based-polling.md new file mode 100644 index 0000000000..d7892fffbb --- /dev/null +++ b/doc/Extensions/MIB-based-polling.md @@ -0,0 +1,159 @@ +## WARNING ## + +MIB-based polling is experimental. It might overload your LibreNMS server, +destroy your data, set your routers on fire, and kick your cat. It has been +tested against a very limited set of devices (namely Ruckus ZD1000 wireless +controllers, and `net-snmp` on Linux). It may fail badly on other hardware. + +The approach taken is fairly simplistic and I claim no special expertise in +understanding MIBs. Most of my knowledge of SNMP comes from reading net-snmp +man pages, and reverse engineering the output of snmptranslate and snmpwalk +and trying to make devices work with LibreNMS. I may have made false +assumptions and probably use wrong terminology in many places. Feel free to +offer corrections/suggestions via pull requests or email. + +Paul Gear + +## Overview ## + +This is the 2nd experimental release of MIB polling. If you used the 1st +release, you MUST perform a data conversion of the MIB-based polling files +using the script `contrib/convert-mib-graphs.sh`. Failure to do so will +result in your data collection silently stopping. + +MIB-based polling is disabled by default; you must set + `$config['poller_modules']['mib'] = 1;` +in `config.php` to enable it. + +## Preparation ## + +MIB-based polling results in the creation of a separate RRD file for each +device-MIB-OID-index combination encountered by LibreNMS. Thus it can cause +your disk space requirements to grow enormously and rapidly. As an example, +enabling MIB-based polling on my test Ruckus ZD1000 wireless controller with +one (1) AP and one (1) user on that AP resulted in a 5 MB increase in RRD +space usage for that device. Each RRD file is around 125 KB in size (on +x64-64 systems) and is pre-allocated, so after the first discovery and poller +run of each devicewith MIB-based polling enabled, disk space should be stable. +However, monitoring disk usage is your responsibility. (The good news: you +can do this with LibreNMS. :-) + +Unless you are running LibreNMS on a powerful system with pure SSD for RRD +storage, it is strongly recommended that you enable rrdcached and ensure it is +working *before* enabling MIB-based polling. + +## Components ## + +The components involved in MIB-based polling are: + +### Discovery ### + + - OS discovery determines whether there are MIBs which should be polled. If + so, they are registered in the `device_mibs` association table as relevant + to that device. MIB associations for each device can be viewed at: + http://your.librenms.server/device/device=XXXX/tab=mib/ + All MIBs used by MIB-based polling may be viewed at: + http://your.librenms.server/mibs/ + All device associations created by MIB-based polling may be viewed at: + http://your.librenms.server/mib_assoc/ (Devices -> MIB associations) + + - In addition, all devices are checked for a MIB matching their sysObjectID. + If there is a matching MIB available, it is automatically included. + The sysObjectID for each device is now displayed on the overview page: + http://your.librenms.server/device/device=XXXX/ + + - Note that the above means that no MIB-based polling will occur until the + devices in question are rediscovered. If you want to begin MIB-based + polling immediately, you must force rediscovery from the web UI, or run it + from the CLI using `./discovery.php -h HOSTNAME` + + - During discovery, relevant MIBs are parsed using `snmptranslate`, and the + data returned is used to populate a database which guides the poller in + what to store. At the moment, only OIDs with Unsigned32 and Counter64 + data types are parsed. + + - Devices may be excluded from MIB polling by changing the setting in the + device edit screen: + http://your.librenms.server/device/device=XXXX/tab=edit/section=modules/ + +### Polling ### + + - During polling the MIB associations for the device are looked up, and the + MIB is polled for current values. You can see the values which LibreNMS + has retrieved from the MIB poller in the "Device MIB values" section of + http://your.librenms.server/device/device=XXXX/tab=mib/ + + - Data from the latest poll is saved in the table `device_oids`, and RRD + files are saved in the relevant device directory as + mibName-oidName-index.rrd + +### Graphing ### + + - For each graph type defined in the database, a graph will appear in: + http://your.librenms.server/device/device=XXXX/tab=graphs/group=mib/ + - MIB graphs are generated generically by + `html/includes/graphs/device/mib.inc.php` + There is presently no customisation of graphs available. + - If there is only one index under a given OID, it is displayed as a normal + line graph; if there multiple OIDs, they are displayed as a stacked graph. + At the moment, all indices are placed in the same graph. This is + non-optimal for, e.g., wifi controllers with hundreds of APs attached. + +### Alerting ### + +There is no specific support for alerting in the MIB-based polling engine, but +the data it collects may be used in alerts. Here's an example of an alert +which detects when a Ruckus wireless controller reports meshing disabled on an +access point: + http://libertysys.com.au/imagebin/3btw98DR.png + + +## Adding/testing other device types ## + +One of the goals of this work is to help take out the heavy lifting of adding +new device types. Even if you want fully-customised graphs or tables, you can +still use the MIB-based poller to make it easy to gather the data you want to +graph. + +### How to add a new device MIB ### + + 1. Ensure the manufacturer's MIB is present in the mibs directory. If you + plan to submit your work to LibreNMS, make sure you attribute the source + of the MIB, including the exact download URL if possible, or explicit + instructions about how to obtain it. + 2. Check that `snmptranslate -Ts -M mibs -m MODULE | grep mibName` produces + a named list of OIDs. See the comments on `snmp_mib_walk()` in + `includes/snmp.inc.php` for an example. + 3. Check that `snmptranslate -Td -On -M mibs -m MODULE MODULE::mibName` + produces a parsed description of the OID values. An example can be + found in the comments for `snmp_mib_parse()` in `includes/snmp.inc.php`. + 4. Get the `sysObjectID` from a device, for example: + ```snmpget -v2c -c public -OUsb -m SNMPv2-MIB -M /opt/librenms/mibs -t 30 hostname sysObjectID.0``` + 5. Ensure `snmptranslate -m all -M /opt/librenms/mibs OID 2>/dev/null` + (where OID is the value returned for sysObjectID above) results in a + valid name for the MIB. See the comments for `snmp_translate()` in + `includes/snmp.inc.php` for an example. If this step fails, it means + there is something wrong with the MIB and `net-snmp` cannot parse it. + 6. Add any additional MIBs you wish to poll for specific device types to + `includes/discovery/os/OSNAME.inc.php` by calling `poll_mibs()` with the + MIB module and name. See `includes/discovery/os/ruckuswireless.inc.php` + for an example. + 7. That should be all you need to see MIB graphs! + 8. If you want to develop more customised support for a particular OS, you + can follow the above process, then use the resultant data collected by + LibreNMS in the RRD files or the database tables `device_oids` + + +## TODO ## + +What's not included in MIB-based polling at present? These may be present in +future versions. Pull requests gratefully accepted! + + - Parse and save integer and timetick data types. + - Filter MIBs/OIDs from being polled and/or saved. + - Move graphs from the MIB section to elsewhere. e.g. If a device uses a + unique MIB for CPU utilisation, we should display it under the relevant + health tab. + - Combine multiple MIB values into graphs automatically on a predefined or + user-defined basis. + - Include MIB types in stats submissions. diff --git a/doc/General/MIB-based-polling.md b/doc/General/MIB-based-polling.md deleted file mode 100644 index 5b390387b9..0000000000 --- a/doc/General/MIB-based-polling.md +++ /dev/null @@ -1,100 +0,0 @@ -## WARNING ## - -MIB-based polling is experimental. It might overload your LibreNMS server, -destroy your data, set your routers on fire, and kick your cat. It has been -tested against a very limited set of devices (namely Ruckus ZD1000 wireless -controllers, and `net-snmp` on Linux). It may fail badly on other hardware. - -The approach taken is fairly basic and I claim no special expertise in -understanding MIBs. Most of my understanding of SNMP comes from reading -net-snmp man pages, and reverse engineering the output of snmptranslate and -snmpwalk and trying to make devices work with LibreNMS. I may have made -false assumptions and probably use wrong terminology in many places. Feel -free to offer corrections/suggestions via pull requests or email. - -Paul Gear - -## Overview ## - -MIB-based polling is disabled by default; you must set - `$config['poller_modules']['mib'] = 1;` -in `config.php` to enable it. - -The components involved in of MIB-based support are: - -### Discovery ### - - - MIB-based detection is not involved; any work done here would have to be - duplicated by the poller and thus would only increase load. - -### Polling ### - - - The file `includes/snmp.inc.php` now contains code which can parse MIBs - using `snmptranslate` and use the data returned to populate an array - which guides the poller in what to store. At the moment, only OIDs with - Unsigned32 and Counter64 data types are parsed. - - `includes/polling/mib.inc.php` looks for a MIB matching sysObjectID in - the MIB directory; if one is found, it: - - parses it - - walks that MIB on the device - - stores any numeric results in individual RRD files - - updates/adds graph definitions in the previously-unused graph_types - database table - - Individual OSes (`includes/polling/os/*.inc.php`) can poll extra MIBs - for a given OS by calling `poll_mib()`. At the moment, this actually - happens before the general MIB polling. - - Devices may be excluded from MIB polling by changing the setting in the - device edit screen (`/device/device=ID/tab=edit/section=modules/`) - -### Graphing ### - - - For each graph type defined in the database, a graph will appear in: - Device -> Graphs -> MIB - - MIB graphs are generated generically by - `html/includes/graphs/device/mib.inc.php` - - At the moment, all units are placed in the same graph. This is probably - non-optimal for, e.g., wifi controllers with hundreds of APs attached. - -## Adding/testing other device types ## - -One of the goals of this work is to help take out the heavy lifting of -adding new device types. Even if you want fully customised graphs or -tables, you can use the automatic collection of MIBs to make it easy to -gather the data you want. - -### How to add a new device MIB ### - - 1. Ensure the manufacturer's MIB is present in the mibs directory. If you - plan to submit your work to LibreNMS, make sure you attribute the source - of the MIB, including the exact download URL. - 2. Check that `snmptranslate -Ts -M mibs -m MODULE | grep mibName` produces - a named list of OIDs. See the comments for `snmp_mib_walk()` in - `includes/snmp.inc.php` for an example. - 3. Check that `snmptranslate -Td -On -M mibs -m MODULE MODULE::mibName` - produces a parsed description of the OID values. An example can be - found in the comments for `snmp_mib_parse()` in `includes/snmp.inc.php`. - 4. Get the `sysObjectID` from a device, for example: - ```snmpget -v2c -c public -OUsb -m SNMPv2-MIB -M /opt/librenms/mibs -t 30 hostname sysObjectID.0``` - 5. Ensure `snmptranslate -m all -M /opt/librenms/mibs OID 2>/dev/null` - (where OID is the value returned for sysObjectID above) results in a - valid name for the MIB. See the comments for `snmp_translate()` in - `includes/snmp.inc.php` for an example. If this step fails, it means - there is something wrong with the MIB and `net-snmp` cannot parse it. - 6. Add any additional MIBs you wish to poll for specific device types to - `includes/polling/os/OSNAME.inc.php` by calling `poll_mibs()` with the - MIB module and name. See `includes/polling/os/ruckuswireless.inc.php` for - an example. - 7. That should be all you need to see MIB graphs! - -## TODO ## - - - Save the most recent MIB data in the database (including string types - which cannot be graphed). Display it in the appropriate places. - - Parse and save integer and timetick data types. - - Filter MIBs/OIDs from being polled and/or saved. - - Move graphs from the MIB section to elsewhere. e.g. There is already - specific support for wireless APs - this should be utilised, but isn't - yet. - - Combine multiple MIB values into graphs automatically on a predefined or - user-defined basis. - - Include MIB types in stats submissions. diff --git a/doc/General/Roadmap.md b/doc/General/Roadmap.md deleted file mode 100644 index 6680a000a7..0000000000 --- a/doc/General/Roadmap.md +++ /dev/null @@ -1,20 +0,0 @@ -- Device support: - - Ruckus wireless controllers - - Investigate generic device support based on MIBs. It should be - possible to do basic graphs based just on the MIB. They would - obviously not be as customised as the specifically supported devices - but should still be useful to users. - -- Functionality/performance improvements: - - Investigate solutions for poller performance improvement. - - Investigate solutions for multiple communities per device. - - Eliminate interface churn for transient interfaces (e.g. ppp/tun) on - net-snmp. - -- Consider adding some non-monitoring administrative functions: - - enabling/disabling ports - - changing access port VLANs - - editing port labels - -- Integrate as many usability improvements as time permits: - - Front page: more automation; GUI configuration diff --git a/html/includes/dev-overview-data.inc.php b/html/includes/dev-overview-data.inc.php index de602c18fd..6ff78d43c4 100644 --- a/html/includes/dev-overview-data.inc.php +++ b/html/includes/dev-overview-data.inc.php @@ -49,6 +49,13 @@ if ($device['serial']) { '; } +if ($device['sysObjectID']) { + echo ' + Object ID + '.$device['sysObjectID'].' + '; +} + if ($device['sysContact']) { echo ' Contact'; diff --git a/html/includes/graphs/custom.inc.php b/html/includes/graphs/custom.inc.php new file mode 100644 index 0000000000..274eadab6f --- /dev/null +++ b/html/includes/graphs/custom.inc.php @@ -0,0 +1,43 @@ + + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +// FIXME: Dummy implementation which only supports ruckuswireless processor & mempool + +$i = 0; +$rrd_list = array(); +if ($subtype == 'processor') { + $rrd_list[0] = array( + 'area' => 1, + 'ds' => 'mibval', + 'descr' => 'CPU Utilization', + 'filename' => rrd_name($device['hostname'], array('ruckusZDSystemStats-CPUUtil-0')), + ); +} + +if ($subtype == 'mempool') { + $rrd_list[0] = array( + 'area' => 1, + 'ds' => 'mibval', + 'descr' => 'Memory Utilization', + 'filename' => rrd_name($device['hostname'], array('ruckusZDSystemStats-MemoryUtil-0')), + ); +} + +$units = '%%'; +$colours = 'mixed'; +$scale_min = '0'; +$scale_max = '100'; +$nototal = 1; + +require_once 'includes/graphs/generic_multi_line.inc.php'; diff --git a/html/includes/graphs/device/mib.inc.php b/html/includes/graphs/device/mib.inc.php index 08241e9226..b97cca8556 100644 --- a/html/includes/graphs/device/mib.inc.php +++ b/html/includes/graphs/device/mib.inc.php @@ -13,25 +13,35 @@ */ $rrd_list = array(); -$prefix = rrd_name($device['hostname'], array($subtype, ''), ''); -foreach (glob($prefix.'*.rrd') as $filename) { +$prefix = rrd_name($device['hostname'], array($subtype, ''), ''); +$filenames = glob($prefix."*.rrd"); +$count = count($filenames); +foreach ($filenames as $filename) { // find out what * expanded to - $globpart = str_replace($prefix, '', $filename); - // take off the prefix - $instance = substr($globpart, 0, -4); - // take off ".rrd" + $globpart = str_replace($prefix, '', $filename); // take off the prefix + $instance = substr($globpart, 0, -4); // take off ".rrd" $ds = array(); $mibparts = explode('-', $subtype); $mibvar = end($mibparts); - $ds['ds'] = name_shorten($mibvar); + $ds['ds'] = 'mibval'; $ds['descr'] = "$mibvar-$instance"; $ds['filename'] = $filename; $rrd_list[] = $ds; } -$colours = 'mixed'; $scale_min = '0'; -$nototal = 0; $simple_rrd = true; -require 'includes/graphs/generic_multi_line.inc.php'; +// If there are multiple matching files, use a stacked graph instead of a line graph +if ($count > 1) { + $nototal = 1; + $divider = $count; + $text_orig = 1; + $colours = 'manycolours'; + include "includes/graphs/generic_multi_simplex_seperated.inc.php"; +} +else { + $colours = 'mixed'; + $nototal = 0; + include "includes/graphs/generic_multi_line.inc.php"; +} diff --git a/html/includes/graphs/device/processor_separate.inc.php b/html/includes/graphs/device/processor_separate.inc.php index 2b59802566..de0760ac68 100644 --- a/html/includes/graphs/device/processor_separate.inc.php +++ b/html/includes/graphs/device/processor_separate.inc.php @@ -18,7 +18,7 @@ foreach ($procs as $proc) { $unit_text = 'Load %'; -$units = '%'; +$units = ''; $total_units = '%'; $colours = 'mixed'; diff --git a/html/includes/graphs/generic_multi_line.inc.php b/html/includes/graphs/generic_multi_line.inc.php index 513b23674c..e4758958e7 100644 --- a/html/includes/graphs/generic_multi_line.inc.php +++ b/html/includes/graphs/generic_multi_line.inc.php @@ -36,6 +36,9 @@ foreach ($rrd_list as $rrd) { } $colour = $config['graph_colours'][$colours][$iter]; + if (!empty($rrd['area']) && empty($rrd['areacolour'])) { + $rrd['areacolour'] = $colour."20"; + } $ds = $rrd['ds']; $filename = $rrd['filename']; @@ -69,8 +72,8 @@ foreach ($rrd_list as $rrd) { } } - $rrd_optionsb .= ' GPRINT:'.$id.':LAST:%5.2lf%s GPRINT:'.$id.'min:MIN:%5.2lf%s'; - $rrd_optionsb .= ' GPRINT:'.$id.'max:MAX:%5.2lf%s GPRINT:'.$id.":AVERAGE:'%5.2lf%s\\n'"; + $rrd_optionsb .= ' GPRINT:'.$id.':LAST:%5.2lf%s'.$units.' GPRINT:'.$id.'min:MIN:%5.2lf%s'.$units; + $rrd_optionsb .= ' GPRINT:'.$id.'max:MAX:%5.2lf%s'.$units.' GPRINT:'.$id.":AVERAGE:'%5.2lf%s$units\\n'"; $i++; $iter++; diff --git a/html/includes/graphs/graph.inc.php b/html/includes/graphs/graph.inc.php index d7ed4cbc89..3e30d4b8e4 100644 --- a/html/includes/graphs/graph.inc.php +++ b/html/includes/graphs/graph.inc.php @@ -43,12 +43,15 @@ if ($auth !== true && $auth != 1) { require $config['install_dir']."/html/includes/graphs/$type/auth.inc.php"; -if ($auth === true && is_file($config['install_dir']."/html/includes/graphs/$type/$subtype.inc.php")) { - include $config['install_dir']."/html/includes/graphs/$type/$subtype.inc.php"; +if ($auth === true && is_custom_graph($type, $subtype, $device)) { + include($config['install_dir'] . "/html/includes/graphs/custom.inc.php"); } else if ($auth === true && is_mib_graph($type, $subtype)) { include $config['install_dir']."/html/includes/graphs/$type/mib.inc.php"; } +elseif ($auth === true && is_file($config['install_dir']."/html/includes/graphs/$type/$subtype.inc.php")) { + include $config['install_dir']."/html/includes/graphs/$type/$subtype.inc.php"; +} else { graph_error("$type*$subtype "); // Graph Template Missing"); diff --git a/html/includes/print-menubar.php b/html/includes/print-menubar.php index 424d273ab5..7059a269e1 100644 --- a/html/includes/print-menubar.php +++ b/html/includes/print-menubar.php @@ -110,6 +110,8 @@ if ( dbFetchCell("SELECT 1 from `packages` LIMIT 1") ) {
  • IPv6 Search
  • MAC Search
  • ARP Tables
  • + +
  • MIB definitions
  • +
  • 'mib_assoc')).'> MIB associations
  • + '; if ($config['navbar']['manage_groups']['hide'] === 0) { diff --git a/html/includes/table/device_mibs.inc.php b/html/includes/table/device_mibs.inc.php new file mode 100644 index 0000000000..6228df94c3 --- /dev/null +++ b/html/includes/table/device_mibs.inc.php @@ -0,0 +1,96 @@ + + * + * by Paul Gear + * based on code by Søren Friis Rosiak + * in commit 054bf3ae209f34a2c3bc8968300722004903df1b + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +$columns = array( + 'module', + 'mib', + 'included_by', + 'last_modified', +); + +if (isset($_POST['device_id'])) { + // device_id supplied - get details for a single device + // used by device MIB page + $params = array( + $_POST['device_id'], + ); + $sql = 'SELECT * FROM `device_mibs`'; + $wheresql = ' WHERE `device_id` = ?'; + $sortcolumns = 3; + $count_sql = "SELECT COUNT(*) FROM `device_mibs`".$wheresql; +} +else { + // device_id not supplied - get details for a all devices + // used by all device MIBs page + $params = array(); + $sql = 'SELECT `d`.`hostname` as `hostname`, `dm`.* FROM `devices` `d`, `device_mibs` `dm`'; + $wheresql = ' WHERE `d`.`device_id` = `dm`.`device_id`'; + array_unshift($columns, 'hostname'); + $sortcolumns = 4; + $count_sql = "SELECT COUNT(*) FROM `devices` `d`, `device_mibs` `dm`".$wheresql; +} + +// all columns are searchable - search across them +if (isset($searchPhrase) && !empty($searchPhrase)) { + $searchsql = implode(' OR ', array_map("search_phrase_column", array_map("mres", $columns))); + $wheresql .= " AND ( $searchsql )"; +} +$sql .= $wheresql; + +// get total +$total = dbFetchCell($count_sql, $params); +if (empty($total)) { + $total = 0; +} + +// set up default sort +if (!isset($sort) || empty($sort)) { + $sort = implode(', ', array_map("mres", array_slice($columns, 0, $sortcolumns))); +} +$sql .= " ORDER BY $sort"; + +// select only the required rows +if (isset($current)) { + $limit_low = (($current * $rowCount) - ($rowCount)); + $limit_high = $rowCount; +} +if ($rowCount != -1) { + $sql .= " LIMIT $limit_low,$limit_high"; +} + +// load data from database into response array +$response = array(); +foreach (dbFetchRows($sql, $params) as $mib) { + $mibrow = array(); + foreach ($columns as $col) { + $mibrow[$col] = $mib[$col]; + } + if (!isset($_POST['device_id'])) { + $device = device_by_id_cache($mib['device_id']); + $mibrow['hostname'] = generate_device_link($device, + $mib['hostname'], array('tab' => 'mib')); + } + $response[] = $mibrow; +} + +$output = array( + 'current' => $current, + 'rowCount' => $rowCount, + 'rows' => $response, + 'total' => $total, +); +echo _json_encode($output); diff --git a/html/includes/table/device_oids.inc.php b/html/includes/table/device_oids.inc.php new file mode 100644 index 0000000000..3c10730d25 --- /dev/null +++ b/html/includes/table/device_oids.inc.php @@ -0,0 +1,83 @@ + + * + * by Paul Gear + * based on code by Søren Friis Rosiak + * in commit 054bf3ae209f34a2c3bc8968300722004903df1b + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +$columns = array( + 'module', + 'mib', + 'object_type', + 'oid', + 'value', + 'numvalue', + 'last_modified', +); + + +$params = array( + $_POST['device_id'], +); + +// start of sql definition +$sql = 'SELECT * FROM `device_oids`'; + +$wheresql = ' WHERE `device_id` = ?'; + +// all columns are searchable - search across them +if (isset($searchPhrase) && !empty($searchPhrase)) { + $searchsql = implode(' OR ', array_map("search_phrase_column", array_map("mres", $columns))); + $wheresql .= " AND ( $searchsql )"; +} +$sql .= $wheresql; + +// get total +$count_sql = "SELECT COUNT(*) FROM `device_oids`".$wheresql; +$total = dbFetchCell($count_sql, $params); +if (empty($total)) { + $total = 0; +} + +// sort by first three columns by default +if (!isset($sort) || empty($sort)) { + $sort = implode(', ', array_map("mres", array_slice($columns, 0, 3))); +} +$sql .= " ORDER BY $sort"; + +// select only the required rows +if (isset($current)) { + $limit_low = (($current * $rowCount) - ($rowCount)); + $limit_high = $rowCount; +} +if ($rowCount != -1) { + $sql .= " LIMIT $limit_low,$limit_high"; +} + +// load data from database into response array +$response = array(); +foreach (dbFetchRows($sql, $params) as $mib) { + $mibrow = array(); + foreach ($columns as $col) { + $mibrow[$col] = $mib[$col]; + } + $response[] = $mibrow; +} + +$output = array( + 'current' => $current, + 'rowCount' => $rowCount, + 'rows' => $response, + 'total' => $total, +); +echo _json_encode($output); diff --git a/html/includes/table/mibs.inc.php b/html/includes/table/mibs.inc.php new file mode 100644 index 0000000000..2c9319b37e --- /dev/null +++ b/html/includes/table/mibs.inc.php @@ -0,0 +1,81 @@ + + * + * by Paul Gear + * based on code by Søren Friis Rosiak + * in commit 054bf3ae209f34a2c3bc8968300722004903df1b + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +$columns = array( + 'module', + 'mib', + 'object_type', + 'oid', + 'syntax', + 'description', + 'max_access', + 'status', + 'included_by', + 'last_modified', +); + + +// start of sql definition +$sql = 'SELECT * FROM `mibdefs`'; + +// all columns are searchable - search across them +if (isset($searchPhrase) && !empty($searchPhrase)) { + $searchsql = implode(' OR ', array_map("search_phrase_column", array_map("mres", $columns))); + $wheresql .= " WHERE ( $searchsql )"; + $sql .= $wheresql; +} + +// get total +$count_sql = "SELECT COUNT(`object_type`) FROM `mibdefs`".$wheresql; +$total = dbFetchCell($count_sql); +if (empty($total)) { + $total = 0; +} + +// sort by first three columns by default +if (!isset($sort) || empty($sort)) { + $sort = implode(', ', array_map("mres", array_slice($columns, 0, 3))); +} +$sql .= " ORDER BY $sort"; + +// select only the required rows +if (isset($current)) { + $limit_low = (($current * $rowCount) - ($rowCount)); + $limit_high = $rowCount; +} +if ($rowCount != -1) { + $sql .= " LIMIT $limit_low,$limit_high"; +} + +// load data from database into response array +$response = array(); +foreach (dbFetchRows($sql) as $mib) { + $mibrow = array(); + foreach ($columns as $col) { + $mibrow[$col] = $mib[$col]; + } + $response[] = $mibrow; +} + +$output = array( + 'current' => $current, + 'rowCount' => $rowCount, + 'rows' => $response, + 'total' => $total, +); +echo _json_encode($output); diff --git a/html/pages/device.inc.php b/html/pages/device.inc.php index 1a68f9dbf3..5fc2c18d22 100644 --- a/html/pages/device.inc.php +++ b/html/pages/device.inc.php @@ -57,7 +57,11 @@ if (device_permitted($vars['device']) || $check_device == $vars['device']) { '; - $health = (dbFetchCell("SELECT COUNT(*) FROM storage WHERE device_id = '".$device['device_id']."'") + dbFetchCell("SELECT COUNT(sensor_id) FROM sensors WHERE device_id = '".$device['device_id']."'") + dbFetchCell("SELECT COUNT(*) FROM mempools WHERE device_id = '".$device['device_id']."'") + dbFetchCell("SELECT COUNT(*) FROM processors WHERE device_id = '".$device['device_id']."'")); + $health = dbFetchCell("SELECT COUNT(*) FROM storage WHERE device_id = '" . $device['device_id'] . "'") + + dbFetchCell("SELECT COUNT(sensor_id) FROM sensors WHERE device_id = '" . $device['device_id'] . "'") + + dbFetchCell("SELECT COUNT(*) FROM mempools WHERE device_id = '" . $device['device_id'] . "'") + + dbFetchCell("SELECT COUNT(*) FROM processors WHERE device_id = '" . $device['device_id'] . "'") + + count_mib_health($device); if ($health) { echo '
  • @@ -367,6 +371,14 @@ if (device_permitted($vars['device']) || $check_device == $vars['device']) {
  • '; + if (device_permitted($device['device_id'])) { + echo '
  • + + MIB + +
  • '; + } + echo '
  • https
  • ssh
  • diff --git a/html/pages/device/graphs.inc.php b/html/pages/device/graphs.inc.php index 154cbbfb51..8c8512b50e 100644 --- a/html/pages/device/graphs.inc.php +++ b/html/pages/device/graphs.inc.php @@ -22,11 +22,7 @@ foreach (dbFetchRows('SELECT * FROM device_graphs WHERE device_id = ? ORDER BY g } } -// These are standard graphs we should have for all systems -$graph_enable['poller']['poller_perf'] = 'device_poller_perf'; -if (can_ping_device($attribs) === true) { - $graph_enable['poller']['ping_perf'] = 'device_ping_perf'; -} +enable_graphs($device, $graph_enable); $sep = ''; foreach ($graph_enable as $section => $nothing) { @@ -56,7 +52,6 @@ print_optionbar_end(); $graph_enable = $graph_enable[$vars['group']]; -// foreach ($config['graph_types']['device'] as $graph => $entry) foreach ($graph_enable as $graph => $entry) { $graph_array = array(); if ($graph_enable[$graph]) { diff --git a/html/pages/device/graphs/cpu.inc.php b/html/pages/device/graphs/cpu.inc.php deleted file mode 100644 index 10b1086d0e..0000000000 --- a/html/pages/device/graphs/cpu.inc.php +++ /dev/null @@ -1,8 +0,0 @@ - 0) { + $mempools = get_mib_mempools($device); + $graph_type = 'device_mempool'; +} +else { + $mempools = dbFetchRows('SELECT * FROM `mempools` WHERE device_id = ?', array($device['device_id'])); +} + // FIXME css alternating colours -foreach (dbFetchRows('SELECT * FROM `mempools` WHERE device_id = ?', array($device['device_id'])) as $mempool) { +foreach ($mempools as $mempool) { if (!is_integer($i / 2)) { $row_colour = $list_colour_a; } @@ -15,30 +23,49 @@ foreach (dbFetchRows('SELECT * FROM `mempools` WHERE device_id = ?', array($devi $text_descr = rewrite_entity_descr($mempool['mempool_descr']); - $mempool_url = 'graphs/id='.$mempool['mempool_id'].'/type=mempool_usage/'; - $mini_url = 'graph.php?id='.$mempool['mempool_id'].'&type='.$graph_type.'&from='.$config['time']['day'].'&to='.$config['time']['now'].'&width=80&height=20&bg=f4f4f4'; + if ($graph_type == 'device_mempool') { + $id = 'device'; + $val = $device['device_id']; + } + else { + $id = 'id'; + $val = $mempool['mempool_id']; + } + $mempool_url = 'graphs/'.$id.'='.$val.'/type='.$graph_type.'/'; + $mini_url = 'graph.php?'.$id.'='.$val.'&type='.$graph_type.'&from='.$config['time']['day'].'&to='.$config['time']['now'].'&width=80&height=20&bg=f4f4f4'; $mempool_popup = "onmouseover=\"return overlib('
    ".$device['hostname'].' - '.$text_descr; - $mempool_popup .= "
    "; + $mempool_popup .= ""; $mempool_popup .= "', RIGHT".$config['overlib_defaults'].');" onmouseout="return nd();"'; $total = formatStorage($mempool['mempool_total']); $used = formatStorage($mempool['mempool_used']); $free = formatStorage($mempool['mempool_free']); - $perc = round(($mempool['mempool_used'] / $mempool['mempool_total'] * 100)); + // don't bother recalculating if mempools use percentage + if ($mempool['percentage'] === true) { + $perc = round($mempool['mempool_used']); + } + else { + $perc = round(($mempool['mempool_used'] / $mempool['mempool_total'] * 100)); + } $background = get_percentage_colours($percent); $right_background = $background['right']; $left_background = $background['left']; - $graph_array['id'] = $mempool['mempool_id']; + $graph_array[$id] = $val; $graph_array['type'] = $graph_type; echo "
    -
    -

    $text_descr
    $used/$total - $perc% used

    -
    "; +
    "; + if ($mempool['percentage'] === true) { + echo "

    $text_descr
    $perc% used

    "; + } + else { + echo "

    $text_descr
    $used/$total - $perc% used

    "; + } + echo "
    "; echo "
    "; include 'includes/print-graphrow.inc.php'; echo "
    "; diff --git a/html/pages/device/health/processor.inc.php b/html/pages/device/health/processor.inc.php index dd60448a3b..1ffdc2a6bb 100644 --- a/html/pages/device/health/processor.inc.php +++ b/html/pages/device/health/processor.inc.php @@ -3,21 +3,36 @@ $graph_type = 'processor_usage'; $i = '1'; -foreach (dbFetchRows('SELECT * FROM `processors` WHERE device_id = ?', array($device['device_id'])) as $proc) { - $proc_url = 'graphs/id='.$proc['processor_id'].'/type=processor_usage/'; - $mini_url = 'graph.php?id='.$proc['processor_id'].'&type='.$graph_type.'&from='.$config['time']['day'].'&to='.$config['time']['now'].'&width=80&height=20&bg=f4f4f4'; +if (count_mib_processors($device) > 0) { + $processors = get_mib_processors($device); + $graph_type = 'device_processor'; +} +else { + $processors = dbFetchRows('SELECT * FROM `processors` WHERE device_id = ?', array($device['device_id'])); +} - $text_descr = $proc['processor_descr']; +foreach ($processors as $proc) { + if ($graph_type == 'device_processor') { + $id = 'device'; + $val = $device['device_id']; + } + else { + $id = 'id'; + $val = $proc['processor_id']; + } + $proc_url = 'graphs/'.$id.'='.$val.'/type='.$graph_type.'/'; + $base_url = 'graph.php?'.$id.'='.$val.'&type='.$graph_type.'&from='.$config['time']['day'].'&to='.$config['time']['now']; + $mini_url = $base_url.'&width=80&height=20&bg=f4f4f4'; - $text_descr = rewrite_entity_descr($text_descr); + $text_descr = rewrite_entity_descr($proc['processor_descr']); $proc_popup = "onmouseover=\"return overlib('
    ".$device['hostname'].' - '.$text_descr; - $proc_popup .= "
    "; + $proc_popup .= ""; $proc_popup .= "', RIGHT".$config['overlib_defaults'].');" onmouseout="return nd();"'; $percent = round($proc['processor_usage']); - $graph_array['id'] = $proc['processor_id']; + $graph_array[$id] = $val; $graph_array['type'] = $graph_type; echo "
    @@ -27,4 +42,4 @@ foreach (dbFetchRows('SELECT * FROM `processors` WHERE device_id = ?', array($de echo "
    "; include 'includes/print-graphrow.inc.php'; echo "
    "; -}//end foreach \ No newline at end of file +}//end foreach diff --git a/html/pages/device/mib.inc.php b/html/pages/device/mib.inc.php new file mode 100644 index 0000000000..7c56d57c3b --- /dev/null +++ b/html/pages/device/mib.inc.php @@ -0,0 +1,88 @@ + + * + * Author: Paul Gear + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +if (!isset($vars['section'])) { + $vars['section'] = "mib"; +} +?> + +

    Device MIB associations

    +
    + + + + + + + + + +
    ModuleMIBIncluded byLast Modified
    +
    + +

    Device MIB values

    +
    + + + + + + + + + + + + +
    ModuleMIBObject typeOIDValueNumeric ValueLast Modified
    +
    + + + + diff --git a/html/pages/mib_assoc.inc.php b/html/pages/mib_assoc.inc.php new file mode 100644 index 0000000000..a792e57966 --- /dev/null +++ b/html/pages/mib_assoc.inc.php @@ -0,0 +1,49 @@ + + * + * Author: Paul Gear + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ + +?> + +

    MIB associations for all devices

    +
    + + + + + + + + + + +
    HostnameModuleMIBIncluded byLast Modified
    +
    + + diff --git a/html/pages/mibs.inc.php b/html/pages/mibs.inc.php new file mode 100644 index 0000000000..43769fc73b --- /dev/null +++ b/html/pages/mibs.inc.php @@ -0,0 +1,54 @@ + + * + * Author: Paul Gear + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ +?> + +

    All MIB definitions

    +
    + + + + + + + + + + + + + + +
    ModuleMIBObject TypeObject IdSyntaxDescriptionIncluded byLast modified
    +
    + + diff --git a/includes/common.php b/includes/common.php index de68cfd788..559df195ae 100644 --- a/includes/common.php +++ b/includes/common.php @@ -580,6 +580,7 @@ function edit_service($service, $descr, $service_ip, $service_param = "", $servi } + /* * convenience function - please use this instead of 'if ($debug) { echo ...; }' */ @@ -596,7 +597,8 @@ function d_echo($text, $no_debug_text = null) { elseif ($no_debug_text) { echo "$no_debug_text"; } -} +} // d_echo + /* * convenience function - please use this instead of 'if ($debug) { print_r ...; }' @@ -609,37 +611,8 @@ function d_print_r($var, $no_debug_text = null) { elseif ($no_debug_text) { echo "$no_debug_text"; } -} +} // d_print_r -/* - * Shorten the name so it works as an RRD data source name (limited to 19 chars by default). - * Substitute for $subst if necessary. - * @return the shortened name - */ -function name_shorten($name, $common = null, $subst = "mibval", $len = 19) { - if ($common !== null) { - // remove common from the beginning of the string, if present - if (strlen($name) > $len && strpos($name, $common) >= 0) { - $newname = str_replace($common, '', $name); - $name = $newname; - } - } - if (strlen($name) > $len) { - $name = $subst; - } - return $name; -} - -/* - * @return the name of the rrd file for $host's $extra component - * @param host Host name - * @param extra Components of RRD filename - will be separated with "-" - */ -function rrd_name($host, $extra, $exten = ".rrd") { - global $config; - $filename = safename(is_array($extra) ? implode("-", $extra) : $extra); - return implode("/", array($config['rrd_dir'], $host, $filename.$exten)); -} /* * @return true if the given graph type is a dynamic MIB graph @@ -647,7 +620,8 @@ function rrd_name($host, $extra, $exten = ".rrd") { function is_mib_graph($type, $subtype) { global $config; return $config['graph_types'][$type][$subtype]['section'] == 'mib'; -} +} // is_mib_graph + /* * @return true if client IP address is authorized to access graphs @@ -670,7 +644,8 @@ function is_client_authorized($clientip) { } return false; -} +} // is_client_authorized + /* * @return an array of all graph subtypes for the given type @@ -702,7 +677,8 @@ function get_graph_subtypes($type) { sort($types); return $types; -} +} // get_graph_subtypes + function get_smokeping_files($device) { global $config; @@ -733,6 +709,7 @@ function get_smokeping_files($device) { return $smokeping_files; } // end get_smokeping_files + function generate_smokeping_file($device,$file='') { global $config; if ($config['smokeping']['integration'] === true) { @@ -741,7 +718,8 @@ function generate_smokeping_file($device,$file='') { else { return $config['smokeping']['dir'] . '/' . $file; } -} +} // generate_smokeping_file + /* * @return rounded value to 10th/100th/1000th depending on input (valid: 10, 100, 1000) @@ -758,6 +736,153 @@ function round_Nth($val = 0, $round_to) { } } // end round_Nth + +/* + * FIXME: Dummy implementation + */ +function count_mib_mempools($device) +{ + if ($device['os'] == 'ruckuswireless') { + return 1; + } + return 0; +} // count_mib_mempools + + +/* + * FIXME: Dummy implementation + */ +function count_mib_processors($device) +{ + if ($device['os'] == 'ruckuswireless') { + return 1; + } + return 0; +} // count_mib_processors + + +function count_mib_health($device) +{ + return count_mib_mempools($device) + count_mib_processors($device); +} // count_mib_health + + +function get_mibval($device, $oid) +{ + $sql = 'SELECT * FROM `device_oids` WHERE `device_id` = ? AND `oid` = ?'; + return dbFetchRow($sql, array($device['device_id'], $oid)); +} // get_mibval + + +/* + * FIXME: Dummy implementation - needs an abstraction for each device + */ +function get_mib_mempools($device) +{ + $mempools = array(); + if ($device['os'] == 'ruckuswireless') { + $mempool = array(); + $mibvals = get_mibval($device, '.1.3.6.1.4.1.25053.1.2.1.1.1.15.14.0'); + $mempool['mempool_descr'] = $mibvals['object_type']; + $mempool['mempool_id'] = 0; + $mempool['mempool_total'] = 100; + $mempool['mempool_used'] = $mibvals['numvalue']; + $mempool['mempool_free'] = 100 - $mibvals['numvalue']; + $mempool['percentage'] = true; + $mempools[] = $mempool; + } + return $mempools; +} // get_mib_mempools + + +/* + * FIXME: Dummy implementation - needs an abstraction for each device + */ +function get_mib_processors($device) +{ + $processors = array(); + if ($device['os'] == 'ruckuswireless') { + $proc = array(); + $mibvals = get_mibval($device, '.1.3.6.1.4.1.25053.1.2.1.1.1.15.13.0'); + $proc['processor_descr'] = $mibvals['object_type']; + $proc['processor_id'] = 0; + $proc['processor_usage'] = $mibvals['numvalue']; + $processors[] = $proc; + } + return $processors; +} // get_mib_processors + + +/* + * FIXME: Dummy implementation - needs an abstraction for each device + * @return true if there is a custom graph defined for this type, subtype, and device + */ +function is_custom_graph($type, $subtype, $device) +{ + if ($device['os'] == 'ruckuswireless' && $type == 'device') { + switch ($subtype) { + case 'cpumem': + case 'mempool': + case 'processor': + return true; + } + } + return false; +} // is_custom_graph + + +/* + * FIXME: Dummy implementation + * Set section/graph entries in $graph_enable for graphs specific to $os. + */ +function enable_os_graphs($os, &$graph_enable) +{ + /* + foreach (dbFetchRows("SELECT * FROM graph_conditions WHERE graph_type = 'device' AND condition_name = 'os' AND condition_value = ?", array($os)) as $graph) { + $graph_enable[$graph['graph_section']][$graph['graph_subtype']] = "device_".$graph['graph_subtype']; + } + */ +} // enable_os_graphs + + +/* + * For each os-based or global graph relevant to $device, set its section/graph entry in $graph_enable. + */ +function enable_graphs($device, &$graph_enable) +{ + // These are standard graphs we should have for all systems + $graph_enable['poller']['poller_perf'] = 'device_poller_perf'; + if (can_ping_device($device) === true) { + $graph_enable['poller']['ping_perf'] = 'device_ping_perf'; + } + + enable_os_graphs($device['os'], $graph_enable); +} // enable_graphs + + +// +// maintain a simple cache of objects +// + +function object_add_cache($section, $obj) +{ + global $object_cache; + $object_cache[$section][$obj] = true; +} // object_add_cache + + +function object_is_cached($section, $obj) +{ + global $object_cache; + if (array_key_exists($obj, $object_cache)) { + return $object_cache[$section][$obj]; + } + else { + return false; + } +} // object_is_cached + + /** * Checks if config allows us to ping this device * $attribs contains an array of all of this devices @@ -775,6 +900,61 @@ function can_ping_device($attribs) { } } // end can_ping_device + +/* + * @return true if the requested module type & name is globally enabled + */ +function is_module_enabled($type, $module) +{ + global $config; + if (isset($config[$type.'_modules'][$module])) { + return $config[$type.'_modules'][$module] == 1; + } + else { + return false; + } +} // is_module_enabled + + +/* + * @return true if every string in $arr begins with $str + */ +function begins_with($str, $arr) +{ + foreach ($arr as $s) { + $pos = strpos($s, $str); + if ($pos === false || $pos > 0) { + return false; + } + } + return true; +} // begins_with + + +/* + * @return the longest starting portion of $str that matches everything in $arr + */ +function longest_matching_prefix($str, $arr) +{ + $len = strlen($str); + while ($len > 0) { + $prefix = substr($str, 0, $len); + if (begins_with($prefix, $arr)) { + return $prefix; + } + $len -= 1; + } + return ''; +} // longest_matching_prefix + + +function search_phrase_column($c) +{ + global $searchPhrase; + return "$c LIKE '%$searchPhrase%'"; +} // search_phrase_column + + /** * Constructs the path to an RRD for the Ceph application * @param string $gtype The type of rrd we're looking for @@ -794,7 +974,7 @@ function ceph_rrd($gtype) { $rrd = join('-', array('app', 'ceph', $vars['id'], $gtype, $var)).'.rrd'; return join('/', array($config['rrd_dir'], $device['hostname'], $rrd)); -} +} // ceph_rrd /** * Parse location field for coordinates diff --git a/includes/defaults.inc.php b/includes/defaults.inc.php index 189dc6a92d..f16e584879 100644 --- a/includes/defaults.inc.php +++ b/includes/defaults.inc.php @@ -315,6 +315,17 @@ $config['graph_colours']['purples'] = array( ); $config['graph_colours']['default'] = $config['graph_colours']['blues']; +// Colour values from http://www.sapdesignguild.org/goodies/diagram_guidelines/color_palettes.html +$config['graph_colours']['manycolours'] = array( + "FFF8A3", "FAE16B", "F8D753", "F3C01C", "F0B400", // yellows + "A9CC8F", "82B16A", "5C9746", "3D8128", "1E6C0B", // greens + "B2C8D9", "779DBF", "3E75A7", "205F9A", "00488C", // blues + "BEA37A", "907A52", "7A653E", "63522B", "3D3000", // browns + "F3AA79", "EB8953", "E1662A", "DC5313", "D84000", // oranges + "B5B5A9", "8B8D82", "74796F", "5D645A", "434C43", // greys + "E6A4A5", "D6707B", "C4384F", "BC1C39", "B30023", // pinks +); + // Map colors $config['network_map_legend'] = array( '0' => '#aeaeae', diff --git a/includes/discovery/discovery-arp.inc.php b/includes/discovery/discovery-arp.inc.php index fd5442b062..6894e0cc65 100644 --- a/includes/discovery/discovery-arp.inc.php +++ b/includes/discovery/discovery-arp.inc.php @@ -60,12 +60,12 @@ foreach (dbFetchRows($sql, array($deviceid)) as $entry) { } // Attempt discovery of each IP only once per run. - if (arp_discovery_is_cached($ip)) { + if (object_is_cached('arp_discovery', $ip)) { echo '.'; continue; } - arp_discovery_add_cache($ip); + object_add_cache('arp_discovery', $ip); $name = gethostbyaddr($ip); echo '+'; diff --git a/includes/discovery/functions.inc.php b/includes/discovery/functions.inc.php index a90a65d41e..309998f0f9 100644 --- a/includes/discovery/functions.inc.php +++ b/includes/discovery/functions.inc.php @@ -131,6 +131,11 @@ function discover_device($device, $options=null) { } } + if (is_mib_poller_enabled($device)) { + $devicemib = array($device['sysObjectID'] => 'all'); + register_mibs($device, $devicemib, "includes/discovery/functions.inc.php"); + } + // Set type to a predefined type for the OS if it's not already set if ($device['type'] == 'unknown' || $device['type'] == '') { if ($config['os'][$device['os']]['type']) { @@ -575,7 +580,6 @@ function discover_processor(&$valid, $device, $oid, $index, $type, $descr, $prec 'processor_precision' => $precision, ); dbUpdate($update_data, 'processors', '`device_id`=? AND `processor_index`=? AND `processor_type`=?', array($device['device_id'], $index, $type)); - d_echo($query."\n"); }//end if $valid[$type][$index] = 1; }//end if @@ -630,7 +634,6 @@ function discover_mempool(&$valid, $device, $index, $type, $descr, $precision='1 } dbUpdate($update_data, 'mempools', 'device_id=? AND mempool_index=? AND mempool_type=?', array($device['device_id'], $index, $type)); - d_echo($query."\n"); }//end if $valid[$type][$index] = 1; }//end if @@ -704,25 +707,3 @@ function discover_process_ipv6(&$valid, $ifIndex, $ipv6_address, $ipv6_prefixlen }//end if }//end discover_process_ipv6() - - -// maintain a simple cache of seen IPs during ARP discovery - - -function arp_discovery_add_cache($ip) { - global $arp_discovery; - $arp_discovery[$ip] = true; - -}//end arp_discovery_add_cache() - - -function arp_discovery_is_cached($ip) { - global $arp_discovery; - if (array_key_exists($ip, $arp_discovery)) { - return $arp_discovery[$ip]; - } - else { - return false; - } - -}//end arp_discovery_is_cached() diff --git a/includes/discovery/os/ruckuswireless.inc.php b/includes/discovery/os/ruckuswireless.inc.php index 2321b1300d..dad1284847 100644 --- a/includes/discovery/os/ruckuswireless.inc.php +++ b/includes/discovery/os/ruckuswireless.inc.php @@ -3,6 +3,8 @@ * LibreNMS Ruckus Wireless OS information module * * Copyright (c) 2015 Søren Friis Rosiak + * Copyright (c) 2015 Gear Consulting Pty Ltd + * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your @@ -13,5 +15,13 @@ if (!$os) { if (strstr($sysObjectId, '.1.3.6.1.4.1.25053.3.1')) { $os = 'ruckuswireless'; + + $ruckus_mibs = array( + "ruckusZDSystemStats" => "RUCKUS-ZD-SYSTEM-MIB", + "ruckusZDWLANTable" => "RUCKUS-ZD-WLAN-MIB", + "ruckusZDWLANAPTable" => "RUCKUS-ZD-WLAN-MIB", + "ruckusZDWLANAPRadioStatsTable" => "RUCKUS-ZD-WLAN-MIB", + ); + register_mibs($device, $ruckus_mibs, "includes/discovery/os/ruckuswireless.inc.php"); } } diff --git a/includes/load_db_graph_types.inc.php b/includes/load_db_graph_types.inc.php index b455308a7d..dc7f605859 100644 --- a/includes/load_db_graph_types.inc.php +++ b/includes/load_db_graph_types.inc.php @@ -14,9 +14,14 @@ // load graph types from the database foreach (dbFetchRows('select * from graph_types') as $graph) { - // remove leading 'graph_' from column names foreach ($graph as $k => $v) { - $key = strpos($k, 'graph_') == 0 ? str_replace('graph_', '', $k) : $k; + if (strpos($k, 'graph_') == 0) { + // remove leading 'graph_' from column name + $key = str_replace('graph_', '', $k); + } + else { + $key = $k; + } $g[$key] = $v; } diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index d678e3688f..628ab8ed37 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -412,31 +412,6 @@ function poll_mib_def($device, $mib_name_table, $mib_subdir, $mib_oids, $mib_gra }//end poll_mib_def() -/* - * Please use this instead of creating & updating RRD files manually. - * @param device Device object - only 'hostname' is used at present - * @param name Array of rrdname components - * @param def Array of data definitions - * @param val Array of value definitions - * - */ - - -function rrd_create_update($device, $name, $def, $val, $step=300) { - global $config; - $rrd = rrd_name($device['hostname'], $name); - - if (!is_file($rrd) && $def != null) { - // add the --step and the rra definitions to the array - $newdef = "--step $step ".implode(' ', $def).$config['rrd_rra']; - rrdtool_create($rrd, $newdef); - } - - rrdtool_update($rrd, $val); - -}//end rrd_create_update() - - function get_main_serial($device) { if ($device['os_group'] == 'cisco') { $serial_output = snmp_get_multi($device, 'entPhysicalSerialNum.1 entPhysicalSerialNum.1001', '-OQUs', 'ENTITY-MIB:OLD-CISCO-CHASSIS-MIB'); diff --git a/includes/polling/mib.inc.php b/includes/polling/mib.inc.php index f1137cdbae..70396b9612 100644 --- a/includes/polling/mib.inc.php +++ b/includes/polling/mib.inc.php @@ -12,5 +12,4 @@ * the source code distribution for details. */ -$devicemib = array($device['sysObjectID'] => 'all'); -poll_mibs($devicemib, $device, $graphs); +poll_mibs($device, $graphs); diff --git a/includes/polling/os/ruckuswireless.inc.php b/includes/polling/os/ruckuswireless.inc.php index a83f69b1ec..013fe2aa1f 100644 --- a/includes/polling/os/ruckuswireless.inc.php +++ b/includes/polling/os/ruckuswireless.inc.php @@ -43,10 +43,3 @@ $ruckuscountry = first_oid_match($device, $ruckuscountries); if (isset($ruckuscountry) && $ruckuscountry != '') { $version .= " ($ruckuscountry)"; } - -$ruckus_mibs = array( - 'ruckusZDSystemStats' => 'RUCKUS-ZD-SYSTEM-MIB', - 'ruckusZDWLANTable' => 'RUCKUS-ZD-WLAN-MIB', - 'ruckusZDWLANAPTable' => 'RUCKUS-ZD-WLAN-MIB', -); -poll_mibs($ruckus_mibs, $device, $graphs); diff --git a/includes/rrdtool.inc.php b/includes/rrdtool.inc.php index 9566497441..2c12dac627 100644 --- a/includes/rrdtool.inc.php +++ b/includes/rrdtool.inc.php @@ -22,7 +22,8 @@ */ -function rrdtool_pipe_open(&$rrd_process, &$rrd_pipes) { +function rrdtool_pipe_open(&$rrd_process, &$rrd_pipes) +{ global $config; $command = $config['rrdtool'].' -'; @@ -73,7 +74,8 @@ function rrdtool_pipe_open(&$rrd_process, &$rrd_pipes) { */ -function rrdtool_pipe_close($rrd_process, &$rrd_pipes) { +function rrdtool_pipe_close($rrd_process, &$rrd_pipes) +{ d_echo(stream_get_contents($rrd_pipes[1])); d_echo(stream_get_contents($rrd_pipes[2])); @@ -100,7 +102,8 @@ function rrdtool_pipe_close($rrd_process, &$rrd_pipes) { */ -function rrdtool_graph($graph_file, $options) { +function rrdtool_graph($graph_file, $options) +{ global $config, $debug; rrdtool_pipe_open($rrd_process, $rrd_pipes); @@ -163,7 +166,8 @@ function rrdtool_graph($graph_file, $options) { */ -function rrdtool($command, $filename, $options) { +function rrdtool($command, $filename, $options) +{ global $config, $debug, $rrd_pipes, $console_color; if ($config['rrdcached'] && @@ -209,7 +213,8 @@ function rrdtool($command, $filename, $options) { */ -function rrdtool_create($filename, $options) { +function rrdtool_create($filename, $options) +{ global $config; if( $config['rrdcached'] && $config['rrdtool_version'] >= 1.5 ) { $chk = rrdtool('info', $filename, ''); @@ -230,7 +235,8 @@ function rrdtool_create($filename, $options) { */ -function rrdtool_update($filename, $options) { +function rrdtool_update($filename, $options) +{ $values = array(); // Do some sanitisation on the data if passed as an array. @@ -250,26 +256,25 @@ function rrdtool_update($filename, $options) { else { return 'Bad options passed to rrdtool_update'; } - -} +} // rrdtool_update -function rrdtool_fetch($filename, $options) { +function rrdtool_fetch($filename, $options) +{ return rrdtool('fetch', $filename, $options); - -} +} // rrdtool_fetch -function rrdtool_last($filename, $options) { +function rrdtool_last($filename, $options) +{ return rrdtool('last', $filename, $options); - -} +} // rrdtool_last -function rrdtool_lastupdate($filename, $options){ +function rrdtool_lastupdate($filename, $options) +{ return rrdtool('lastupdate', $filename, $options); - -} +} // rrdtool_lastupdate /** @@ -280,8 +285,6 @@ function rrdtool_lastupdate($filename, $options){ * @param string string to escape * @param integer if passed, string will be padded and trimmed to exactly this length (after rrdtool unescapes it) */ - - function rrdtool_escape($string, $maxlength=null){ $result = shorten_interface_type($string); $result = str_replace("'", '', $result); # remove quotes @@ -296,8 +299,20 @@ function rrdtool_escape($string, $maxlength=null){ $result = str_replace(':', '\:', $result); # escape colons return $result.' '; +} // rrdtool_escape -} + +/* + * @return the name of the rrd file for $host's $extra component + * @param host Host name + * @param extra Components of RRD filename - will be separated with "-" + */ +function rrd_name($host, $extra, $exten = ".rrd") +{ + global $config; + $filename = safename(is_array($extra) ? implode("-", $extra) : $extra); + return implode("/", array($config['rrd_dir'], $host, $filename.$exten)); +} // rrd_name function rrdtool_tune($type, $filename, $max) { $fields = array(); @@ -314,4 +329,51 @@ function rrdtool_tune($type, $filename, $max) { $options = "--maximum " . implode(":$max --maximum ", $fields). ":$max"; rrdtool('tune', $filename, $options); } -} +} // rrdtool_tune + +/* + * Please use this instead of creating & updating RRD files manually. + * @param device Device object - only 'hostname' is used at present + * @param name Array of rrdname components + * @param def Array of data definitions + * @param val Array of value definitions + * + */ +function rrd_create_update($device, $name, $def, $val, $step=300) +{ + global $config; + $rrd = rrd_name($device['hostname'], $name); + + if (!is_file($rrd) && $def != null) { + // add the --step and the rra definitions to the array + $newdef = "--step $step ".implode(' ', $def).$config['rrd_rra']; + rrdtool_create($rrd, $newdef); + } + + rrdtool_update($rrd, $val); +} // rrd_create_update + + +/* + * @return bool indicating existence of RRD file + * @param device Device object as used with rrd_create_update() + * @param name RRD name array as used with rrd_create_update() and rrd_name() + */ +function rrd_file_exists($device, $name) +{ + return is_file(rrd_name($device['hostname'], $name)); +} // rrd_file_exists + + +/* + * @return bool indicating rename success or failure + * @param device Device object as used with rrd_create_update() + * @param oldname RRD name array as used with rrd_create_update() and rrd_name() + * @param newname RRD name array as used with rrd_create_update() and rrd_name() + */ +function rrd_file_rename($device, $oldname, $newname) +{ + $oldrrd = rrd_name($device['hostname'], $oldname); + $newrrd = rrd_name($device['hostname'], $newname); + return rename($oldrrd, $newrrd); +} // rrd_file_rename diff --git a/includes/snmp.inc.php b/includes/snmp.inc.php index f4603e5135..cb83d80683 100644 --- a/includes/snmp.inc.php +++ b/includes/snmp.inc.php @@ -1,4 +1,19 @@ + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. Please see LICENSE.txt at the top level of + * the source code distribution for details. + */ function string_to_oid($string) { $oid = strlen($string); @@ -200,7 +215,7 @@ function snmp_walk($device, $oid, $options=null, $mib=null, $mibdir=null) { function snmpwalk_cache_cip($device, $oid, $array=array(), $mib=0) { - global $config; + global $config, $debug; $timeout = prep_snmp_setting($device, 'timeout'); $retries = prep_snmp_setting($device, 'retries'); @@ -236,7 +251,6 @@ function snmpwalk_cache_cip($device, $oid, $array=array(), $mib=0) { } $data = trim(external_exec($cmd)); - $device_id = $device['device_id']; // echo("Caching: $oid\n"); foreach (explode("\n", $data) as $entry) { @@ -272,7 +286,7 @@ function snmpwalk_cache_cip($device, $oid, $array=array(), $mib=0) { function snmp_cache_ifIndex($device) { // FIXME: this is not yet using our own snmp_* - global $config; + global $config, $debug; $timeout = prep_snmp_setting($device, 'timeout'); $retries = prep_snmp_setting($device, 'retries'); @@ -303,7 +317,6 @@ function snmp_cache_ifIndex($device) { } $data = trim(external_exec($cmd)); - $device_id = $device['device_id']; $array = array(); foreach (explode("\n", $data) as $entry) { @@ -433,7 +446,7 @@ function snmpwalk_cache_triple_oid($device, $oid, $array, $mib=null, $mibdir=nul function snmpwalk_cache_twopart_oid($device, $oid, $array, $mib=0) { - global $config; + global $config, $debug; $timeout = prep_snmp_setting($device, 'timeout'); $retries = prep_snmp_setting($device, 'retries'); @@ -470,7 +483,6 @@ function snmpwalk_cache_twopart_oid($device, $oid, $array, $mib=0) { $data = trim(external_exec($cmd)); - $device_id = $device['device_id']; foreach (explode("\n", $data) as $entry) { list($oid,$value) = explode('=', $entry, 2); $oid = trim($oid); @@ -524,7 +536,6 @@ function snmpwalk_cache_threepart_oid($device, $oid, $array, $mib=0) { $data = trim(external_exec($cmd)); - $device_id = $device['device_id']; foreach (explode("\n", $data) as $entry) { list($oid,$value) = explode('=', $entry, 2); $oid = trim($oid); @@ -547,7 +558,7 @@ function snmpwalk_cache_threepart_oid($device, $oid, $array, $mib=0) { function snmp_cache_slotport_oid($oid, $device, $array, $mib=0) { - global $config; + global $config, $debug; $timeout = prep_snmp_setting($device, 'timeout'); $retries = prep_snmp_setting($device, 'retries'); @@ -583,7 +594,6 @@ function snmp_cache_slotport_oid($oid, $device, $array, $mib=0) { } $data = trim(external_exec($cmd)); - $device_id = $device['device_id']; foreach (explode("\n", $data) as $entry) { $entry = str_replace($oid.'.', '', $entry); @@ -609,7 +619,7 @@ function snmp_cache_oid($oid, $device, $array, $mib=0) { function snmp_cache_port_oids($oids, $port, $device, $array, $mib=0) { - global $config; + global $config, $debug; $timeout = prep_snmp_setting($device, 'timeout'); $retries = prep_snmp_setting($device, 'retries'); @@ -680,7 +690,6 @@ function snmp_cache_portIfIndex($device, $array) { $cmd .= ' '.$device['transport'].':'.$device['hostname'].':'.$device['port'].' portIfIndex'; $output = trim(external_exec($cmd)); - $device_id = $device['device_id']; foreach (explode("\n", $output) as $entry) { $entry = str_replace('CISCO-STACK-MIB::portIfIndex.', '', $entry); @@ -717,7 +726,6 @@ function snmp_cache_portName($device, $array) { $cmd .= ' '.$device['transport'].':'.$device['hostname'].':'.$device['port'].' portName'; $output = trim(external_exec($cmd)); - $device_id = $device['device_id']; // echo("Caching: portName\n"); foreach (explode("\n", $output) as $entry) { $entry = str_replace('portName.', '', $entry); @@ -787,7 +795,7 @@ function snmp_gen_auth(&$device) { /* - * Translate the given MIB into a vaguely useful PHP array. Each keyword becomes an array index. + * Translate the given MIB into a PHP array. Each keyword becomes an array index. * * Example: * snmptranslate -Td -On -M mibs -m RUCKUS-ZD-SYSTEM-MIB RUCKUS-ZD-SYSTEM-MIB::ruckusZDSystemStatsNumSta @@ -801,11 +809,7 @@ function snmp_gen_auth(&$device) { * ::= { iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) ruckusRootMIB(25053) ruckusObjects(1) ruckusZD(2) ruckusZDSystemModule(1) ruckusZDSystemMIB(1) ruckusZDSystemObjects(1) * ruckusZDSystemStats(15) 30 } */ - - function snmp_mib_parse($oid, $mib, $module, $mibdir=null) { - global $debug; - $fulloid = explode('.', $oid); $lastpart = end($fulloid); @@ -827,8 +831,6 @@ function snmp_mib_parse($oid, $mib, $module, $mibdir=null) { // then the name of the object type if ($f[1] && $f[1] == 'OBJECT-TYPE') { $result['object_type'] = $f[0]; - $result['shortname'] = str_replace($mib, '', $f[0]); - $result['dsname'] = name_shorten($f[0], $mib); continue; } @@ -873,8 +875,7 @@ function snmp_mib_parse($oid, $mib, $module, $mibdir=null) { else { return null; } - -}//end snmp_mib_parse() +} // snmp_mib_parse /* @@ -891,7 +892,8 @@ function snmp_mib_parse($oid, $mib, $module, $mibdir=null) { */ -function snmp_mib_walk($mib, $module, $mibdir=null) { +function snmp_mib_walk($mib, $module, $mibdir=null) +{ $cmd = 'snmptranslate -Ts'; $cmd .= mibdir($mibdir); $cmd .= ' -m '.$module; @@ -909,24 +911,73 @@ function snmp_mib_walk($mib, $module, $mibdir=null) { return $result; -}//end snmp_mib_walk() +} // snmp_mib_walk + + +function quote_column($a) +{ + return '`'.$a.'`'; +} // quote_column + + +function join_array($a, $b) +{ + return quote_column($a).'='.$b; +} // join_array /* - * @return an array containing all of the mib objects, keyed by object-type; - * returns an empty array if something goes wrong. + * Update the given table in the database with the given row & column data. + * @param tablename The table to update + * @param columns An array of column names + * @param numkeys The number of columns which are in the primary key of the table; these primary keys must be first in the list of columns + * @param rows Row data to insert, an array of arrays with column names as the second-level keys */ +function update_db_table($tablename, $columns, $numkeys, $rows) +{ + dbBeginTransaction(); + foreach ($rows as $nothing => $obj) { + // create a parameter list based on the columns + $params = array(); + foreach ($columns as $column) { + $params[] = $obj[$column]; + } + $column_placeholders = array_fill(0, count($columns), '?'); + // build the "ON DUPLICATE KEY" part + $non_key_columns = array_slice($columns, $numkeys); + $non_key_placeholders = array_slice($column_placeholders, $numkeys); + $update_definitions = array_map("join_array", $non_key_columns, $non_key_placeholders); + $non_key_params = array_slice($params, $numkeys); -function snmp_mib_load($mib, $module, $mibdir=null) { + $sql = 'INSERT INTO `' . $tablename . '` (' . + implode(',', array_map("quote_column", $columns)) . + ') VALUES (' . implode(',', $column_placeholders) . + ') ON DUPLICATE KEY UPDATE ' . implode(',', $update_definitions); + $result = dbQuery($sql, array_merge($params, $non_key_params)); + d_echo("Result: $result\n"); + } + dbCommitTransaction(); +} // update_db_table + +/* + * Load the given MIB into the database. + * @return count of objects loaded + */ +function snmp_mib_load($mib, $module, $included_by, $mibdir = null) +{ $mibs = array(); foreach (snmp_mib_walk($mib, $module, $mibdir) as $obj) { $mibs[$obj['object_type']] = $obj; + $mibs[$obj['object_type']]['included_by'] = $included_by; } + d_print_r($mibs); + // NOTE: `last_modified` omitted due to being automatically maintained by MySQL + $columns = array('module', 'mib', 'object_type', 'oid', 'syntax', 'description', 'max_access', 'status', 'included_by'); + update_db_table('mibdefs', $columns, 3, $mibs); + return count($mibs); - return $mibs; - -}//end snmp_mib_load() +} // snmp_mib_load /* @@ -936,9 +987,8 @@ function snmp_mib_load($mib, $module, $mibdir=null) { * snmptranslate -m all -M mibs .1.3.6.1.4.1.8072.3.2.10 2>/dev/null * NET-SNMP-TC::linux */ - - -function snmp_translate($oid, $module, $mibdir=null) { +function snmp_translate($oid, $module, $mibdir = null) +{ if ($module !== 'all') { $oid = "$module::$oid"; } @@ -966,16 +1016,15 @@ function snmp_translate($oid, $module, $mibdir=null) { $matches[2], ); -}//end snmp_translate() +} // snmp_translate /* * check if the type of the oid is a numeric type, and if so, * @return the name of RRD type that is best suited to saving it */ - - -function oid_rrd_type($oid, $mibdef) { +function oid_rrd_type($oid, $mibdef) +{ if (!isset($mibdef[$oid])) { return false; } @@ -986,8 +1035,16 @@ function oid_rrd_type($oid, $mibdef) { return false; case 'TimeTicks': - // Need to find a way to flag that this should be parsed - // return 'COUNTER'; + // FIXME + return false; + + case 'INTEGER': + case 'Integer32': + // FIXME + return false; + + case 'Counter32': + // FIXME return false; case 'Counter64': @@ -999,7 +1056,7 @@ function oid_rrd_type($oid, $mibdef) { return false; -}//end oid_rrd_type() +} // oid_rrd_type /* @@ -1008,9 +1065,8 @@ function oid_rrd_type($oid, $mibdef) { * Update the database with graph definitions as needed. * We don't include the index in the graph name - that is handled at display time. */ - - -function tag_graphs($mibname, $oids, $mibdef, &$graphs) { +function tag_graphs($mibname, $oids, $mibdef, &$graphs) +{ foreach ($oids as $index => $array) { foreach ($array as $oid => $val) { $graphname = $mibname.'-'.$mibdef[$oid]['shortname']; @@ -1018,15 +1074,14 @@ function tag_graphs($mibname, $oids, $mibdef, &$graphs) { } } -}//end tag_graphs() +} // tag_graphs /* * Ensure a graph_type definition exists in the database for the entities in this MIB */ - - -function update_mib_graph_types($mibname, $oids, $mibdef, $graphs) { +function update_mib_graph_types($mibname, $oids, $mibdef, $graphs) +{ $seengraphs = array(); // Get the list of graphs currently in the database @@ -1054,35 +1109,57 @@ function update_mib_graph_types($mibname, $oids, $mibdef, $graphs) { dbInsert($graphdef, 'graph_types'); } } - }//end foreach - -}//end update_mib_graph_types() + } +} // update_mib_graph_types /* * Save all of the measurable oids for the device in their own RRDs. + * Save the current value of all the oids in the database. */ - - -function save_mibs($device, $mibname, $oids, $mibdef, &$graphs) { +function save_mibs($device, $mibname, $oids, $mibdef, &$graphs) +{ $usedoids = array(); + $deviceoids = array(); foreach ($oids as $index => $array) { - foreach ($array as $oid => $val) { - $type = oid_rrd_type($oid, $mibdef); + foreach ($array as $obj => $val) { + // build up the device_oid row for saving into the database + $numvalue = preg_match('/^\d+$/', $val) ? $val : null; + $deviceoids[] = array( + 'device_id' => $device['device_id'], + 'oid' => $mibdef[$obj]['oid'].".".$index, + 'module' => $mibdef[$obj]['module'], + 'mib' => $mibdef[$obj]['mib'], + 'object_type' => $obj, + 'value' => $val, + 'numvalue' => $numvalue, + ); + + $type = oid_rrd_type($obj, $mibdef); if ($type === false) { continue; } - $usedoids[$index][$oid] = $val; + $usedoids[$index][$obj] = $val; + + // if there's a file from the previous version of MIB-based polling, rename it + if (rrd_file_exists($device, array($mibname, $mibdef[$obj]['object_type'], $index)) + && !rrd_file_exists($device, array($mibname, $mibdef[$obj]['shortname'], $index))) { + rrd_file_rename($device, + array($mibname, $mibdef[$obj]['object_type'], $index), + array($mibname, $mibdef[$obj]['shortname'], $index)); + // Note: polling proceeds regardless of rename result + } + rrd_create_update( $device, array( $mibname, - $mibdef[$oid]['shortname'], + $mibdef[$obj]['shortname'], $index, ), - array('DS:'.$mibdef[$oid]['dsname'].":$type"), - array($mibdef[$oid]['dsname'] => $val) + array("DS:mibval:$type"), + array("mibval" => $val) ); } } @@ -1090,43 +1167,129 @@ function save_mibs($device, $mibname, $oids, $mibdef, &$graphs) { tag_graphs($mibname, $usedoids, $mibdef, $graphs); update_mib_graph_types($mibname, $usedoids, $mibdef, $graphs); -}//end save_mibs() + // update database + $columns = array('device_id', 'oid', 'module', 'mib', 'object_type', 'value', 'numvalue'); + update_db_table('device_oids', $columns, 2, $deviceoids); +} // save_mibs /* - * Take a list of MIB name => module pairs. - * Validate MIBs and poll based on the results. + * @return an array of MIB objects matching $module, $name, keyed by object_type */ +function load_mibdefs($module, $name) +{ + $params = array($module, $name); + $result = array(); + $object_types = array(); + foreach (dbFetchRows("SELECT * FROM `mibdefs` WHERE `module` = ? AND `mib` = ?", $params) as $row) { + $mib = $row['object_type']; + $object_types[] = $mib; + $result[$mib] = $row; + } + + // add shortname to each element + $prefix = longest_matching_prefix($name, $object_types); + foreach ($result as $mib => $m) { + $result[$mib]['shortname'] = str_replace($prefix, '', $m['object_type']); + } + + d_print_r($result); + return $result; +} // load_mibdefs + +/* + * @return an array of MIB names and modules for $device from the database + */ +function load_device_mibs($device) +{ + $params = array($device['device_id']); + $result = array(); + foreach (dbFetchRows("SELECT `mib`, `module` FROM device_mibs WHERE device_id = ?", $params) as $row) { + $result[$row['mib']] = $row['module']; + } + return $result; +} // load_device_mibs -function poll_mibs($list, $device, &$graphs) { +/* + * @return true if this device should be polled with MIB-based discovery + */ +function is_mib_poller_enabled($device) +{ + if (!is_module_enabled('poller', 'mib')) { + d_echo("MIB polling module disabled globally.\n"); + return false; + } + if (!is_dev_attrib_enabled($device, 'poll_mib')) { d_echo('MIB module disabled for '.$device['hostname']."\n"); + return false; + } + + return true; +} // is_mib_poller_enabled + +/* + * Run MIB-based polling for $device. Update $graphs with the results. + */ +function poll_mibs($device, &$graphs) +{ + if (!is_mib_poller_enabled($device)) { return; } - $mibdefs = array(); - echo 'MIB-based polling:'; + echo 'MIB: polling '; d_echo("\n"); - foreach ($list as $name => $module) { + foreach (load_device_mibs($device) as $name => $module) { + echo "$name "; + d_echo("\n"); + $oids = snmpwalk_cache_oid($device, $name, array(), $module, null, "-OQUsb"); + d_print_r($oids); + save_mibs($device, $name, $oids, load_mibdefs($module, $name), $graphs); + } + echo "\n"; +} // poll_mibs + +/* + * Take a list of MIB name => module pairs. + * Validate MIBs and store the device->mib mapping in the database. + * See includes/discovery/os/ruckuswireless.inc.php for an example of usage. + */ +function register_mibs($device, $mibs, $included_by) +{ + if (!is_mib_poller_enabled($device)) { + return; + } + + echo "MIB: registering\n"; + + foreach ($mibs as $name => $module) { $translated = snmp_translate($name, $module); if ($translated) { - echo " $module::$name"; - d_echo("\n"); - $mod = $translated[0]; - $nam = $translated[1]; - $mibdefs[$nam] = snmp_mib_load($nam, $mod); - $oids = snmpwalk_cache_oid($device, $nam, array(), $mod, null, '-OQUsb'); - d_print_r($oids); - save_mibs($device, $nam, $oids, $mibdefs[$nam], $graphs); + $mod = $translated[0]; + $nam = $translated[1]; + echo " $mod::$nam\n"; + if (snmp_mib_load($nam, $mod, $included_by) > 0) { + // NOTE: `last_modified` omitted due to being automatically maintained by MySQL + $columns = array('device_id', 'module', 'mib', 'included_by'); + $rows = array(); + $rows[] = array( + 'device_id' => $device['device_id'], + 'module' => $mod, + 'mib' => $nam, + 'included_by' => $included_by, + ); + update_db_table('device_mibs', $columns, 3, $rows); + } + else { + echo("MIB: Could not load definition for $mod::$nam\n"); + } } else { - d_echo("MIB: no match for $module::$name\n"); + echo("MIB: Could not find $module::$name\n"); } } - d_echo('Done MIB-based polling'); echo "\n"; - -}//end poll_mibs() +} // register_mibs diff --git a/sql-schema/085.sql b/sql-schema/085.sql new file mode 100644 index 0000000000..6383926070 --- /dev/null +++ b/sql-schema/085.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS `mibdefs` ( `module` varchar(255) NOT NULL, `mib` varchar(255) NOT NULL, `object_type` varchar(255) NOT NULL, `oid` varchar(255) NOT NULL, `syntax` varchar(255) NOT NULL, `description` varchar(255), `max_access` varchar(255), `status` varchar(255), `included_by` varchar(255) NOT NULL, `last_modified` timestamp NOT NULL, PRIMARY KEY (`module`, `mib`, `object_type`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='MIB definitions'; +CREATE TABLE IF NOT EXISTS `device_mibs` ( `device_id` integer(11) NOT NULL, `module` varchar(255) NOT NULL, `mib` varchar(255) NOT NULL, `included_by` varchar(255) NOT NULL, `last_modified` timestamp NOT NULL, PRIMARY KEY (`device_id`, `module`, `mib`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Device to MIB mappings'; +CREATE TABLE IF NOT EXISTS `device_oids` ( `device_id` int(11) NOT NULL, `oid` varchar(255) NOT NULL, `module` varchar(255) NOT NULL, `mib` varchar(255) NOT NULL, `object_type` varchar(255) NOT NULL, `value` varchar(255), `numvalue` bigint, `last_modified` timestamp NOT NULL, PRIMARY KEY (`device_id`, `oid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Per-device MIB data'; +DELETE FROM `device_graphs`; +ALTER TABLE `device_graphs` CHANGE `graph` `graph` VARCHAR(255);