1<?php
2
3/**
4 * Observium
5 *
6 *   This file is part of Observium.
7 *
8 * @package    observium
9 * @subpackage poller
10 * @copyright  (C) 2006-2013 Adam Armstrong, (C) 2013-2019 Observium Limited
11 *
12 */
13
14
15/**
16 * Poll and cache entity _NUMERIC_ Oids,
17 * need for cross cache between different entities, ie status and sensors
18 *
19 * @param $device
20 * @param $entity_type
21 * @param $oid_cache
22 *
23 * @return bool
24 */
25function poll_cache_oids($device, $entity_type, &$oid_cache)
26{
27  global $config;
28
29  $use_walk = FALSE; // Use multi get by default
30  $mib_walk_option = $entity_type . '_walk'; // ie: $config['mibs'][$mib]['sensors_walk']
31  $snmp_flags = OBS_SNMP_ALL_NUMERIC; // Numeric Oids by default
32
33  $translate = entity_type_translate_array($entity_type);
34  $table          = $translate['table'];
35  $mib_field      = $translate['mib_field'];
36  $object_field   = $translate['object_field'];
37  $oid_field      = $translate['oid_field'];
38  $deleted_field  = $translate['deleted_field'];
39  $device_field   = $translate['device_id_field'];
40
41  switch ($entity_type)
42  {
43    case 'sensor':
44    case 'status':
45    case 'counter':
46      // Device not support walk
47      $use_walk = isset($config['os'][$device['os']]['sensors_poller_walk']) &&
48                        $config['os'][$device['os']]['sensors_poller_walk'];
49
50      // For sensors and statuses always use same option
51      $mib_walk_option = 'sensors_walk';
52
53      // Walk query
54      $walk_query = "SELECT DISTINCT `$mib_field`, `$object_field` FROM `$table` WHERE `$device_field` = ? AND `$deleted_field` = ? AND `poller_type` = ?";
55      $walk_query .= " AND `$mib_field` != ? AND `$object_field` != ?";
56      $walk_params = [$device['device_id'], '0', 'snmp', '', ''];
57
58      // Multi-get query
59      $get_query = "SELECT `$oid_field` FROM `$table` WHERE `$device_field` = ? AND `$deleted_field` = ? AND `poller_type` = ? ORDER BY `$oid_field`";
60      $get_params = [$device['device_id'], '0', 'snmp'];
61
62      break;
63
64    default:
65      print_debug("Unknown Entity $entity_type");
66      return FALSE;
67  }
68
69  if ($use_walk)
70  {
71    // Walk by mib & object
72    $oid_to_cache = dbFetchRows($walk_query, $walk_params);
73    print_debug_vars($oid_to_cache);
74    foreach ($oid_to_cache as $entry)
75    {
76      $mib    = $entry[$mib_field];
77      $object = $entry[$object_field];
78
79      // MIB not support walk (by definition)
80      if (isset($config['mibs'][$mib][$mib_walk_option]) &&
81               !$config['mibs'][$mib][$mib_walk_option])
82      {
83        continue;
84      }
85      else if (isset($GLOBALS['cache']['snmp_object_polled'][$mib][$object]))
86      {
87        print_debug("MIB/Object ($mib::$object)already polled.");
88        continue;
89      }
90
91      $oid_cache = snmp_walk_multipart_oid($device, $object, $oid_cache, $mib, NULL, $snmp_flags);
92      $GLOBALS['cache']['snmp_object_polled'][$mib][$object] = 1;
93    }
94  } else {
95    // Multi get for all others
96    $oid_to_cache = dbFetchColumn($get_query, $get_params);
97    usort($oid_to_cache, 'compare_numeric_oids'); // correctly sort numeric oids
98    print_debug_vars($oid_to_cache);
99    $oid_cache = snmp_get_multi_oid($device, $oid_to_cache, $oid_cache, NULL, NULL, $snmp_flags);
100  }
101
102  print_debug_vars($oid_cache);
103
104  return TRUE;
105}
106
107function poll_device($device, $options)
108{
109  global $config, $device, $polled_devices, $db_stats, $exec_status, $alert_rules, $alert_table, $graphs, $attribs;
110
111  $device_start = utime();  // Start counting device poll time
112
113  $alert_metrics = array();
114  $oid_cache = array();
115  $device_state = array();
116  //$old_device_state = unserialize($device['device_state']);
117  $attribs = get_entity_attribs('device', $device['device_id']);
118
119  print_debug_vars($device);
120  print_debug_vars($attribs);
121
122  $pid_info = check_process_run($device); // This just clear stalled DB entries
123  add_process_info($device); // Store process info
124
125  $alert_rules = cache_alert_rules();
126  $alert_table = cache_device_alert_table($device['device_id']);
127
128  print_debug_vars($alert_rules);
129  print_debug_vars($alert_table);
130
131  $status = 0;
132
133  print_cli_heading($device['hostname'] . " [".$device['device_id']."]", 1);
134
135  print_cli_data("OS", $device['os'], 1);
136
137  if ($config['os'][$device['os']]['group'])
138  {
139    $device['os_group'] = $config['os'][$device['os']]['group'];
140    print_cli_data("OS Group", $device['os_group'], 1);
141  }
142
143  if (is_numeric($device['last_polled_timetaken']))
144  {
145    print_cli_data("Last poll duration", $device['last_polled_timetaken']. " seconds", 1);
146  }
147
148  print_cli_data("Last Polled", $device['last_polled'], 1);
149  print_cli_data("SNMP Version", $device['snmp_version'], 1);
150
151  //unset($poll_update); unset($poll_update_query); unset($poll_separator);
152  $update_array = array();
153
154  $host_rrd_dir = $config['rrd_dir'] . "/" . $device['hostname'];
155  if (!is_dir($host_rrd_dir)) { mkdir($host_rrd_dir); echo("Created directory : $host_rrd_dir\n"); }
156
157  $flags = OBS_DNS_ALL;
158  if ($device['snmp_transport'] == 'udp6' || $device['snmp_transport'] == 'tcp6') // Exclude IPv4 if used transport 'udp6' or 'tcp6'
159  {
160    $flags = $flags ^ OBS_DNS_A;
161  }
162  $attribs['ping_skip'] = isset($attribs['ping_skip']) && $attribs['ping_skip'];
163  if ($attribs['ping_skip'])
164  {
165    $flags = $flags | OBS_PING_SKIP; // Add skip ping flag
166  }
167  $device['pingable'] = isPingable($device['hostname'], $flags);
168  if ($device['pingable'])
169  {
170    $device['snmpable'] = isSNMPable($device);
171    if ($device['snmpable'])
172    {
173      $ping_msg = ($attribs['ping_skip'] ? '' : 'PING (' . $device['pingable'] . 'ms) and ');
174
175      print_cli_data("Device status", "Device is reachable by " . $ping_msg . "SNMP (".$device['snmpable']."ms)", 1);
176      $status = "1";
177      $status_type = 'ok';
178    } else {
179      print_cli_data("Device status", "Device is not responding to SNMP requests", 1);
180      $status = "0";
181      $status_type = 'snmp';
182    }
183  } else {
184    print_cli_data("Device status", "Device is not responding to PINGs", 1);
185    $status = "0";
186    print_vars(get_status_var('ping_dns'));
187    if (isset_status_var('ping_dns') && get_status_var('ping_dns') != 'ok')
188    {
189      $status_type = 'dns';
190    } else {
191      $status_type = 'ping';
192    }
193  }
194
195
196  if ($device['status'] != $status)
197  {
198    dbUpdate(array('status' => $status), 'devices', 'device_id = ?', array($device['device_id']));
199    // dbInsert(array('importance' => '0', 'device_id' => $device['device_id'], 'message' => "Device is " .($status == '1' ? 'up' : 'down')), 'alerts');
200
201    $event_msg = 'Device status changed to ';
202    if ($status == '1')
203    {
204      // Device Up, Severity Warning (4)
205      $event_msg .= 'Up';
206      $event_severity = 4;
207    } else {
208      // Device Down, Severity Error (3)!
209      $event_msg .= 'Down';
210      $event_severity = 3;
211    }
212    if ($status_type != 'ok') { $event_msg .= ' (' . $status_type . ')'; }
213    log_event($event_msg, $device, 'device', $device['device_id'], $event_severity);
214  }
215  // Device status type
216  if (isset($device['status_type']) && $device['status_type'] != $status_type)
217  {
218    dbUpdate(array('status_type' => $status_type), 'devices', 'device_id = ?', array($device['device_id']));
219    if ($status == '0' && $device['status_type'] != 'ok')
220    {
221      // Write eventlog entry (only if status Down)
222      log_event('Device status changed to Down ('.$device['status_type'].' -> '.$status_type.')', $device, 'device', $device['device_id'], 3);
223    }
224  }
225
226  rrdtool_update_ng($device, 'status', array('status' => $status));
227
228  if (!$attribs['ping_skip'])
229  {
230    // Ping response RRD database.
231    rrdtool_update_ng($device, 'ping', array('ping' => ($device['pingable'] ? $device['pingable'] : 'U')));
232  }
233
234  // SNMP response RRD database.
235  rrdtool_update_ng($device, 'ping_snmp', array('ping_snmp' => ($device['snmpable'] ? $device['snmpable'] : 'U')));
236
237  $alert_metrics['device_status'] = $status;
238  $alert_metrics['device_status_type'] = $status_type;
239  $alert_metrics['device_ping'] = $device['pingable']; // FIXME, when ping skipped, here always 0.001
240  $alert_metrics['device_snmp'] = $device['snmpable'];
241
242  if ($status == "1")
243  {
244    // Arrays for store and check enabled/disabled graphs
245    $graphs    = array();
246    $graphs_db = array();
247    $graphs_insert = array();
248    $graphs_delete = array();
249    foreach (dbFetchRows("SELECT * FROM `device_graphs` WHERE `device_id` = ?", array($device['device_id'])) as $entry)
250    {
251      // Not know how empty was here
252      if (empty($entry['graph']))
253      {
254        $graphs_delete[] = $entry['device_graph_id'];
255      }
256
257      $graphs_db[$entry['graph']] = $entry;
258    }
259
260    $graphs['availability'] = TRUE; // Everything has this!
261
262    if (!$attribs['ping_skip'])
263    {
264      // Enable Ping graphs
265      $graphs['ping'] = TRUE;
266    }
267
268    // Enable SNMP graphs
269    $graphs['ping_snmp'] = TRUE;
270
271    // Run these base modules always and before all other modules!
272    $poll_modules = array('system', 'os');
273
274    if(isset($options['m']) && $options['m'] == 'none')
275    {
276      unset($poll_modules);
277    }
278
279    $mods_disabled_global = array();
280    $mods_disabled_device = array();
281    $mods_excluded        = array();
282
283    if ($options['m'])
284    {
285      foreach (explode(',', $options['m']) as $module)
286      {
287        $module = trim($module);
288        if (in_array($module, $poll_modules)) { continue; } // Skip already added modules
289        if ($module == 'unix-agent')
290        {
291          array_unshift($poll_modules, $module);            // Add 'unix-agent' before all
292          continue;
293        }
294        if (is_file($config['install_dir'] . "/includes/polling/$module.inc.php"))
295        {
296          $poll_modules[] = $module;
297        }
298      }
299    } else {
300      foreach ($config['poller_modules'] as $module => $module_status)
301      {
302        if (in_array($module, $poll_modules)) { continue; } // Skip already added modules
303        if ($attribs['poll_'.$module] || ($module_status && !isset($attribs['poll_'.$module])))
304        {
305          if (poller_module_excluded($device, $module))
306          {
307            $mods_excluded[] = $module;
308            //print_warning("Module [ $module ] excluded for device.");
309            continue;
310          }
311          if ($module == 'unix-agent')
312          {
313            array_unshift($poll_modules, $module);          // Add 'unix-agent' before all
314            continue;
315          }
316          if (is_file($config['install_dir'] . "/includes/polling/$module.inc.php"))
317          {
318            $poll_modules[] = $module;
319          }
320        }
321        elseif (isset($attribs['poll_'.$module]) && !$attribs['poll_'.$module])
322        {
323          $mods_disabled_device[] = $module;
324          //print_warning("Module [ $module ] disabled on device.");
325        } else {
326          $mods_disabled_global[] = $module;
327          //print_warning("Module [ $module ] disabled globally.");
328        }
329      }
330
331    }
332
333    if (count($mods_excluded)) { print_cli_data("Modules Excluded", implode(", ", $mods_excluded), 1); }
334    if (count($mods_disabled_global)) { print_cli_data("Disabled Globally", implode(", ", $mods_disabled_global), 1); }
335    if (count($mods_disabled_device)) { print_cli_data("Disabled Device", implode(", ", $mods_disabled_global), 1); }
336    if (count($poll_modules)) { print_cli_data("Modules Enabled", implode(", ", $poll_modules), 1); }
337
338    echo(PHP_EOL);
339
340    foreach ($poll_modules as $module)
341    {
342      print_debug(PHP_EOL . "including: includes/polling/$module.inc.php");
343
344      print_cli_heading("Module Start: %R".$module."");
345
346      $m_start = utime();
347
348      include($config['install_dir'] . "/includes/polling/$module.inc.php");
349
350      $m_end   = utime();
351
352      $m_run   = round($m_end - $m_start, 4);
353      $device_state['poller_mod_perf'][$module] = $m_run;
354      print_cli_data("Module time", number_format($m_run, 4)."s");
355
356      if (!isset($options['m']))
357      {
358        rrdtool_update_ng($device, 'perf-pollermodule', array('val' => $m_run), $module);
359      }
360
361      echo(PHP_EOL);
362
363    }
364
365    print_cli_heading($device['hostname']. " [" . $device['device_id'] . "] completed poller modules at " . date("Y-m-d H:i:s"), 1);
366
367    // Check and update graphs DB
368    $graphs_stat = array();
369
370    if (!isset($options['m']))
371    {
372      // Hardcoded poller performance
373      $graphs['poller_perf'] = TRUE;
374      $graphs['pollersnmp_count']    = TRUE;
375      $graphs['pollersnmp_times']    = TRUE;
376      $graphs['pollersnmp_errors_count'] = TRUE;
377      $graphs['pollersnmp_errors_times'] = TRUE;
378      $graphs['pollerdb_count']    = TRUE;
379      $graphs['pollerdb_times']    = TRUE;
380      $graphs['pollermemory_perf'] = TRUE;
381
382      // Delete not exists graphs from DB (only if poller run without modules option)
383      foreach ($graphs_db as $graph => $entry)
384      {
385        if (!isset($graphs[$graph]))
386        {
387          //dbDelete('device_graphs', "`device_id` = ? AND `graph` = ?", array($device['device_id'], $graph));
388          $graphs_delete[] = $entry['device_graph_id'];
389          unset($graphs_db[$graph]);
390          $graphs_stat['deleted'][] = $graph;
391        }
392      }
393    }
394
395    // Add or update graphs in DB
396    foreach ($graphs as $graph => $value)
397    {
398      if (!$graph) { continue; } // Not know how here can empty
399
400      if (!isset($graphs_db[$graph]))
401      {
402        //dbInsert(array('device_id' => $device['device_id'], 'graph' => $graph, 'enabled' => $value), 'device_graphs');
403        $graphs_insert[] = array('device_id' => $device['device_id'], 'graph' => $graph, 'enabled' => $value);
404        $graphs_stat['added'][] = $graph;
405      }
406      else if ($value != $graphs_db[$graph]['enabled'])
407      {
408        dbUpdate(array('enabled' => $value), 'device_graphs', '`device_graph_id` = ?', array($device['device_id'], $graph));
409        $graphs_stat['updated'][] = $graph;
410      } else {
411        $graphs_stat['checked'][] = $graph;
412      }
413    }
414    if (count($graphs_insert))
415    {
416      dbInsertMulti($graphs_insert, 'device_graphs');
417    }
418    if (count($graphs_delete))
419    {
420      dbDelete('device_graphs', generate_query_values($graphs_delete, 'device_graph_id', NULL, FALSE));
421    }
422
423    // Print graphs stats
424    foreach ($graphs_stat as $key => $stat)
425    {
426      if (count($stat)) { print_cli_data('Graphs ['.$key.']', implode(', ', $stat), 1); }
427    }
428
429    $device_end  = utime();
430    $device_run  = $device_end - $device_start;
431    $device_time = round($device_run, 4);
432
433    $update_array['last_polled'] = array('NOW()');
434    $update_array['last_polled_timetaken'] = $device_time;
435
436    #echo("$device_end - $device_start; $device_time $device_run");
437
438    print_cli_data("Poller time", $device_time." seconds", 1);
439    //print_message(PHP_EOL."Polled in $device_time seconds");
440
441    // Store device stats and history data (only) if we're not doing a single-module poll
442    if (!$options['m'])
443    {
444
445      // Fetch previous device state (do not use $device array here, for exclude update history collisions)
446      $old_device_state = dbFetchCell('SELECT `device_state` FROM `devices` WHERE `device_id` = ?;', array($device['device_id']));
447      $old_device_state = unserialize($old_device_state);
448
449      // Add first entry
450      $poller_history = array(intval($device_start) => $device_time); // start => duration
451      // Add and keep not more than 288 (24 hours with 5min interval) last entries
452      if (isset($old_device_state['poller_history']))
453      {
454        print_debug_vars($old_device_state['poller_history']);
455        $poller_history = array_slice($poller_history + $old_device_state['poller_history'], 0, 288, TRUE);
456      }
457      print_debug_vars($poller_history);
458
459      $device_state['poller_history'] = $poller_history;
460
461      // Keep discovery history and perf too
462      if (isset($old_device_state['discovery_history']))
463      {
464        $device_state['discovery_history'] = $old_device_state['discovery_history'];
465      }
466      if (isset($old_device_state['discovery_mod_perf']))
467      {
468        $device_state['discovery_mod_perf'] = $old_device_state['discovery_mod_perf'];
469      }
470      unset($poller_history, $old_device_state);
471
472      $update_array['device_state'] = serialize($device_state);
473
474      // Also store history in graph
475      rrdtool_update_ng($device, 'perf-poller', array('val' => $device_time));
476    }
477
478    if (OBS_DEBUG)
479    {
480      echo("Updating " . $device['hostname'] . " - ");
481      print_vars($update_array);
482      echo(" \n");
483    }
484
485    $updated = dbUpdate($update_array, 'devices', '`device_id` = ?', array($device['device_id']));
486
487    if ($updated) {
488      print_cli_data("Updated Data", implode(", ", array_keys($update_array)), 1);
489    }
490
491    $alert_metrics['device_la']            = $device_state['la']['5min']; // 5 min as common LA
492    $alert_metrics['device_la_1min']       = $device_state['la']['1min'];
493    $alert_metrics['device_la_5min']       = $device_state['la']['5min'];
494    $alert_metrics['device_la_15min']      = $device_state['la']['15min'];
495
496    $alert_metrics['device_uptime']        = $device['uptime'];
497    $alert_metrics['device_rebooted']      = $rebooted; // 0 - not rebooted, 1 - rebooted
498    $alert_metrics['device_duration_poll'] = $device['last_polled_timetaken'];
499
500    unset($cache_storage); // Clear cache of hrStorage ** MAYBE FIXME? ** (ok, later)
501    unset($cache); // Clear cache (unify all things here?)
502
503  } else if (!$options['m']) {
504    // State is 0, also collect poller time for down devices, since it not zero!
505
506    $device_end  = utime();
507    $device_run  = $device_end - $device_start;
508    $device_time = round($device_run, 4);
509
510    print_cli_data("Poller time", $device_time." seconds", 1);
511    // Also store history in graph
512    rrdtool_update_ng($device, 'perf-poller', array('val' => $device_time));
513  }
514
515  check_entity('device', $device, $alert_metrics);
516
517  echo(PHP_EOL);
518
519  // Clean
520  del_process_info($device); // Remove process info
521  unset($alert_metrics);
522}
523
524///FIXME. It's not a very nice solution, but will approach as temporal.
525// Function return FALSE, if poller module allowed for device os (otherwise TRUE).
526function poller_module_excluded($device, $module)
527{
528  global $config;
529
530  ///FIXME. rename module: 'wmi' -> 'windows-wmi'
531  if ($module == 'wmi'  && $device['os'] != 'windows') { return TRUE; }
532
533  if ($module == 'ipmi' &&
534      (!isset($config['os'][$device['os']]['ipmi']) || $config['os'][$device['os']]['ipmi'] == FALSE)) { return TRUE; }
535  if ($module == 'unix-agent' && !($device['os_group'] == 'unix' || $device['os'] == 'generic')) { return TRUE; }
536
537  if (isset($config['os'][$device['os']]['poller_blacklist']))
538  {
539    if (in_array($module, $config['os'][$device['os']]['poller_blacklist']))
540    {
541      return TRUE;
542    }
543  }
544
545  $os_test = explode('-', $module, 2);
546  if (count($os_test) === 1) { return FALSE; } // Check modules only with a dash.
547  list($os_test) = $os_test;
548
549  ///FIXME. rename module: 'cipsec-tunnels' -> 'cisco-ipsec-tunnels'
550  if (($os_test == 'cisco' || $os_test == 'cipsec') && $device['os_group'] != 'cisco') { return TRUE; }
551  //$os_groups = array('cisco', 'unix');
552  //foreach ($os_groups as $os_group)
553  //{
554  //  if ($os_test == $os_group && $device['os_group'] != $os_group) { return TRUE; }
555  //}
556
557  $oses = array('junose', 'arista_eos', 'netscaler', 'arubaos');
558  foreach ($oses as $os)
559  {
560    if (strpos($os, $os_test) !== FALSE && $device['os'] != $os) { return TRUE; }
561  }
562
563  return FALSE;
564}
565
566/**
567 * Poll a table or oids from SNMP and build an RRD based on an array of arguments.
568 *
569 * Current limitations:
570 *  - single MIB and RRD file for all graphs
571 *  - single table per MIB
572 *  - if set definition 'call_function', than poll used specific function for snmp walk/get,
573 *    else by default used snmpwalk_cache_oid()
574 *  - allowed oids only with simple numeric index (oid.0, oid.33), NOT allowed (oid.1.2.23)
575 *  - only numeric data
576 *
577 * Example of (full) args array:
578 *  array(
579 *   'file'          => 'someTable.rrd',              // [MANDATORY] RRD filename, but if not set used MIB_table.rrd as filename
580 *   'call_function' => 'snmpwalk_cache_oid'          // [OPTIONAL] Which function to use for snmp poll, bu default snmpwalk_cache_oid()
581 *   'mib'           => 'SOMETHING-MIB',              // [OPTIONAL] MIB or list of MIBs separated by a colon
582 *   'mib_dir'       => 'something',                  // [OPTIONAL] OS MIB directory or array of directories
583 *   'graphs'        => array('one','two'),           // [OPTIONAL] List of graph_types that this table provides
584 *   'table'         => 'someTable',                  // [RECOMENDED] Table name for OIDs
585 *   'numeric'       => '.1.3.6.1.4.1.555.4.1.1.48',  // [OPTIONAL] Numeric table OID
586 *   'index'         => '1',                          // [OPTIONAL] Force an OID index for the entire table. If not set, equals '0'
587 *   'ds_rename'     => array('http' => ''),          // [OPTIONAL] Array for renaming OIDs to DSes
588 *   'oids'          => array(                        // List of OIDs you can use as key: full OID name
589 *     'someOid' => array(                                 // OID name (You can use OID name, like 'cpvIKECurrSAs')
590 *       'descr'     => 'Current IKE SAs',                 // [OPTIONAL] Description of the OID contents
591 *       'numeric'   => '.1.3.6.1.4.1.555.4.1.1.48.45',    // [OPTIONAL] Numeric OID
592 *       'index'     => '0',                               // [OPTIONAL] OID index, if not set equals '0'
593 *       'ds_name'   => 'IKECurrSAs',                      // [OPTIONAL] DS name, if not set used OID name truncated to 19 chars
594 *       'ds_type'   => 'GAUGE',                           // [OPTIONAL] DS type, if not set equals 'COUNTER'
595 *       'ds_min'    => '0',                               // [OPTIONAL] Min value for DS, if not set equals 'U'
596 *       'ds_max'    => '30000'                            // [OPTIONAL] Max value for DS, if not set equals '100000000000'
597 *    )
598 *  )
599 *
600 */
601function collect_table($device, $oids_def, &$graphs)
602{
603  $rrd      = array();
604  $mib      = NULL;
605  $mib_dirs = NULL;
606  $use_walk = isset($oids_def['table']) && $oids_def['table']; // Use snmpwalk by default
607  $call_function = strtolower($oids_def['call_function']);
608  switch ($call_function)
609  {
610    case 'snmp_get':
611    case 'snmp_get_multi':
612      $use_walk = FALSE;
613      break;
614    case 'snmpwalk_cache_bare_oid':
615      break;
616    case 'snmpwalk_cache_oid':
617    default:
618      $call_function = 'snmpwalk_cache_oid';
619      if (!$use_walk)
620      {
621        // Break because we should use snmpwalk, but walking table not set
622        return FALSE;
623      }
624  }
625  if (isset($oids_def['numeric'])) { $oids_def['numeric'] = '.'.trim($oids_def['numeric'], '. '); } // Remove trailing dot
626  if (isset($oids_def['mib']))     { $mib      = $oids_def['mib']; }
627  if (isset($oids_def['mib_dir'])) { $mib_dirs = mib_dirs($oids_def['mib_dir']); }
628  if (isset($oids_def['file']))
629  {
630    $rrd_file = $oids_def['file'];
631  }
632  elseif ($mib && isset($oids_def['table']))
633  {
634    // Try to use MIB & tableName as rrd_file
635    $rrd_file = strtolower(safename($mib.'_'.$oids_def['table'])).'.rrd';
636  } else {
637    print_debug("  WARNING, not have rrd filename.");
638    return FALSE; // Not have RRD filename
639  }
640
641  // Get MIBS/Tables/OIDs permissions
642  if ($use_walk)
643  {
644    // if use table walk, than check only this table disabled (not oids)
645    $disabled_tables = get_device_objects_disabled($device, $mib);
646    if (in_array($oids_def['table'], $disabled_tables))
647    {
648      print_debug("  WARNING, table '".$oids_def['table']."' for '$mib' disabled and skipped.");
649      return FALSE; // table disabled, exit
650    }
651  } else {
652    // if use multi_get, than check all oids disabled
653    $disabled_oids = get_device_objects_disabled($device, $mib);
654    $oids_ok = array_diff(array_keys($oids_def['oids']), $disabled_oids);
655    if (count($oids_ok) == 0)
656    {
657      print_debug("  WARNING, oids '".implode("', '", array_keys($oids_def['oids']))."' for '$mib' disabled and skipped.");
658      return FALSE;  // All oids disabled, exit
659    }
660  }
661
662  $search  = array();
663  $replace = array();
664  if (is_array($oids_def['ds_rename']))
665  {
666    foreach ($oids_def['ds_rename'] as $s => $r)
667    {
668      $search[]  = $s;
669      $replace[] = $r;
670    }
671  }
672
673  // rrd DS limit is 20 bytes (19 chars + NULL terminator)
674  $ds_len = 19;
675
676  $oids       = array();
677  $oids_index = array();
678  foreach ($oids_def['oids'] as $oid => $entry)
679  {
680    if (is_numeric($entry['numeric']) && isset($oids_def['numeric']))
681    {
682      $entry['numeric'] = $oids_def['numeric'] . '.' . $entry['numeric']; // Numeric oid, for future using
683    }
684    if (!isset($entry['index']) && isset($oids_def['index']))
685    {
686      $entry['index'] = $oids_def['index'];
687    }
688    elseif (!isset($entry['index']))
689    {
690      $entry['index'] = '0';
691    }
692    if (!isset($entry['ds_type'])) { $entry['ds_type'] = 'COUNTER'; }
693    if (!isset($entry['ds_min']))  { $entry['ds_min']  = 'U'; }
694    if (!isset($entry['ds_max']))  { $entry['ds_max']  = '100000000000'; }
695    if (!isset($entry['ds_name']))
696    {
697      // Convert OID name to DS name
698      $ds_name = $oid;
699      if (is_array($oids_def['ds_rename'])) { $ds_name = str_replace($search, $replace, $ds_name); }
700    } else {
701      $ds_name = $entry['ds_name'];
702    }
703    if (strlen($ds_name) > $ds_len) { $ds_name = truncate($ds_name, $ds_len, ''); }
704
705    if (isset($oids_def['no_index']) && $oids_def['no_index'] == TRUE)
706    {
707      $oids[]       = $oid;
708    } else {
709      $oids[]       = $oid.'.'.$entry['index'];
710    }
711    $oids_index[] = array('index' => $entry['index'], 'oid' => $oid);
712
713    $rrd['rrd_create'][] = ' DS:'.$ds_name.':'.$entry['ds_type'].':600:'.$entry['ds_min'].':'.$entry['ds_max'];
714    if (OBS_DEBUG) { $rrd['ds_list'][] = $ds_name; } // Make DS lists for compare with RRD file in debug
715  }
716
717  switch ($call_function)
718  {
719    case 'snmpwalk_cache_oid':
720      $data = snmpwalk_cache_oid($device, $oids_def['table'], array(), $mib, $mib_dirs);
721      break;
722    case 'snmpwalk_cache_bare_oid':
723      $data = snmpwalk_cache_bare_oid($device, $oids_def['table'], array(), $mib, $mib_dirs);
724      break;
725    case 'snmp_get':
726    case 'snmp_get_multi':
727    case 'snmp_get_multi_oid':
728      $data = snmp_get_multi_oid($device, $oids, array(), $mib, $mib_dirs);
729      break;
730  }
731  if (!snmp_status())
732  {
733    // Break because latest snmp walk/get return not good exitstatus (wrong mib/timeout/error/etc)
734    print_debug("  WARNING, latest snmp walk/get return not good exitstatus for '$mib', RRD update skipped.");
735    return FALSE;
736  }
737
738  //print_debug_vars($data);
739
740  if (isset($oids_def['no_index']) && $oids_def['no_index'] == TRUE || $call_function == 'snmpwalk_cache_double_oid')
741  {
742    $data[0] = $data[''];
743  }
744  elseif ( $call_function == 'snmpwalk_cache_bare_oid')
745  {
746    $data[0] = $data;
747  }
748
749  print_debug_vars($data);
750
751  foreach ($oids_index as $entry)
752  {
753    $index = $entry['index'];
754    $oid   = $entry['oid'];
755
756    if (is_numeric($data[$index][$oid]))
757    {
758      // The original OID definition from the table.
759      $def = $oids_def['oids'][$oid];
760
761      // Apply multiplier value from the entry
762      if (isset($def['multiplier']) && $def['multiplier'] != 0)
763      {
764        $data[$index][$oid] = scale_value($data[$index][$oid], $def['multiplier']);
765      }
766
767      $rrd['ok']           = TRUE; // We have any data for current rrd_file
768      $rrd['rrd_update'][] = $data[$index][$oid];
769    } else {
770      $rrd['rrd_update'][] = 'U';
771    }
772  }
773
774  // Ok, all previous checks done, update RRD, table/oids permissions, $graphs
775  if (isset($rrd['ok']) && $rrd['ok'])
776  {
777    // Create/update RRD file
778    $rrd_create = implode('', $rrd['rrd_create']);
779    $rrd_update = 'N:'.implode(':', $rrd['rrd_update']);
780    rrdtool_create($device, $rrd_file, $rrd_create);
781    rrdtool_update($device, $rrd_file, $rrd_update);
782
783    foreach ($oids_def['graphs'] as $graph)
784    {
785      $graphs[$graph] = TRUE; // Set all graphs to TRUE
786    }
787
788    // Compare DSes form RRD file with DSes from array
789    if (OBS_DEBUG)
790    {
791      $graph_template  = "\$config['graph_types']['device']['GRAPH_CHANGE_ME'] = array(\n";
792      $graph_template .= "  'file'      => '$rrd_file',\n";
793      $graph_template .= "  'ds'        => array(\n";
794      $rrd_file_info = rrdtool_file_info(get_rrd_path($device, $rrd_file));
795      foreach ($rrd_file_info['DS'] as $ds => $nothing)
796      {
797        $ds_list[] = $ds;
798        $graph_template .= "    '$ds' => array('label' => '$ds'),\n";
799      }
800      $graph_template .= "  )\n);";
801      $in_args = array_diff($rrd['ds_list'], $ds_list);
802      if ($in_args)
803      {
804        print_message("%rWARNING%n, in file '%W".$rrd_file_info['filename']."%n' different DS lists. NOT have: ".implode(', ', $in_args));
805      }
806      $in_file = array_diff($ds_list, $rrd['ds_list']);
807      if ($in_file)
808      {
809        print_message("%rWARNING%n, in file '%W".$rrd_file_info['filename']."%n' different DS lists. Excess: ".implode(', ', $in_file));
810      }
811
812      // Print example for graph template using rrd_file and ds list
813      print_message($graph_template);
814    }
815  }
816  else if ($use_walk)
817  {
818    // Table NOT exist on device!
819    // Disable polling table (only if table not enabled manually in DB)
820
821    // This code just disables collection forever after the first failed query!
822
823    /*
824    if (!dbFetchCell("SELECT COUNT(*) FROM `devices_mibs` WHERE `device_id` = ? AND `mib` = ?
825                     AND `table_name` = ? AND (`oid` = '' OR `oid` IS NULL)", array($device['device_id'], $mib, $oids_def['table'])))
826    {
827      dbInsert(array('device_id' => $device['device_id'], 'mib' => $mib,
828                     'table_name' => $oids_def['table'], 'disabled' => '1'), 'devices_mibs');
829    }
830    print_debug("  WARNING, table '".$oids_def['table']."' for '$mib' disabled.");
831    */
832  } else {
833    // OIDs NOT exist on device!
834    // Disable polling oids (only if table not enabled manually in DB)
835    /*
836    foreach (array_keys($oids_def['oids']) as $oid)
837    {
838      if (!dbFetchCell("SELECT COUNT(*) FROM `devices_mibs` WHERE `device_id` = ? AND `mib` = ?
839                       AND `oid` = ?", array($device['device_id'], $mib, $oid)))
840      {
841        dbInsert(array('device_id' => $device['device_id'], 'mib' => $mib,
842                       'oid' => $oid, 'disabled' => '1'), 'devices_mibs');
843      }
844    }
845    print_debug("  WARNING, oids '".implode("', '", array_keys($oids_def['oids']))."' for '$mib' disabled.");
846    */
847  }
848
849  // Return obtained snmp data
850  return $data;
851}
852
853function poll_p2p_radio($device, $mib, $index, $radio)
854{
855  $params  = array('radio_tx_freq', 'radio_rx_freq', 'radio_tx_power', 'radio_rx_level', 'radio_name', 'radio_bandwidth', 'radio_modulation', 'radio_total_capacity', 'radio_standard', 'radio_loopback', 'radio_tx_mute', 'radio_eth_capacity', 'radio_e1t1_channels', 'radio_cur_capacity');
856
857  if (is_array($GLOBALS['cache']['p2p_radios'][$mib][$index])) { $radio_db = $GLOBALS['cache']['p2p_radios'][$mib][$index]; }
858
859  // Update the Database
860
861  if (!isset($radio_db['radio_id']))  // If we don't have an entry already, create it
862  {
863    $insert = array();
864    $insert['device_id'] = $device['device_id'];
865    $insert['radio_mib'] = $mib;
866    $insert['radio_index'] = $index;
867
868    foreach ($params as $param)
869    {
870      $insert[$param] = $radio[$param];
871      if ($radio[$param] == NULL) { $insert[$param] = array('NULL'); }
872    }
873
874    $radio_id = dbInsert($insert, 'p2p_radios');
875    echo("+");
876
877  } else {  // If we already have an entry, check if it needs updating
878
879    $update = array();
880    foreach ($params as $param)
881    {
882      if ($radio[$param] != $radio_db[$param]) { $update[$param] = $radio[$param]; }
883    }
884    if (count($update)) // If there have been changes, update it
885    {
886      dbUpdate($update, 'p2p_radios', '`radio_id` = ?', array($radio_db['radio_id']));
887      echo('U');
888    } else {
889      echo('.');
890    }
891  }
892
893  rrdtool_update_ng($device, 'p2p_radio', array(
894    'tx_power'     => $radio['radio_tx_power'],
895    'rx_level'     => $radio['radio_rx_level'],
896    'rmse'         => $radio['radio_rmse'],
897    'agc_gain'     => $radio['radio_agc_gain'],
898    'cur_capacity' => $radio['radio_cur_capacity'],
899    'sym_rate_tx'  => $radio['radio_sym_rate_tx'],
900    'sym_rate_rx'  => $radio['radio_sym_rate_tx'],
901  ), "$mib-$index");
902
903  $GLOBALS['valid']['p2p_radio'][$mib][$index] = 1; // FIXME. What? How it passed there?
904}
905
906function update_application($app_id, $app_data)
907{
908
909  $update_array = array('app_json' => json_encode($app_data), 'app_lastpolled' => time());
910
911  dbUpdate($update_array, 'applications', '`app_id` = ?', array($app_id));
912
913}
914
915// EOF
916