Observium_CE/discovery.php

306 lines
11 KiB
PHP
Executable File

#!/usr/bin/env php
<?php
/**
* Observium
*
* This file is part of Observium.
*
* @package observium
* @subpackage discovery
* @copyright (C) 2006-2013 Adam Armstrong, (C) 2013-2022 Observium Limited
*
*/
chdir(dirname($argv[0]));
// Get options before definitions!
$options = getopt("h:i:m:n:p:U:dquaMV");
include("includes/sql-config.inc.php");
include("includes/discovery/functions.inc.php");
$cli = TRUE;
//if (is_cron()) { $options['q'] = TRUE; } // Set quiet for cron
$start = utime();
$runtime_stats = array();
if (isset($options['V'])) {
print_message(OBSERVIUM_PRODUCT . " " . OBSERVIUM_VERSION);
if (is_array($options['V'])) { print_versions(); }
exit;
}
if (isset($options['M'])) {
print_message(OBSERVIUM_PRODUCT . " " . OBSERVIUM_VERSION);
print_message('Enabled discovery modules:');
$m_disabled = array();
foreach ($config['discovery_modules'] as $module => $ok) {
if ($ok) {
print_message(' ' . $module);
} else {
$m_disabled[] = $module;
}
}
if (count($m_disabled)) {
print_message('Disabled discovery modules:');
print_message(' ' . implode("\n ", $m_disabled));
}
exit;
}
if (!isset($options['q'])) {
print_cli_banner();
if (OBS_DEBUG) { print_versions(); }
// Warning about obsolete configs.
if (print_obsolete_config()) { echo PHP_EOL; }
}
if (isset($options['u']) || isset($options['U']) ||
(isset($options['h']) && in_array($options['h'], [ 'all', 'odd', 'even', 'none' ]))) {
$options['u'] = TRUE;
include($config['install_dir'] . '/includes/update/update.php');
} elseif (!isset($options['q'])) {
// Warn about need DB schema update
$db_version = get_db_version();
$db_version = sprintf("%03d", $db_version + 1);
if (is_file($config['install_dir'] . "/update/$db_version.sql") || is_file($config['install_dir'] . "/update/$db_version.php")) {
print_warning("Your database schema is old and needs updating. Run from console:\n " . $config['install_dir'] . "/discovery.php -u");
}
unset($db_version);
}
$where = '';
if (isset($options['h'])) {
$params = array();
switch ($options['h']) {
case 'odd':
$options['n'] = 1;
$options['i'] = 2;
break;
case 'even':
$options['n'] = 0;
$options['i'] = 2;
break;
case 'all':
$where = ' ';
$doing = 'all';
break;
case 'new':
$where = ' AND (`last_discovered` IS NULL OR `last_discovered` = ? OR `force_discovery` = ?)';
$params[] = '0000-00-00 00:00:00';
$params[] = 1;
$doing = 'new';
// add new devices on remote poller from actions queue
if (OBS_DISTRIBUTED && function_exists('run_action_queue')) {
run_action_queue('device_add');
//run_action_queue('device_rename');
//run_action_queue('device_delete');
// Update alert and group tables
run_action_queue('tables_update');
}
break;
case 'none':
//$options['u'] = TRUE;
break;
default:
$doing = $options['h'];
if (is_numeric($options['h'])) {
$where = ' AND `device_id` = ?';
$params[] = $options['h'];
} else {
$where = ' AND `hostname` LIKE ?';
$params[] = str_replace('*', '%', $options['h']);
}
}
}
if (isset($options['i'], $options['n']) && $options['i']) {
$where .= ' AND MOD(device_id,' . $options['i'] . ') = ?';
$params[] = $options['n'];
$doing = $options['n'] . '/' . $options['i'];
}
if (!$where && !$options['u'] && !isset($options['a'])) {
print_message("%n
USAGE:
$scriptname [-dquV] [-i instances] [-n number] [-m module] [-h device]
EXAMPLE:
-h <device id> | <device hostname wildcard> Discover single device
-h odd Discover odd numbered devices (same as -i 2 -n 0)
-h even Discover even numbered devices (same as -i 2 -n 1)
-h all Discover all devices
-h new Discover all devices that have not had a discovery run before
-i <instances> -n <number> Discover as instance <number> of <instances>
Instances start at 0. 0-3 for -n 4
OPTIONS:
-h Device hostname, id or key odd/even/all/new.
-i Discovery instance.
-n Discovery number.
-q Quiet output.
-a Force update Groups/Alerts table
-u Upgrade DB schema
-M Show globally enabled/disabled modules and exit.
-V Show version and exit.
DEBUGGING OPTIONS:
-d Enable debugging output.
-dd More verbose debugging output.
-m Specify modules (separated by commas) to be run.
%rInvalid arguments!%n", 'color', FALSE);
}
if ($config['version_check'] && ($options['h'] !== 'new' || $options['u'])) {
include($config['install_dir'] . '/includes/versioncheck.inc.php');
}
if (!$where) {
// Only update Group/Alert tables
if (isset($options['a'])) {
if (OBS_DISTRIBUTED && function_exists('run_action_queue')) {
//run_action_queue('device_add');
//run_action_queue('device_rename');
//run_action_queue('device_delete');
// Update alert and group tables
run_action_queue('tables_update');
} else {
$silent = isset($options['q']);
if (function_exists('update_group_tables')) { update_group_tables($silent); } // Not exist in CE
if (function_exists('update_alert_tables')) { update_alert_tables($silent); }
}
}
exit;
}
// For not new devices discovery, skip down devices
if ($options['h'] !== 'new') {
$where .= ' AND `status` = ?';
$params[] = 1;
}
$discovered_devices = 0;
print_cli_heading("%WStarting discovery run at " . date("Y-m-d H:i:s"), 0);
$where .= ' AND `poller_id` = ?';
$params[] = $config['poller_id'];
foreach (dbFetchRows("SELECT * FROM `devices` WHERE `disabled` = 0 $where ORDER BY `last_discovered_timetaken` ASC", $params) as $device) {
// Additional check if device SNMPable, because during
// discovery many devices (long time), the some device can be switched off
if ($options['h'] === 'new' || isSNMPable($device)) {
discover_device($device, $options);
} else {
$string = "Device '" . $device['hostname'] . "' skipped, because switched off during runtime discovery process.";
print_debug($string);
logfile($argv[0] . ": $string");
}
}
print_cli_heading("%WFinished discovery run at " . date("Y-m-d H:i:s"), 0);
$end = utime();
$run = $end - $start;
$discovery_time = substr($run, 0, 5);
// Update Group/Alert tables
if (($discovered_devices && !isset($options['m'])) || isset($options['a'])) {
$silent = isset($options['q']);
if (OBS_DISTRIBUTED && !isset($options['a']) && function_exists('add_action_queue') &&
$action_id = add_action_queue('tables_update', 'discovery', [ 'silent' => $silent ])) {
print_message("Update alert and group tables added to queue [$action_id].");
//log_event("Device with hostname '$hostname' added to queue [$action_id] for addition on remote Poller [{$vars['poller_id']}].", NULL, 'info', NULL, 7);
} else {
if (function_exists('update_group_tables')) { update_group_tables($silent); } // Not exist in CE
if (function_exists('update_alert_tables')) { update_alert_tables($silent); }
}
}
if ($discovered_devices) {
// Single device ID convert to hostname for log
if (is_numeric($doing)) {
$doing = $device['hostname'];
// This discovery passed from wrapper and with process id
if ($config['poller_id'] > 0 &&
$poller = dbFetchRow('SELECT * FROM `pollers` WHERE `poller_id` = ?', [ $config['poller_id'] ])) {
print_debug_vars($poller, 1);
$host_id = get_local_id();
$update = [];
if ($poller['host_id'] != $host_id) {
$update['host_id'] = $host_id;
log_event("Poller ".$config['poller_id']." host ID changed: '".$poller['host_id']."' -> '".$host_id."'");
}
if ($poller['host_uname'] != php_uname()) {
$update['host_uname'] = php_uname();
log_event("Poller ".$config['poller_id']." host uname changed: '".$poller['host_uname']."' -> '".$update['host_uname']."'");
}
if (count($update)) {
dbUpdate($update, 'pollers', '`poller_id` = ?', [ $config['poller_id'] ]);
}
}
}
} elseif (!isset($options['q']) && !$options['u']) {
print_warning("WARNING: 0 devices discovered." . ($options['h'] !== 'new' ? " Did you specify a device that does not exist?" : ''));
}
$string = $argv[0] . ": $doing - $discovered_devices devices discovered in $discovery_time secs";
print_debug($string);
logfile($string);
// Clean stale observium processes
$process_sql = "SELECT * FROM `observium_processes` WHERE `poller_id` = ? AND `process_start` < ?";
foreach (dbFetchRows($process_sql, [ $config['poller_id'], $config['time']['fourhour'] ]) as $process) {
// We found processes in DB, check if it exist on system
print_debug_vars($process);
$pid_info = get_pid_info($process['process_pid']);
if (is_array($pid_info) && str_contains($pid_info['COMMAND'], $process['process_name'])) {
// Process still running
} else {
// Remove stalled DB entries
dbDelete('observium_processes', '`process_id` = ?', array($process['process_id']));
print_debug("Removed stale process entry from DB (cmd: '" . $process['process_command'] . "', PID: '" . $process['process_pid'] . "')");
}
}
if (!isset($options['q'])) {
if ($config['snmp']['hide_auth']) {
print_debug("NOTE, \$config['snmp']['hide_auth'] is set to TRUE, snmp community and snmp v3 auth hidden from debug output.");
}
print_cli_data('Devices Discovered', $discovered_devices, 0);
print_cli_data('Discovery Time', $discovery_time . " secs", 0);
print_cli_data('Memory usage', formatStorage(memory_get_usage(TRUE), 2, 4) .
' (peak: ' . formatStorage(memory_get_peak_usage(TRUE), 2, 4) . ')', 0);
print_cli_data('MySQL Usage', 'Cell[' . ($db_stats['fetchcell'] + 0) . '/' . round($db_stats['fetchcell_sec'] + 0, 3) . 's]' .
' Row[' . ($db_stats['fetchrow'] + 0) . '/' . round($db_stats['fetchrow_sec'] + 0, 3) . 's]' .
' Rows[' . ($db_stats['fetchrows'] + 0) . '/' . round($db_stats['fetchrows_sec'] + 0, 3) . 's]' .
' Column[' . ($db_stats['fetchcol'] + 0) . '/' . round($db_stats['fetchcol_sec'] + 0, 3) . 's]' .
' Update[' . ($db_stats['update'] + 0) . '/' . round($db_stats['update_sec'] + 0, 3) . 's]' .
' Insert[' . ($db_stats['insert'] + 0) . '/' . round($db_stats['insert_sec'] + 0, 3) . 's]' .
' Delete[' . ($db_stats['delete'] + 0) . '/' . round($db_stats['delete_sec'] + 0, 3) . 's]', 0);
$rrd_times = [];
foreach ($GLOBALS['rrdtool'] as $cmd => $data) {
$rrd_times[] = $cmd . "[" . $data['count'] . "/" . round($data['time'], 3) . "s]";
}
print_cli_data('RRDTool Usage', implode(" ", $rrd_times), 0);
}
// EOF