diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8cc3ea1d2a..d7add3a28a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ #### Please note -> Please read this information carefully. +> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting. - [ ] Have you signed the [Contributors agreement](http://docs.librenms.org/General/Contributing/) - [ ] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/) diff --git a/.gitignore b/.gitignore index 8025a1d7e0..2f7c08a528 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ nbproject patches rrd /vendor +composer.phar diff --git a/.travis.yml b/.travis.yml index 7a27f95828..86c04a8549 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,33 +3,24 @@ matrix: fast_finish: true include: - php: 7.0 - env: - PHP_L=1 - EXECUTE_BUILD_DOCS=false - php: 5.3 env: - PHP_L_OLD=1 - EXECUTE_BUILD_DOCS=false + SKIP_STYLE_CHECK=1 - php: 5.4 env: - PHP_L_OLD=1 - EXECUTE_BUILD_DOCS=false + SKIP_STYLE_CHECK=1 - php: 5.5 env: - PHP_L=1 - EXECUTE_BUILD_DOCS=false + SKIP_STYLE_CHECK=1 - php: 5.6 env: - PHP_L=1 - PHP_CS=1 + SKIP_STYLE_CHECK=1 EXECUTE_BUILD_DOCS=true - php: hhvm env: - PHP_L_OLD=1 - EXECUTE_BUILD_DOCS=false + SKIP_STYLE_CHECK=1 allow_failures: - - php: 7.0 - php: hhvm cache: @@ -44,7 +35,6 @@ after_success: - test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && test $EXECUTE_BUILD_DOCS == "true" && bash scripts/deploy-docs.sh script: - - if [[ $PHP_L == 1 ]]; then find . -path './vendor' -prune -o -name "*.php" -print0 | xargs -0 -n1 -P8 php -l | grep -v '^No syntax errors detected' ; test $? -eq 1; fi - - if [[ $PHP_L_OLD == 1 ]]; then find . -regextype posix-extended -regex "\./(lib/influxdb-php|vendor)" -prune -o -name "*.php" -print0 | xargs -0 -n1 -P8 php -l | grep -v '^No syntax errors detected' ; test $? -eq 1; fi - - if [[ $PHP_CS == 1 ]]; then vendor/bin/phpcs -n -p --colors --extensions=php --standard=PSR2 --ignore=html/lib/* html; fi + - php scripts/pre-commit.php -p -l + - php scripts/pre-commit.php -p -s - phpunit diff --git a/AUTHORS.md b/AUTHORS.md index d570321879..9544097fd4 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -121,6 +121,10 @@ LibreNMS contributors: - Phil Regnauld (reegnauld) - Russell Morris (arrmo) - Bennett Blodinger (benwa) +- Michael Hansen (nerdalertdk) +- Daniel Cox (ospfbgp) +- Joseph Cunningham (joeywas) +- Michael Van Delft (HybridAU) [1]: http://observium.org/ "Observium web site" Observium was written by: diff --git a/LibreNMS/ClassLoader.php b/LibreNMS/ClassLoader.php index b14f25bc47..3c9fb0afe1 100644 --- a/LibreNMS/ClassLoader.php +++ b/LibreNMS/ClassLoader.php @@ -25,7 +25,6 @@ namespace LibreNMS; - /** * Class ClassLoader * @package LibreNMS @@ -63,7 +62,7 @@ class ClassLoader $file = str_replace(array('\\', '_'), DIRECTORY_SEPARATOR, $name) . '.php'; $fullFile = realpath(__DIR__ . '/..') . DIRECTORY_SEPARATOR . $file; - if($vdebug) { + if ($vdebug) { echo __CLASS__ . " [[ $name > $fullFile ]]\n"; } @@ -84,7 +83,7 @@ class ClassLoader if (isset($this->classMap[$name])) { $file = $this->classMap[$name]; - if($vdebug) { + if ($vdebug) { echo __CLASS__ . " (( $name > $file ))\n"; } @@ -99,7 +98,7 @@ class ClassLoader foreach (array_keys($this->dirMap[$namespace]) as $dir) { $file = $dir . DIRECTORY_SEPARATOR . $class . '.php'; - if($vdebug) { + if ($vdebug) { echo __CLASS__ . " (( $name > $file ))\n"; } @@ -180,7 +179,8 @@ class ClassLoader * @param string $class the full class name to split * @return array of the split class [namespace, classname] */ - private function splitNamespace($class) { + private function splitNamespace($class) + { $parts = explode('\\', $class); $last = array_pop($parts); return array(implode('\\', $parts), $last); diff --git a/LibreNMS/Component.php b/LibreNMS/Component.php index f71aa63fa6..54779462a1 100644 --- a/LibreNMS/Component.php +++ b/LibreNMS/Component.php @@ -25,7 +25,8 @@ namespace LibreNMS; -class Component { +class Component +{ /* * These fields are used in the component table. They are returned in the array * so that they can be modified but they can not be set as user attributes. We @@ -40,12 +41,12 @@ class Component { 'error' => '', ); - public function getComponentType($TYPE=null) { + public function getComponentType($TYPE = null) + { if (is_null($TYPE)) { $SQL = "SELECT DISTINCT `type` as `name` FROM `component` ORDER BY `name`"; $row = dbFetchRow($SQL, array()); - } - else { + } else { $SQL = "SELECT DISTINCT `type` as `name` FROM `component` WHERE `type` = ? ORDER BY `name`"; $row = dbFetchRow($SQL, array($TYPE)); } @@ -53,14 +54,14 @@ class Component { if (!isset($row)) { // We didn't find any component types return false; - } - else { + } else { // We found some.. return $row; } } - public function getComponents($device_id=null,$options=array()) { + public function getComponents($device_id = null, $options = array()) + { // Define our results array, this will be set even if no rows are returned. $RESULT = array(); $PARAM = array(); @@ -87,25 +88,24 @@ class Component { $SQL .= " ( "; foreach ($options['filter'] as $field => $array) { // Only add valid fields to the query - if (in_array($field,$validFields)) { + if (in_array($field, $validFields)) { if ($array[0] == 'LIKE') { $SQL .= "`".$field."` LIKE ? AND "; $array[1] = "%".$array[1]."%"; - } - else { + } else { // Equals operator is the default $SQL .= "`".$field."` = ? AND "; } - array_push($PARAM,$array[1]); + array_push($PARAM, $array[1]); } } // Strip the last " AND " before closing the bracket. - $SQL = substr($SQL,0,-5)." )"; + $SQL = substr($SQL, 0, -5)." )"; } if ($COUNT == 0) { // Strip the " WHERE " that we didn't use. - $SQL = substr($SQL,0,-7); + $SQL = substr($SQL, 0, -7); } // sort column direction @@ -149,7 +149,7 @@ class Component { foreach ($RESULT as $k => $v) { // k1 = component id, v1 = component array foreach ($v as $k1 => $v1) { - if ( ($COUNT >= $options['limit'][0]) && ($COUNT < $options['limit'][0]+$options['limit'][1])) { + if (($COUNT >= $options['limit'][0]) && ($COUNT < $options['limit'][0]+$options['limit'][1])) { $TEMP[$k][$k1] = $v1; } // We are counting components. @@ -162,7 +162,8 @@ class Component { return $RESULT; } - public function getComponentStatus($device=null) { + public function getComponentStatus($device = null) + { $sql_query = "SELECT status, count(status) as count FROM component WHERE"; $sql_param = array(); $add = 0; @@ -191,12 +192,13 @@ class Component { $count[$v['status']] = $v['count']; } - d_echo("Component Count by Status: ".print_r($count,TRUE)."\n"); + d_echo("Component Count by Status: ".print_r($count, true)."\n"); return $count; } - public function getComponentStatusLog($component=null,$start=null,$end=null) { - if ( ($component == null) || ($start == null) || ($end == null) ) { + public function getComponentStatusLog($component = null, $start = null, $end = null) + { + if (($component == null) || ($start == null) || ($end == null)) { // Error... d_echo("Required arguments are missing. Component: ".$component.", Start: ".$start.", End: ".$end."\n"); return false; @@ -211,8 +213,7 @@ class Component { $result = dbFetchRow($sql_query, $sql_param); if ($result == false) { $return['initial'] = false; - } - else { + } else { $return['initial'] = $result['status']; } @@ -221,11 +222,12 @@ class Component { $sql_param = array($component,$start,$end); $return['data'] = dbFetchRows($sql_query, $sql_param); - d_echo("Status Log Data: ".print_r($return,TRUE)."\n"); + d_echo("Status Log Data: ".print_r($return, true)."\n"); return $return; } - public function createComponent ($device_id,$TYPE) { + public function createComponent($device_id, $TYPE) + { // Prepare our default values to be inserted. $DATA = $this->reserved; @@ -237,16 +239,17 @@ class Component { $id = dbInsert($DATA, 'component'); // Add a default status log entry - we always start ok. - $this->createStatusLogEntry($id,0,'Component Created'); + $this->createStatusLogEntry($id, 0, 'Component Created'); // Create a default component array based on what was inserted. $ARRAY = array(); $ARRAY[$id] = $DATA; - unset ($ARRAY[$id]['device_id']); // This doesn't belong here. + unset($ARRAY[$id]['device_id']); // This doesn't belong here. return $ARRAY; } - public function createStatusLogEntry($component,$status,$message) { + public function createStatusLogEntry($component, $status, $message) + { // Add an entry to the statuslog table for a particular component. $DATA = array( 'component' => $component, @@ -257,18 +260,19 @@ class Component { return dbInsert($DATA, 'component_statuslog'); } - public function deleteComponent ($id) { + public function deleteComponent($id) + { // Delete a component from the database. - return dbDelete('component', "`id` = ?",array($id)); + return dbDelete('component', "`id` = ?", array($id)); } - public function setComponentPrefs ($device_id,$ARRAY) { + public function setComponentPrefs($device_id, $ARRAY) + { // Compare the arrays. Update/Insert where necessary. $OLD = $this->getComponents($device_id); // Loop over each component. foreach ($ARRAY as $COMPONENT => $AVP) { - // Make sure the component already exists. if (!isset($OLD[$device_id][$COMPONENT])) { // Error. Component doesn't exist in the database. @@ -281,7 +285,7 @@ class Component { // If the Status has changed we need to add a log entry if ($AVP['status'] != $OLD[$device_id][$COMPONENT]['status']) { d_echo("Status Changed - Old: ".$OLD[$device_id][$COMPONENT]['status'].", New: ".$AVP['status']."\n"); - $this->createStatusLogEntry($COMPONENT,$AVP['status'],$AVP['error']); + $this->createStatusLogEntry($COMPONENT, $AVP['status'], $AVP['error']); } // Process our reserved components first. @@ -289,7 +293,6 @@ class Component { foreach ($this->reserved as $k => $v) { // does the reserved field exist, if not skip. if (isset($AVP[$k])) { - // Has the value changed? if ($AVP[$k] != $OLD[$device_id][$COMPONENT][$k]) { // The value has been modified, add it to our update array. @@ -311,8 +314,8 @@ class Component { foreach ($UPDATE as $k => $v) { $MSG .= $k." => ".$v.","; } - $MSG = substr($MSG,0,-1); - log_event($MSG,$device_id,'component',$COMPONENT); + $MSG = substr($MSG, 0, -1); + log_event($MSG, $device_id, 'component', $COMPONENT); } // Process our AVP Adds and Updates @@ -325,32 +328,28 @@ class Component { dbInsert($DATA, 'component_prefs'); // Log the addition to the Eventlog. - log_event ("Component: " . $AVP[$COMPONENT]['type'] . "(" . $COMPONENT . "). Attribute: " . $ATTR . ", was added with value: " . $VALUE, $device_id, 'component', $COMPONENT); - } - elseif ($OLD[$device_id][$COMPONENT][$ATTR] != $VALUE) { + log_event("Component: " . $AVP[$COMPONENT]['type'] . "(" . $COMPONENT . "). Attribute: " . $ATTR . ", was added with value: " . $VALUE, $device_id, 'component', $COMPONENT); + } elseif ($OLD[$device_id][$COMPONENT][$ATTR] != $VALUE) { // Attribute exists but the value is different, need to update $DATA = array('value'=>$VALUE); dbUpdate($DATA, 'component_prefs', '`component` = ? AND `attribute` = ?', array($COMPONENT, $ATTR)); // Add the modification to the Eventlog. - log_event("Component: ".$AVP[$COMPONENT]['type']."(".$COMPONENT."). Attribute: ".$ATTR.", was modified from: ".$OLD[$COMPONENT][$ATTR].", to: ".$VALUE,$device_id,'component',$COMPONENT); + log_event("Component: ".$AVP[$COMPONENT]['type']."(".$COMPONENT."). Attribute: ".$ATTR.", was modified from: ".$OLD[$COMPONENT][$ATTR].", to: ".$VALUE, $device_id, 'component', $COMPONENT); } - } // End Foreach AVP // Process our Deletes. $DELETE = array_diff_key($OLD[$device_id][$COMPONENT], $AVP); foreach ($DELETE as $KEY => $VALUE) { // As the Attribute has been removed from the array, we should remove it from the database. - dbDelete('component_prefs', "`component` = ? AND `attribute` = ?",array($COMPONENT,$KEY)); + dbDelete('component_prefs', "`component` = ? AND `attribute` = ?", array($COMPONENT,$KEY)); // Log the addition to the Eventlog. - log_event ("Component: " . $AVP[$COMPONENT]['type'] . "(" . $COMPONENT . "). Attribute: " . $KEY . ", was deleted.", $COMPONENT); + log_event("Component: " . $AVP[$COMPONENT]['type'] . "(" . $COMPONENT . "). Attribute: " . $KEY . ", was deleted.", $COMPONENT); } - } return true; } - } diff --git a/LibreNMS/Exceptions/FileExistsException.php b/LibreNMS/Exceptions/FileExistsException.php index 02ec938f5a..55a42cd183 100644 --- a/LibreNMS/Exceptions/FileExistsException.php +++ b/LibreNMS/Exceptions/FileExistsException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class FileExistsException extends \Exception { diff --git a/LibreNMS/Exceptions/HostExistsException.php b/LibreNMS/Exceptions/HostExistsException.php index c48740b81a..7e3e9de88b 100644 --- a/LibreNMS/Exceptions/HostExistsException.php +++ b/LibreNMS/Exceptions/HostExistsException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class HostExistsException extends \Exception { diff --git a/LibreNMS/Exceptions/HostIpExistsException.php b/LibreNMS/Exceptions/HostIpExistsException.php index 4159bfdbc1..7345a8d9f2 100644 --- a/LibreNMS/Exceptions/HostIpExistsException.php +++ b/LibreNMS/Exceptions/HostIpExistsException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class HostIpExistsException extends HostExistsException { diff --git a/LibreNMS/Exceptions/HostUnreachableException.php b/LibreNMS/Exceptions/HostUnreachableException.php index 951ccf1a60..8ab9bac383 100644 --- a/LibreNMS/Exceptions/HostUnreachableException.php +++ b/LibreNMS/Exceptions/HostUnreachableException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class HostUnreachableException extends \Exception { protected $reasons = array(); diff --git a/LibreNMS/Exceptions/HostUnreachablePingException.php b/LibreNMS/Exceptions/HostUnreachablePingException.php index f013587d13..c0fa98f18a 100644 --- a/LibreNMS/Exceptions/HostUnreachablePingException.php +++ b/LibreNMS/Exceptions/HostUnreachablePingException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class HostUnreachablePingException extends HostUnreachableException { diff --git a/LibreNMS/Exceptions/HostUnreachableSnmpException.php b/LibreNMS/Exceptions/HostUnreachableSnmpException.php index ec6e97d677..6ccabd0f24 100644 --- a/LibreNMS/Exceptions/HostUnreachableSnmpException.php +++ b/LibreNMS/Exceptions/HostUnreachableSnmpException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class HostUnreachableSnmpException extends HostUnreachableException { diff --git a/LibreNMS/Exceptions/InvalidPortAssocModeException.php b/LibreNMS/Exceptions/InvalidPortAssocModeException.php index 285fb4ac9c..0217ac5aad 100644 --- a/LibreNMS/Exceptions/InvalidPortAssocModeException.php +++ b/LibreNMS/Exceptions/InvalidPortAssocModeException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class InvalidPortAssocModeException extends \Exception { diff --git a/LibreNMS/Exceptions/SnmpVersionUnsupportedException.php b/LibreNMS/Exceptions/SnmpVersionUnsupportedException.php index 79b87e053e..bf8f2bbe61 100644 --- a/LibreNMS/Exceptions/SnmpVersionUnsupportedException.php +++ b/LibreNMS/Exceptions/SnmpVersionUnsupportedException.php @@ -25,7 +25,6 @@ namespace LibreNMS\Exceptions; - class SnmpVersionUnsupportedException extends \Exception { diff --git a/LibreNMS/IRCBot.php b/LibreNMS/IRCBot.php new file mode 100644 index 0000000000..c4452e183b --- /dev/null +++ b/LibreNMS/IRCBot.php @@ -0,0 +1,729 @@ + + * Modified and Relicensed by under the expressed + * permission by the Copyright-Holder . + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * */ + +namespace LibreNMS; + +class IRCBot +{ + + private $last_activity = ''; + + private $data = ''; + + private $authd = array(); + + private $debug = false; + + private $server = ''; + + private $port = ''; + + private $ssl = false; + + private $pass = ''; + + private $nick = 'LibreNMS'; + + private $chan = array(); + + private $commands = array( + 'auth', + 'quit', + 'listdevices', + 'device', + 'port', + 'down', + 'version', + 'status', + 'log', + 'help', + 'reload', + 'join', + ); + + private $external = array(); + + private $tick = 62500; + + + public function __construct() + { + global $config, $database_link; + $this->log('Setting up IRC-Bot..'); + if (is_resource($database_link)) { + $this->sql = $database_link; + } + + $this->config = $config; + $this->debug = $this->config['irc_debug']; + $this->config['irc_authtime'] = $this->config['irc_authtime'] ? $this->config['irc_authtime'] : 3; + $this->max_retry = $this->config['irc_maxretry']; + $this->server = $this->config['irc_host']; + if ($this->config['irc_port'][0] == '+') { + $this->ssl = true; + $this->port = substr($this->config['irc_port'], 1); + } else { + $this->port = $this->config['irc_port']; + } + + if ($this->config['irc_nick']) { + $this->nick = $this->config['irc_nick']; + } + + if ($this->config['irc_chan']) { + if (is_array($this->config['irc_chan'])) { + $this->chan = $this->config['irc_chan']; + } elseif (strstr($this->config['irc_chan'], ',')) { + $this->chan = explode(',', $this->config['irc_chan']); + } else { + $this->chan = array($this->config['irc_chan']); + } + } + + if ($this->config['irc_alert_chan']) { + if (strstr($this->config['irc_alert_chan'], ',')) { + $this->config['irc_alert_chan'] = explode(',', $this->config['irc_alert_chan']); + } else { + $this->config['irc_alert_chan'] = array($this->config['irc_alert_chan']); + } + } + + if ($this->config['irc_pass']) { + $this->pass = $this->config['irc_pass']; + } + + $this->loadExternal(); + $this->log('Starting IRC-Bot..'); + $this->init(); + }//end __construct() + + + private function loadExternal() + { + if (!$this->config['irc_external']) { + return true; + } + + $this->log('Caching external commands...'); + if (!is_array($this->config['irc_external'])) { + $this->config['irc_external'] = explode(',', $this->config['irc_external']); + } + + foreach ($this->config['irc_external'] as $ext) { + if (($this->external[$ext] = file_get_contents('includes/ircbot/'.$ext.'.inc.php')) == '') { + unset($this->external[$ext]); + } + } + + return $this->log('Cached '.sizeof($this->external).' commands.'); + }//end load_external() + + + private function init() + { + if ($this->config['irc_alert']) { + $this->connectAlert(); + } + + $this->last_activity = time(); + + $this->j = 2; + + $this->connect(); + $this->log('Connected'); + if ($this->pass) { + fwrite($this->socket['irc'], 'PASS '.$this->pass."\n\r"); + } + + $this->doAuth(); + while (true) { + foreach ($this->socket as $n => $socket) { + if (!is_resource($socket) || feof($socket)) { + $this->log("Socket '$n' closed. Restarting."); + break 2; + } + } + + $this->getData(); + if ($this->config['irc_alert']) { + $this->alertData(); + } + + if ($this->config['irc_conn_timeout']) { + $inactive_seconds = time() - $this->last_activity; + $max_inactive = $this->config['irc_conn_timeout']; + if ($inactive_seconds > $max_inactive) { + $this->log("No data from server since " . $max_inactive . " seconds. Restarting."); + break; + } + } + + + usleep($this->tick); + } + + return $this->init(); + }//end init() + + + private function connectAlert() + { + $f = $this->config['install_dir'].'/.ircbot.alert'; + if (( file_exists($f) && filetype($f) != 'fifo' && !unlink($f) ) || ( !file_exists($f) && !shell_exec("mkfifo $f && echo 1") )) { + $this->log('Error - Cannot create Alert-File'); + return false; + } + + if (($this->socket['alert'] = fopen($f, 'r+'))) { + $this->log('Opened Alert-File'); + stream_set_blocking($this->socket['alert'], false); + return true; + } + + $this->log('Error - Cannot open Alert-File'); + return false; + }//end connect_alert() + + + private function read($buff) + { + $r = fread($this->socket[$buff], 64); + $this->buff[$buff] .= $r; + $r = strlen($r); + if (strstr($this->buff[$buff], "\n")) { + $tmp = explode("\n", $this->buff[$buff], 2); + $this->buff[$buff] = substr($this->buff[$buff], (strlen($tmp[0]) + 1)); + if ($this->debug) { + $this->log("Returning buffer '$buff': '".trim($tmp[0])."'"); + } + + return $tmp[0]; + } + + if ($this->debug && $r > 0) { + $this->log("Expanding buffer '$buff' = '".trim($this->buff[$buff])."'"); + } + + return false; + }//end read() + + + private function alertData() + { + if (($alert = $this->read('alert')) !== false) { + $alert = json_decode($alert, true); + if (!is_array($alert)) { + return false; + } + + switch ($alert['state']) : + case 3: + $severity_extended = '+'; + break; + case 4: + $severity_extended = '-'; + break; + default: + $severity_extended = ''; + endswitch; + + $severity = str_replace(array('warning', 'critical'), array(chr(3).'8Warning', chr(3).'4Critical'), $alert['severity']).$severity_extended.chr(3).' '; + if ($alert['state'] == 0 and $this->config['irc_alert_utf8']) { + $severity = str_replace(array('Warning', 'Critical'), array('W̶a̶r̶n̶i̶n̶g̶', 'C̶r̶i̶t̶i̶c̶a̶l̶'), $severity); + } + + if ($this->config['irc_alert_chan']) { + foreach ($this->config['irc_alert_chan'] as $chan) { + $this->ircRaw('PRIVMSG '.$chan.' :'.$severity.trim($alert['title']).' - Rule: '.trim($alert['name'] ? $alert['name'] : $alert['rule']).(sizeof($alert['faults']) > 0 ? ' - Faults:' : '')); + foreach ($alert['faults'] as $k => $v) { + $this->ircRaw('PRIVMSG '.$chan.' :#'.$k.' '.$v['string']); + } + } + } else { + foreach ($this->authd as $nick => $data) { + if ($data['expire'] >= time()) { + $this->ircRaw('PRIVMSG '.$nick.' :'.$severity.trim($alert['title']).' - Rule: '.trim($alert['name'] ? $alert['name'] : $alert['rule']).(sizeof($alert['faults']) > 0 ? ' - Faults'.(sizeof($alert['faults']) > 3 ? ' (showing first 3 out of '.sizeof($alert['faults']).' )' : '' ).':' : '')); + foreach ($alert['faults'] as $k => $v) { + $this->ircRaw('PRIVMSG '.$nick.' :#'.$k.' '.$v['string']); + if ($k >= 3) { + break; + } + } + } + } + } + }//end if + }//end alertData() + + + private function getData() + { + if (($data = $this->read('irc')) !== false) { + $this->last_activity = time(); + $this->data = $data; + $ex = explode(' ', $this->data); + if ($ex[0] == 'PING') { + return $this->ircRaw('PONG '.$ex[1]); + } + + if ($ex[1] == 376 || $ex[1] == 422 || ($ex[1] == 'MODE' && $ex[2] == $this->nick)) { + if ($this->j == 2) { + $this->joinChan(); + $this->j = 0; + } + } + + $this->command = str_replace(array(chr(10), chr(13)), '', $ex[3]); + if (strstr($this->command, ':.')) { + $this->handleCommand(); + } + } + }//end getData() + + + private function joinChan($chan = false) + { + if ($chan) { + $this->chan[] = $chan; + } + + foreach ($this->chan as $chan) { + $this->ircRaw('JOIN '.$chan); + } + + return true; + }//end joinChan() + + + private function handleCommand() + { + $this->command = str_replace(':.', '', $this->command); + $tmp = explode(':.'.$this->command.' ', $this->data); + $this->user = $this->getAuthdUser(); + if ($this->isAuthd() || trim($this->command) == 'auth') { + $this->proceedCommand(str_replace("\n", '', trim($this->command)), trim($tmp[1])); + } + + $this->authd[$this->getUser($this->data)] = $this->user; + return false; + }//end handleCommand() + + + private function proceedCommand($command, $params) + { + $command = strtolower($command); + if (in_array($command, $this->commands)) { + $this->chkdb(); + $this->log($command." ( '".$params."' )"); + return $this->{'_'.$command}($params); + } elseif ($this->external[$command]) { + $this->chkdb(); + $this->log($command." ( '".$params."' ) [Ext]"); + return eval($this->external[$command]); + } + + return false; + }//end proceedCommand() + + + private function respond($msg) + { + $chan = $this->getChan($this->data); + return $this->sendMessage($msg, strstr($chan, '#') ? $chan : $this->getUser($this->data)); + }//end respond() + + + private function getChan($param) + { + $data = explode('PRIVMSG ', $this->data, 3); + $data = explode(' ', $data[1], 2); + return $data[0]; + }//end getChan() + + + private function getUser($param) + { + $arrData = explode('!', $param, 2); + return str_replace(':', '', $arrData[0]); + }//end getUser() + + + private function connect($try) + { + if ($try > $this->max_retry) { + $this->log('Failed too many connection attempts, aborting'); + return die(); + } + + $this->log('Trying to connect to '.$this->server.':'.$this->port.($this->ssl ? ' (SSL)' : '')); + if ($this->socket['irc']) { + fclose($this->socket['irc']); + } + + if ($this->ssl) { + $server = 'ssl://'.$this->server; + } else { + $server = $this->server; + } + + if ($this->ssl && $this->config['irc_disable_ssl_check']) { + $ssl_context_params = array('ssl'=>array('allow_self_signed'=> true, 'verify_peer' => false, 'verify_peer_name' => false )); + $ssl_context = stream_context_create($ssl_context_params); + $this->socket['irc'] = stream_socket_client($server.':'.$this->port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $ssl_context); + } else { + $this->socket['irc'] = fsockopen($server, $this->port); + } + + if (!is_resource($this->socket['irc'])) { + return $this->connect($try + 1); + } else { + stream_set_blocking($this->socket['irc'], false); + return true; + } + }//end connect() + + + private function doAuth() + { + if ($this->ircRaw('USER '.$this->nick.' 0 '.$this->nick.' :'.$this->nick) && $this->ircRaw('NICK '.$this->nick)) { + return true; + } + + return false; + }//end doAuth() + + + private function sendMessage($message, $chan) + { + if ($this->debug) { + $this->log("Sending 'PRIVMSG ".trim($chan).' :'.trim($message)."'"); + } + + return $this->ircRaw('PRIVMSG '.trim($chan).' :'.trim($message)); + }//end sendMessage() + + + private function log($msg) + { + echo '['.date('r').'] '.trim($msg)."\n"; + return true; + }//end log() + + + private function chkdb() + { + if (!is_resource($this->sql)) { + if (($this->sql = mysqli_connect($this->config['db_host'], $this->config['db_user'], $this->config['db_pass'])) != false && mysqli_select_db($this->sql, $this->config['db_name'])) { + return true; + } else { + $this->log('Cannot connect to MySQL'); + return die(); + } + } else { + return true; + } + }//end chkdb() + + + private function isAuthd() + { + if ($this->user['expire'] >= time()) { + $this->user['expire'] = (time() + ($this->config['irc_authtime'] * 3600)); + return true; + } else { + return false; + } + }//end isAuthd() + + + private function getAuthdUser() + { + return $this->authd[$this->getUser($this->data)]; + }//end get_user() + + + private function ircRaw($params) + { + return fputs($this->socket['irc'], $params."\r\n"); + }//end irc_raw() + + + private function _auth($params) + { + $params = explode(' ', $params, 2); + if (strlen($params[0]) == 64) { + if ($this->tokens[$this->getUser($this->data)] == $params[0]) { + $this->user['expire'] = (time() + ($this->config['irc_authtime'] * 3600)); + $tmp = dbFetchRow('SELECT level FROM users WHERE user_id = ?', array($this->user['id'])); + $this->user['level'] = $tmp['level']; + if ($this->user['level'] < 5) { + foreach (dbFetchRows('SELECT device_id FROM devices_perms WHERE user_id = ?', array($this->user['id'])) as $tmp) { + $this->user['devices'][] = $tmp['device_id']; + } + + foreach (dbFetchRows('SELECT port_id FROM ports_perms WHERE user_id = ?', array($this->user['id'])) as $tmp) { + $this->user['ports'][] = $tmp['port_id']; + } + } + + return $this->respond('Authenticated.'); + } else { + return $this->respond('Nope.'); + } + } else { + $user = dbFetchRow('SELECT `user_id`,`username`,`email` FROM `users` WHERE `username` = ?', array(mres($params[0]))); + if ($user['email'] && $user['username'] == $params[0]) { + $token = hash('gost', openssl_random_pseudo_bytes(1024)); + $this->tokens[$this->getUser($this->data)] = $token; + $this->user['name'] = $params[0]; + $this->user['id'] = $user['user_id']; + if ($this->debug) { + $this->log("Auth for '".$params[0]."', ID: '".$user['user_id']."', Token: '".$token."', Mail: '".$user['email']."'"); + } + + if (send_mail($user['email'], 'LibreNMS IRC-Bot Authtoken', "Your Authtoken for the IRC-Bot:\r\n\r\n".$token."\r\n\r\n") === true) { + return $this->respond('Token sent!'); + } else { + return $this->respond('Sorry, seems like mail doesnt like us.'); + } + } else { + return $this->respond('Who are you again?'); + } + }//end if + return false; + }//end _auth() + + + private function _reload() + { + if ($this->user['level'] == 10) { + global $config; + $config = array(); + include 'includes/defaults.inc.php'; + include 'config.php'; + include 'includes/definitions.inc.php'; + $this->respond('Reloading configuration & defaults'); + if ($config != $this->config) { + return $this->__construct(); + } + } else { + return $this->respond('Permission denied.'); + } + }//end _reload() + + + private function _join($params) + { + if ($this->user['level'] == 10) { + return $this->joinChan($params); + } else { + return $this->respond('Permission denied.'); + } + }//end _join() + + + private function _quit($params) + { + if ($this->user['level'] == 10) { + return die(); + } else { + return $this->respond('Permission denied.'); + } + }//end _quit() + + + private function _help($params) + { + foreach ($this->commands as $cmd) { + $msg .= ', '.$cmd; + } + + $msg = substr($msg, 2); + return $this->respond("Available commands: $msg"); + }//end _help() + + + private function _version($params) + { + return $this->respond($this->config['project_name_version'].', PHP: '.PHP_VERSION); + }//end _version() + + + private function _log($params) + { + $num = 1; + if ($params > 1) { + $num = $params; + } + + if ($this->user['level'] < 5) { + $tmp = dbFetchRows('SELECT `event_id`,`host`,`datetime`,`message`,`type` FROM `eventlog` WHERE `host` IN ('.implode(',', $this->user['devices']).') ORDER BY `event_id` DESC LIMIT '.mres($num)); + } else { + $tmp = dbFetchRows('SELECT `event_id`,`host`,`datetime`,`message`,`type` FROM `eventlog` ORDER BY `event_id` DESC LIMIT '.mres($num)); + } + + foreach ($tmp as $device) { + $hostid = dbFetchRow('SELECT `hostname` FROM `devices` WHERE `device_id` = '.$device['host']); + $this->respond($device['event_id'].' '.$hostid['hostname'].' '.$device['datetime'].' '.$device['message'].' '.$device['type']); + } + + if (!$hostid) { + $this->respond('Nothing to see, maybe a bug?'); + } + + return true; + }//end _log() + + + private function _down($params) + { + if ($this->user['level'] < 5) { + $tmp = dbFetchRows('SELECT `hostname` FROM `devices` WHERE status=0 AND `device_id` IN ('.implode(',', $this->user['devices']).')'); + } else { + $tmp = dbFetchRows('SELECT `hostname` FROM `devices` WHERE status=0'); + } + + foreach ($tmp as $db) { + if ($db['hostname']) { + $msg .= ', '.$db['hostname']; + } + } + + $msg = substr($msg, 2); + $msg = $msg ? $msg : 'Nothing to show :)'; + return $this->respond($msg); + }//end _down() + + + private function _device($params) + { + $params = explode(' ', $params); + $hostname = $params[0]; + $device = dbFetchRow('SELECT * FROM `devices` WHERE `hostname` = ?', array($hostname)); + if (!$device) { + return $this->respond('Error: Bad or Missing hostname, use .listdevices to show all devices.'); + } + + if ($this->user['level'] < 5 && !in_array($device['device_id'], $this->user['devices'])) { + return $this->respond('Error: Permission denied.'); + } + + $status = $device['status'] ? 'Up '.formatUptime($device['uptime']) : 'Down'; + $status .= $device['ignore'] ? '*Ignored*' : ''; + $status .= $device['disabled'] ? '*Disabled*' : ''; + return $this->respond($device['os'].' '.$device['version'].' '.$device['features'].' '.$status); + }//end _device() + + + private function _port($params) + { + $params = explode(' ', $params); + $hostname = $params[0]; + $ifname = $params[1]; + if (!$hostname || !$ifname) { + return $this->respond('Error: Missing hostname or ifname.'); + } + + $device = dbFetchRow('SELECT * FROM `devices` WHERE `hostname` = ?', array($hostname)); + $port = dbFetchRow('SELECT * FROM `ports` WHERE (`ifName` = ? OR `ifDescr` = ?) AND device_id = ?', array($ifname, $ifname, $device['device_id'])); + if ($this->user['level'] < 5 && !in_array($port['port_id'], $this->user['ports']) && !in_array($device['device_id'], $this->user['devices'])) { + return $this->respond('Error: Permission denied.'); + } + + $bps_in = formatRates($port['ifInOctets_rate'] * 8); + $bps_out = formatRates($port['ifOutOctets_rate'] * 8); + $pps_in = format_bi($port['ifInUcastPkts_rate']); + $pps_out = format_bi($port['ifOutUcastPkts_rate']); + return $this->respond($port['ifAdminStatus'].'/'.$port['ifOperStatus'].' '.$bps_in.' > bps > '.$bps_out.' | '.$pps_in.'pps > PPS > '.$pps_out.'pps'); + }//end _port() + + + private function _listdevices($params) + { + if ($this->user['level'] < 5) { + $tmp = dbFetchRows('SELECT `hostname` FROM `devices` WHERE `device_id` IN ('.implode(',', $this->user['devices']).')'); + } else { + $tmp = dbFetchRows('SELECT `hostname` FROM `devices`'); + } + + foreach ($tmp as $device) { + $msg .= ', '.$device['hostname']; + } + + $msg = substr($msg, 2); + $msg = $msg ? $msg : 'Nothing to show..?'; + return $this->respond($msg); + }//end _listdevices() + + + private function _status($params) + { + $params = explode(' ', $params); + $statustype = $params[0]; + if ($this->user['level'] < 5) { + $d_w = ' WHERE device_id IN ('.implode(',', $this->user['devices']).')'; + $d_a = ' AND device_id IN ('.implode(',', $this->user['devices']).')'; + $p_w = ' WHERE port_id IN ('.implode(',', $this->user['ports']).') OR device_id IN ('.implode(',', $this->user['devices']).')'; + $p_a = ' AND (I.port_id IN ('.implode(',', $this->user['ports']).') OR I.device_id IN ('.implode(',', $this->user['devices']).'))'; + } + + switch ($statustype) { + case 'devices': + case 'device': + case 'dev': + $devcount = array_pop(dbFetchRow('SELECT count(*) FROM devices'.$d_w)); + $devup = array_pop(dbFetchRow("SELECT count(*) FROM devices WHERE status = '1' AND `ignore` = '0'".$d_a)); + $devdown = array_pop(dbFetchRow("SELECT count(*) FROM devices WHERE status = '0' AND `ignore` = '0'".$d_a)); + $devign = array_pop(dbFetchRow("SELECT count(*) FROM devices WHERE `ignore` = '1'".$d_a)); + $devdis = array_pop(dbFetchRow("SELECT count(*) FROM devices WHERE `disabled` = '1'".$d_a)); + $msg = 'Devices: '.$devcount.' ('.$devup.' up, '.$devdown.' down, '.$devign.' ignored, '.$devdis.' disabled'.')'; + break; + + case 'ports': + case 'port': + case 'prt': + $prtcount = array_pop(dbFetchRow('SELECT count(*) FROM ports'.$p_w)); + $prtup = array_pop(dbFetchRow("SELECT count(*) FROM ports AS I, devices AS D WHERE I.ifOperStatus = 'up' AND I.ignore = '0' AND I.device_id = D.device_id AND D.ignore = '0'".$p_a)); + $prtdown = array_pop(dbFetchRow("SELECT count(*) FROM ports AS I, devices AS D WHERE I.ifOperStatus = 'down' AND I.ifAdminStatus = 'up' AND I.ignore = '0' AND D.device_id = I.device_id AND D.ignore = '0'".$p_a)); + $prtsht = array_pop(dbFetchRow("SELECT count(*) FROM ports AS I, devices AS D WHERE I.ifAdminStatus = 'down' AND I.ignore = '0' AND D.device_id = I.device_id AND D.ignore = '0'".$p_a)); + $prtign = array_pop(dbFetchRow("SELECT count(*) FROM ports AS I, devices AS D WHERE D.device_id = I.device_id AND (I.ignore = '1' OR D.ignore = '1')".$p_a)); + $prterr = array_pop(dbFetchRow("SELECT count(*) FROM ports AS I, devices AS D WHERE D.device_id = I.device_id AND (I.ignore = '0' OR D.ignore = '0') AND (I.ifInErrors_delta > '0' OR I.ifOutErrors_delta > '0')".$p_a)); + $msg = 'Ports: '.$prtcount.' ('.$prtup.' up, '.$prtdown.' down, '.$prtign.' ignored, '.$prtsht.' shutdown'.')'; + break; + + case 'services': + case 'service': + case 'srv': + $srvcount = array_pop(dbFetchRow('SELECT count(service_id) FROM services'.$d_w)); + $srvup = array_pop(dbFetchRow("SELECT count(service_id) FROM services WHERE service_status = '1' AND service_ignore ='0'".$d_a)); + $srvdown = array_pop(dbFetchRow("SELECT count(service_id) FROM services WHERE service_status = '0' AND service_ignore = '0'".$d_a)); + $srvign = array_pop(dbFetchRow("SELECT count(service_id) FROM services WHERE service_ignore = '1'".$d_a)); + $srvdis = array_pop(dbFetchRow("SELECT count(service_id) FROM services WHERE service_disabled = '1'".$d_a)); + $msg = 'Services: '.$srvcount.' ('.$srvup.' up, '.$srvdown.' down, '.$srvign.' ignored, '.$srvdis.' disabled'.')'; + break; + + default: + $msg = 'Error: STATUS requires one of the following: ||'; + break; + }//end switch + + return $this->respond($msg); + }//end _status() +}//end class diff --git a/LibreNMS/ObjectCache.php b/LibreNMS/ObjectCache.php index c2bb3f7d66..437c96402d 100644 --- a/LibreNMS/ObjectCache.php +++ b/LibreNMS/ObjectCache.php @@ -28,7 +28,8 @@ namespace LibreNMS; use ArrayAccess; -class ObjectCache implements ArrayAccess { +class ObjectCache implements ArrayAccess +{ private $data = array(); @@ -39,13 +40,13 @@ class ObjectCache implements ArrayAccess { * Initialize ObjectCache * @param string $obj Name of Object */ - public function __construct($obj) { + public function __construct($obj) + { global $config; $this->obj = $obj; if (isset($GLOBALS['_ObjCache'][$obj])) { $this->data = $GLOBALS['_ObjCacheSkell'][$obj]; - } - else { + } else { if (!is_array($GLOBALS['_ObjCacheSkell'])) { $GLOBALS['_ObjCacheSkell'] = array(); } @@ -64,7 +65,6 @@ class ObjectCache implements ArrayAccess { } } }//end if - }//end __construct() @@ -73,13 +73,13 @@ class ObjectCache implements ArrayAccess { * @param string $obj Name of Data-Object * @return boolean */ - public function offsetExists($obj) { + public function offsetExists($obj) + { if (isset($this->data[$obj])) { return true; } return false; - }//end offsetExists() @@ -88,15 +88,14 @@ class ObjectCache implements ArrayAccess { * @param string $obj Name of Data-Object * @return mixed */ - public function offsetGet($obj) { + public function offsetGet($obj) + { if (isset($this->data[$obj])) { if (isset($this->data[$obj]['value'])) { return $this->data[$obj]['value']; - } - else if (isset($GLOBALS['_ObjCache'][$this->obj][$obj]['value'])) { + } elseif (isset($GLOBALS['_ObjCache'][$this->obj][$obj]['value'])) { return $GLOBALS['_ObjCache'][$this->obj][$obj]['value']; - } - else { + } else { $GLOBALS['_ObjCache'][$this->obj][$obj]['value'] = dbFetchRows($this->data[$obj]['query'], $this->data[$obj]['params']); if (sizeof($GLOBALS['_ObjCache'][$this->obj][$obj]['value']) == 1 && sizeof($GLOBALS['_ObjCache'][$this->obj][$obj]['value'][0]) == 1) { $GLOBALS['_ObjCache'][$this->obj][$obj]['value'] = current($GLOBALS['_ObjCache'][$this->obj][$obj]['value'][0]); @@ -104,7 +103,6 @@ class ObjectCache implements ArrayAccess { return $GLOBALS['_ObjCache'][$this->obj][$obj]['value']; } } - }//end offsetGet() @@ -114,14 +112,14 @@ class ObjectCache implements ArrayAccess { * @param mixed $value Value * @return boolean */ - public function offsetSet($obj, $value) { + public function offsetSet($obj, $value) + { if (!is_array($this->data[$obj])) { $this->data[$obj] = array(); } $this->data[$obj]['value'] = $value; return $this->data[$obj]['value']; - }//end offsetSet() @@ -130,11 +128,9 @@ class ObjectCache implements ArrayAccess { * @param string $obj Name of Data-Object * @return mixed */ - public function offsetUnset($obj) { + public function offsetUnset($obj) + { unset($this->data[$obj]['value']); return true; - }//end offsetUnset() - - }//end class diff --git a/LibreNMS/Proc.php b/LibreNMS/Proc.php new file mode 100644 index 0000000000..a588fdbf18 --- /dev/null +++ b/LibreNMS/Proc.php @@ -0,0 +1,237 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2016 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS; + +use Exception; + +class Proc +{ + /** + * @var resource the process this object is responsible for + */ + private $_process; + /** + * @var array array of process pipes [stdin,stdout,stderr] + */ + private $_pipes; + + /** + * @var bool if this process is synchronous (waits for output) + */ + private $_synchronous; + + /** + * Create and run a new process + * Most arguments match proc_open() + * + * @param string $cmd the command to execute + * @param array $descriptorspec the definition of pipes to initialize + * @param null $cwd working directory to change to + * @param array|null $env array of environment variables to set + * @param bool $blocking set the output pipes to blocking (default: false) + * @throws Exception the command was unable to execute + */ + public function __construct($cmd, $descriptorspec, $cwd = null, $env = null, $blocking = false) + { + $this->_process = proc_open($cmd, $descriptorspec, $this->_pipes, $cwd, $env); + if (!is_resource($this->_process)) { + throw new Exception("Command failed: $cmd"); + } + stream_set_blocking($this->_pipes[1], $blocking); + stream_set_blocking($this->_pipes[2], $blocking); + $this->_synchronous = true; + } + + /** + * Called when this object goes out of scope or php exits + * If it is still running, terminate the process + */ + public function __destruct() + { + if ($this->isRunning()) { + $this->terminate(); + } + } + + /** + * Get one of the pipes + * 0 - stdin + * 1 - stdout + * 2 - stderr + * + * @param int $nr pipe number (0-2) + * @return resource the pipe handle + */ + public function pipe($nr) + { + return $this->_pipes[$nr]; + } + + + /** + * Send a command to this process and return the output + * the output may not correspond to this command if this + * process is not synchronous + * If the command isn't terminated with a newline, add one + * + * @param $command + * @return array + */ + public function sendCommand($command) + { + if (!ends_with($command, PHP_EOL)) { + $command .= PHP_EOL; + } + $this->sendInput($command); + + return $this->getOutput(); + } + + /** + * Send data to stdin + * + * @param string $data the string to send + */ + public function sendInput($data) + { + fwrite($this->_pipes[0], $data); + } + + /** + * Gets the current output of the process + * If this process is set to synchronous, wait for output + * + * @param int $timeout time to wait for output, only applies if this process is synchronous + * @return array [stdout, stderr] + */ + public function getOutput($timeout = 15) + { + if ($this->_synchronous) { + $pipes = array($this->_pipes[1], $this->_pipes[2]); + $w = null; + $x = null; + + stream_select($pipes, $w, $x, $timeout); + } + return array(stream_get_contents($this->_pipes[1]), stream_get_contents($this->_pipes[2])); + } + + /** + * Attempt to gracefully close this process + * optionally send one last piece of input + * such as a quit command + * + * @param string $cmd the final command to send + * @return int the exit status of this process (-1 means error) + */ + public function close($cmd = null) + { + if (isset($cmd)) { + $this->sendInput($cmd); + } + + fclose($this->_pipes[0]); + fclose($this->_pipes[1]); + fclose($this->_pipes[2]); + + return proc_close($this->_process); + } + + /** + * Forcibly close this process + * Please attempt to run close() instead of this + * This will be called when this object is destroyed if the process is still running + * + * @param int $signal the signal to send + * @throws Exception + */ + public function terminate($signal = 15) + { + $status = $this->getStatus(); + + fclose($this->_pipes[1]); + fclose($this->_pipes[2]); + + $closed = proc_terminate($this->_process, $signal); + + if (!$closed) { + // try harder + $pid = $status['pid']; + $killed = posix_kill($pid, 9); //9 is the SIGKILL signal + proc_close($this->_process); + + if (!$killed) { + throw new Exception("Terminate failed!"); + } + } + } + + /** + * Get the status of this process + * see proc_get_status() + * + * @return array status array + */ + public function getStatus() + { + return proc_get_status($this->_process); + } + + /** + * Check if this process is running + * + * @return bool + */ + public function isRunning() + { + if (!is_resource($this->_process)) { + return false; + } + $st = $this->getStatus(); + return isset($st['running']); + } + + /** + * If this process waits for output + * @return boolean + */ + public function isSynchronous() + { + return $this->_synchronous; + } + + /** + * Set this process as synchronous, by default processes are synchronous + * It is advisable not to change this mid way as output could get mixed up + * or you could end up blocking until the getOutput timeout expires + * + * @param boolean $synchronous + */ + public function setSynchronous($synchronous) + { + $this->_synchronous = $synchronous; + } +} diff --git a/LibreNMS/RRDRecursiveFilterIterator.php b/LibreNMS/RRDRecursiveFilterIterator.php index ef038fe313..527b2f60ee 100644 --- a/LibreNMS/RRDRecursiveFilterIterator.php +++ b/LibreNMS/RRDRecursiveFilterIterator.php @@ -31,9 +31,11 @@ namespace LibreNMS; * @method boolean isDir() * **/ -class RRDRecursiveFilterIterator extends \RecursiveFilterIterator { +class RRDRecursiveFilterIterator extends \RecursiveFilterIterator +{ - public function accept() { + public function accept() + { $filename = $this->current()->getFilename(); if ($filename[0] === '.') { // Ignore hidden files and directories diff --git a/addhost.php b/addhost.php index ed33b148d8..329ecb960f 100755 --- a/addhost.php +++ b/addhost.php @@ -45,12 +45,12 @@ if (isset($options['f']) && $options['f'] == 0) { } $port_assoc_mode = $config['default_port_association_mode']; -$valid_assoc_modes = get_port_assoc_modes (); -if (isset ($options['p'])) { +$valid_assoc_modes = get_port_assoc_modes(); +if (isset($options['p'])) { $port_assoc_mode = $options['p']; - if (! in_array ($port_assoc_mode, $valid_assoc_modes)) { + if (! in_array($port_assoc_mode, $valid_assoc_modes)) { echo "Invalid port association mode '" . $port_assoc_mode . "'\n"; - echo 'Valid modes: ' . join (', ', $valid_assoc_modes) . "\n"; + echo 'Valid modes: ' . join(', ', $valid_assoc_modes) . "\n"; exit(1); } @@ -178,14 +178,13 @@ if (!empty($argv[1])) { echo " $reason\n"; } exit(2); - } catch (Exception $e){ + } catch (Exception $e) { print_error($e->getMessage()); exit(3); } } else { - c_echo( - "\n".$config['project_name_version'].' Add Host Tool + "\n".$config['project_name_version'].' Add Host Tool Usage (SNMPv1/2c): ./addhost.php [-g ] [-f] [-p ] <%Whostname%n> [community] [v1|v2c] [port] ['.implode('|', $config['snmp']['transports']).'] Usage (SNMPv3) : Config Defaults : ./addhost.php [-g ] [-f] [-p ] <%Whostname%n> any v3 [user] [port] ['.implode('|', $config['snmp']['transports']).'] @@ -198,7 +197,7 @@ if (!empty($argv[1])) { -p allow you to set a port association mode for this device. By default ports are associated by \'ifIndex\'. For Linux/Unix based devices \'ifName\' or \'ifDescr\' might be useful for a stable iface mapping. The default for this installation is \'' . $config['default_port_association_mode'] . '\' - Valid port assoc modes are: ' . join (', ', $valid_assoc_modes) . ' + Valid port assoc modes are: ' . join(', ', $valid_assoc_modes) . ' %rRemember to run discovery for the host afterwards.%n ' diff --git a/adduser.php b/adduser.php index 21f368d755..d456cf8ce5 100755 --- a/adduser.php +++ b/adduser.php @@ -22,8 +22,7 @@ require 'includes/functions.php'; if (file_exists('html/includes/authentication/'.$config['auth_mechanism'].'.inc.php')) { include 'html/includes/authentication/'.$config['auth_mechanism'].'.inc.php'; -} -else { +} else { echo "ERROR: no valid auth_mechanism defined.\n"; exit(); } @@ -34,15 +33,12 @@ if (auth_usermanagement()) { if (adduser($argv[1], $argv[2], $argv[3], @$argv[4])) { echo 'User '.$argv[1]." added successfully\n"; } - } - else { + } else { echo 'User '.$argv[1]." already exists!\n"; } - } - else { + } else { echo "Add User Tool\nUsage: ./adduser.php [email]\n"; } -} -else { +} else { echo "Auth module does not allow adding users!\n"; }//end if diff --git a/alerts.php b/alerts.php index 185ff1047b..143a6fcb0c 100755 --- a/alerts.php +++ b/alerts.php @@ -41,8 +41,7 @@ if (file_exists($config['install_dir'].'/.alerts.lock')) { if ($lock === true) { exit(1); -} -else { +} else { file_put_contents($config['install_dir'].'/.alerts.lock', getmypid()); } @@ -57,8 +56,7 @@ if (isset($options['d'])) { ini_set('display_startup_errors', 1); ini_set('log_errors', 1); ini_set('error_reporting', 1); -} -else { +} else { $debug = false; // ini_set('display_errors', 0); ini_set('display_startup_errors', 0); @@ -86,7 +84,8 @@ unlink($config['install_dir'].'/.alerts.lock'); * @param integer $rule Rule-ID * @return boolean */ -function IsRuleValid($device, $rule) { +function IsRuleValid($device, $rule) +{ global $rulescache; if (empty($rulescache[$device]) || !isset($rulescache[$device])) { foreach (GetRules($device) as $chk) { @@ -99,7 +98,6 @@ function IsRuleValid($device, $rule) { } return false; - }//end IsRuleValid() @@ -108,7 +106,8 @@ function IsRuleValid($device, $rule) { * @param array $alert * @return boolean */ -function IssueAlert($alert) { +function IssueAlert($alert) +{ global $config; if (dbFetchCell('SELECT attrib_value FROM devices_attribs WHERE attrib_type = "disable_notify" && device_id = ?', array($alert['device_id'])) == '1') { return true; @@ -129,7 +128,6 @@ function IssueAlert($alert) { } return true; - }//end IssueAlert() @@ -137,7 +135,8 @@ function IssueAlert($alert) { * Issue ACK notification * @return void */ -function RunAcks() { +function RunAcks() +{ foreach (dbFetchRows('SELECT alerts.device_id, alerts.rule_id, alerts.state FROM alerts WHERE alerts.state = 2 && alerts.open = 1') as $alert) { $tmp = array( $alert['rule_id'], @@ -156,7 +155,6 @@ function RunAcks() { IssueAlert($alert); dbUpdate(array('open' => 0), 'alerts', 'rule_id = ? && device_id = ?', array($alert['rule_id'], $alert['device_id'])); } - }//end RunAcks() @@ -164,7 +162,8 @@ function RunAcks() { * Run Follow-Up alerts * @return void */ -function RunFollowUp() { +function RunFollowUp() +{ global $config; foreach (dbFetchRows('SELECT alerts.device_id, alerts.rule_id, alerts.state FROM alerts WHERE alerts.state != 2 && alerts.state > 0 && alerts.open = 0') as $alert) { $tmp = array( @@ -193,12 +192,11 @@ function RunFollowUp() { if ($n > $o) { $ret .= ' Worsens'; $state = 3; - $alert['details']['diff'] = array_diff($chk,$alert['details']['rule']); - } - elseif ($n < $o) { + $alert['details']['diff'] = array_diff($chk, $alert['details']['rule']); + } elseif ($n < $o) { $ret .= ' Betters'; $state = 4; - $alert['details']['diff'] = array_diff($alert['details']['rule'],$chk); + $alert['details']['diff'] = array_diff($alert['details']['rule'], $chk); } if ($state > 0 && $n > 0) { @@ -210,7 +208,6 @@ function RunFollowUp() { echo $ret.' ('.$o.'/'.$n.")\r\n"; } }//end foreach - }//end RunFollowUp() @@ -218,7 +215,8 @@ function RunFollowUp() { * Run all alerts * @return void */ -function RunAlerts() { +function RunAlerts() +{ global $config; foreach (dbFetchRows('SELECT alerts.device_id, alerts.rule_id, alerts.state FROM alerts WHERE alerts.state != 2 && alerts.open = 1') as $alert) { $tmp = array( @@ -248,8 +246,7 @@ function RunAlerts() { if (!empty($rextra['delay'])) { if ((time() - strtotime($alert['time_logged']) + $config['alert']['tolerance_window']) < $rextra['delay'] || (!empty($alert['details']['delay']) && (time() - $alert['details']['delay'] + $config['alert']['tolerance_window']) < $rextra['delay'])) { continue; - } - else { + } else { $alert['details']['delay'] = time(); $updet = true; } @@ -263,8 +260,7 @@ function RunAlerts() { $updet = true; $noiss = false; } - } - else { + } else { // This is the new way if (!empty($rextra['delay']) && (time() - strtotime($alert['time_logged']) + $config['alert']['tolerance_window']) < $rextra['delay']) { continue; @@ -273,8 +269,7 @@ function RunAlerts() { if (!empty($rextra['interval'])) { if (!empty($alert['details']['interval']) && (time() - $alert['details']['interval'] + $config['alert']['tolerance_window']) < $rextra['interval']) { continue; - } - else { + } else { $alert['details']['interval'] = time(); $updet = true; } @@ -318,7 +313,6 @@ function RunAlerts() { dbUpdate(array('open' => 0), 'alerts', 'rule_id = ? && device_id = ?', array($alert['rule_id'], $alert['device_id'])); } }//end foreach - }//end RunAlerts() @@ -327,7 +321,8 @@ function RunAlerts() { * @param array $obj Alert-Array * @return void */ -function ExtTransports($obj) { +function ExtTransports($obj) +{ global $config; $tmp = false; // To keep scrutinizer from naging because it doesnt understand eval @@ -348,12 +343,10 @@ function ExtTransports($obj) { if ($tmp === true) { echo 'OK'; log_event('Issued '.$prefix[$obj['state']]." for rule '".$obj['name']."' to transport '".$transport."'", $obj['device_id']); - } - elseif ($tmp === false) { + } elseif ($tmp === false) { echo 'ERROR'; log_event('Could not issue '.$prefix[$obj['state']]." for rule '".$obj['name']."' to transport '".$transport."'", $obj['device_id']); - } - else { + } else { echo 'ERROR: '.$tmp."\r\n"; log_event('Could not issue '.$prefix[$obj['state']]." for rule '".$obj['name']."' to transport '".$transport."' Error: ".$tmp, $obj['device_id']); } @@ -361,7 +354,6 @@ function ExtTransports($obj) { echo '; '; } - }//end ExtTransports() @@ -370,7 +362,8 @@ function ExtTransports($obj) { * @param array $obj Alert-Array * @return string */ -function FormatAlertTpl($obj) { +function FormatAlertTpl($obj) +{ $tpl = $obj["template"]; $msg = '$ret .= "'.str_replace(array('{else}', '{/if}', '{/foreach}'), array('"; } else { $ret .= "', '"; } $ret .= "', '"; } $ret .= "'), addslashes($tpl)).'";'; $parsed = $msg; @@ -381,23 +374,19 @@ function FormatAlertTpl($obj) { while (++$x < $s) { if ($msg[$x] == '{' && $buff == '') { $buff .= $msg[$x]; - } - elseif ($buff == '{ ') { + } elseif ($buff == '{ ') { $buff = ''; - } - elseif ($buff != '') { + } elseif ($buff != '') { $buff .= $msg[$x]; } if ($buff == '{if') { $pos = $x; $if = true; - } - elseif ($buff == '{foreach') { + } elseif ($buff == '{foreach') { $pos = $x; $for = true; - } - elseif ($buff == '{calc') { + } elseif ($buff == '{calc') { $pos = $x; $calc = true; } @@ -413,24 +402,21 @@ function FormatAlertTpl($obj) { '"; if( ', ' ) { $ret .= "', ); - } - elseif ($for) { + } elseif ($for) { $for = false; $o = 8; $native = array( '"; foreach( ', ' as $key=>$value) { $ret .= "', ); - } - elseif ($calc) { + } elseif ($calc) { $calc = false; $o = 5; $native = array( '"; $ret .= (float) (0+(', ')); $ret .= "', ); - } - else { + } else { continue; } @@ -443,7 +429,6 @@ function FormatAlertTpl($obj) { $parsed = populate($parsed); return RunJail($parsed, $obj); - }//end FormatAlertTpl() @@ -452,7 +437,8 @@ function FormatAlertTpl($obj) { * @param array $alert Alert-Result from DB * @return array */ -function DescribeAlert($alert) { +function DescribeAlert($alert) +{ $obj = array(); $i = 0; $device = dbFetchRow('SELECT hostname, sysName, location, uptime FROM devices WHERE device_id = ?', array($alert['device_id'])); @@ -472,17 +458,14 @@ function DescribeAlert($alert) { if ($alert['state'] >= 1) { if (!empty($tpl['title'])) { $obj['title'] = $tpl['title']; - } - else { + } else { $obj['title'] = 'Alert for device '.$device['hostname'].' - '.($alert['name'] ? $alert['name'] : $alert['rule']); } if ($alert['state'] == 2) { $obj['title'] .= ' got acknowledged'; - } - elseif ($alert['state'] == 3) { + } elseif ($alert['state'] == 3) { $obj['title'] .= ' got worse'; - } - elseif ($alert['state'] == 4) { + } elseif ($alert['state'] == 4) { $obj['title'] .= ' got better'; } @@ -496,11 +479,10 @@ function DescribeAlert($alert) { } } $obj['elapsed'] = TimeFormat(time() - strtotime($alert['time_logged'])); - if( !empty($extra['diff']) ) { + if (!empty($extra['diff'])) { $obj['diff'] = $extra['diff']; } - } - elseif ($alert['state'] == 0) { + } elseif ($alert['state'] == 0) { $id = dbFetchRow('SELECT alert_log.id,alert_log.time_logged,alert_log.details FROM alert_log WHERE alert_log.state != 2 && alert_log.state != 0 && alert_log.rule_id = ? && alert_log.device_id = ? && alert_log.id < ? ORDER BY id DESC LIMIT 1', array($alert['rule_id'], $alert['device_id'], $alert['id'])); if (empty($id['id'])) { return false; @@ -509,15 +491,13 @@ function DescribeAlert($alert) { $extra = json_decode(gzuncompress($id['details']), true); if (!empty($tpl['title_rec'])) { $obj['title'] = $tpl['title_rec']; - } - else { + } else { $obj['title'] = 'Device '.$device['hostname'].' recovered from '.($alert['name'] ? $alert['name'] : $alert['rule']); } $obj['elapsed'] = TimeFormat(strtotime($alert['time_logged']) - strtotime($id['time_logged'])); $obj['id'] = $id['id']; $obj['faults'] = false; - } - else { + } else { return 'Unknown State'; }//end if $obj['uid'] = $alert['id']; @@ -527,11 +507,10 @@ function DescribeAlert($alert) { $obj['timestamp'] = $alert['time_logged']; $obj['contacts'] = $extra['contacts']; $obj['state'] = $alert['state']; - if (strstr($obj['title'],'%')) { + if (strstr($obj['title'], '%')) { $obj['title'] = RunJail('$ret = "'.populate(addslashes($obj['title'])).'";', $obj); } return $obj; - }//end DescribeAlert() @@ -540,7 +519,8 @@ function DescribeAlert($alert) { * @param integer $secs Seconds elapsed * @return string */ -function TimeFormat($secs) { +function TimeFormat($secs) +{ $bit = array( 'y' => $secs / 31556926 % 12, 'w' => $secs / 604800 % 52, @@ -561,7 +541,6 @@ function TimeFormat($secs) { } return join(' ', $ret); - }//end TimeFormat() @@ -571,11 +550,11 @@ function TimeFormat($secs) { * @param array $obj Object with variables * @return string|mixed */ -function RunJail($code, $obj) { +function RunJail($code, $obj) +{ $ret = ''; eval($code); return $ret; - }//end RunJail() @@ -585,21 +564,20 @@ function RunJail($code, $obj) { * @param boolean $wrap Wrap variable for text-usage (default: true) * @return string */ -function populate($txt, $wrap=true) { +function populate($txt, $wrap = true) +{ preg_match_all('/%([\w\.]+)/', $txt, $m); foreach ($m[1] as $tmp) { $orig = $tmp; $rep = false; if ($tmp == 'key' || $tmp == 'value') { $rep = '$'.$tmp; - } - else { + } else { if (strstr($tmp, '.')) { $tmp = explode('.', $tmp, 2); $pre = '$'.$tmp[0]; $tmp = $tmp[1]; - } - else { + } else { $pre = '$obj'; } @@ -613,5 +591,4 @@ function populate($txt, $wrap=true) { }//end foreach return $txt; - }//end populate() diff --git a/billing-calculate.php b/billing-calculate.php index e89e65675a..5ad73352a7 100755 --- a/billing-calculate.php +++ b/billing-calculate.php @@ -60,8 +60,7 @@ foreach (dbFetchRows('SELECT * FROM `bills` ORDER BY `bill_id`') as $bill) { $overuse = ($used - $allowed); $overuse = (($overuse <= 0) ? '0' : $overuse); $percent = round((($rate_data['rate_95th'] / $bill['bill_cdr']) * 100), 2); - } - else if ($bill['bill_type'] == 'quota') { + } elseif ($bill['bill_type'] == 'quota') { $type = 'Quota'; $allowed = $bill['bill_quota']; $used = $rate_data['total_data']; @@ -113,8 +112,7 @@ foreach (dbFetchRows('SELECT * FROM `bills` ORDER BY `bill_id`') as $bill) { dbUpdate($update, 'bill_history', '`bill_hist_id` = ?', array($check['bill_hist_id'])); echo ' Updated history! '; - } - else { + } else { $update = array( 'rate_95th' => $rate_data['rate_95th'], 'rate_95th_in' => $rate_data['rate_95th_in'], diff --git a/build-base.php b/build-base.php index c6135a12c8..3256594a8f 100644 --- a/build-base.php +++ b/build-base.php @@ -29,12 +29,11 @@ if ($select === false) { $limit = 0; while (!feof($sql_fh)) { $line = fgetss($sql_fh); - if (isset($_SESSION['stage']) ) { + if (isset($_SESSION['stage'])) { $limit++; if (isset($_SESSION['offset']) && $limit < $_REQUEST['offset']) { continue; - } - elseif ( time()-$_SESSION['last'] > 45 ) { + } elseif (time()-$_SESSION['last'] > 45) { $_SESSION['offset'] = $limit; $GLOBALS['refresh'] = 'Installing, please wait..'.date('r').''; return; diff --git a/check-services.php b/check-services.php index e418c8d385..ee2ab28a64 100755 --- a/check-services.php +++ b/check-services.php @@ -51,6 +51,5 @@ rrdtool_initialize(); foreach (dbFetchRows('SELECT * FROM `devices` AS D, `services` AS S WHERE S.device_id = D.device_id ORDER by D.device_id DESC') as $service) { // Run the polling function poll_service($service); - } //end foreach -rrdtool_terminate(); +rrdtool_close(); diff --git a/composer.json b/composer.json index 2dd4acf45c..a93df0564a 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,9 @@ { - "require": { - "squizlabs/php_codesniffer": "*" - } + "require-dev": { + "squizlabs/php_codesniffer": "*", + "phpunit/phpunit": "4.*", + "jakub-onderka/php-parallel-lint": "*", + "jakub-onderka/php-console-highlighter": "*", + "fojuth/readmegen": "1.*" + } } diff --git a/config.php.default b/config.php.default index c8ac44a2bf..3332ccb7d9 100755 --- a/config.php.default +++ b/config.php.default @@ -9,21 +9,13 @@ $config['db_pass'] = 'PASSWORD'; $config['db_name'] = 'librenms'; $config['db']['extension'] = 'mysqli';// mysql or mysqli -### Memcached config - We use this to store realtime usage -$config['memcached']['enable'] = FALSE; -$config['memcached']['host'] = 'localhost'; -$config['memcached']['port'] = 11211; - // This is the user LibreNMS will run as //Please ensure this user is created and has the correct permissions to your install $config['user'] = 'librenms'; -### Locations - it is recommended to keep the default -#$config['install_dir'] = "/opt/librenms"; - ### This should *only* be set if you want to *force* a particular hostname/port ### It will prevent the web interface being usable form any other hostname -#$config['base_url'] = "http://librenms.company.com"; +$config['base_url'] = "/"; ### Enable this to use rrdcached. Be sure rrd_dir is within the rrdcached dir ### and that your web server has permission to talk to rrdcached. @@ -41,9 +33,6 @@ $config['auth_mechanism'] = "mysql"; # default, other options: ldap, http-auth #$config['nets'][] = "172.16.0.0/12"; #$config['nets'][] = "192.168.0.0/16"; -# following is necessary for poller-wrapper -# poller-wrapper is released public domain -$config['poller-wrapper']['alerter'] = FALSE; # Uncomment the next line to disable daily updates #$config['update'] = 0; @@ -55,3 +44,9 @@ $config['rrd_purge'] = 0; # Set default port association mode for new devices (default: ifIndex) #$config['default_port_association_mode'] = 'ifIndex'; + +# Enable the in-built billing extension +$config['enable_billing'] = 1; + +# Enable the in-built services support (Nagios plugins) +$config['show_services'] = 1; diff --git a/config_to_json.php b/config_to_json.php index 5d5b0a4d79..789e3b9686 100644 --- a/config_to_json.php +++ b/config_to_json.php @@ -12,14 +12,13 @@ $config_file = 'config.php'; // move to install dir chdir(dirname($argv[0])); -function iscli() { +function iscli() +{ if (php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR'])) { return true; - } - else { + } else { return false; } - } // check if we are running through the CLI, otherwise abort diff --git a/daily.php b/daily.php index 4f3292ec8a..a18d4525d6 100644 --- a/daily.php +++ b/daily.php @@ -24,8 +24,7 @@ if ($options['f'] === 'update') { if ($config['update_channel'] == 'master') { exit(1); - } - elseif ($config['update_channel'] == 'release') { + } elseif ($config['update_channel'] == 'release') { exit(3); } exit(0); @@ -54,8 +53,7 @@ if ($options['f'] === 'syslog') { if (dbDelete('syslog', 'seq >= ? AND seq < ? AND timestamp < DATE_SUB(NOW(), INTERVAL ? DAY)', array($rows, $limit, $config['syslog_purge'])) > 0) { $rows = $limit; echo 'Syslog cleared for entries over '.$config['syslog_purge']." days 1000 limit\n"; - } - else { + } else { break; } } @@ -145,8 +143,8 @@ if ($options['f'] === 'purgeusers') { foreach (dbFetchRows("SELECT DISTINCT(`user`) FROM `authlog` WHERE `datetime` >= DATE_SUB(NOW(), INTERVAL ? DAY)", array($purge)) as $user) { $users[] = $user['user']; } - $del_users = '"'.implode('","',$users).'"'; - if (dbDelete('users', "username NOT IN ($del_users)",array($del_users))) { + $del_users = '"'.implode('","', $users).'"'; + if (dbDelete('users', "username NOT IN ($del_users)", array($del_users))) { echo "Removed users that haven't logged in for $purge days"; } } diff --git a/delhost.php b/delhost.php index 38ea772ad4..b45009844b 100755 --- a/delhost.php +++ b/delhost.php @@ -25,11 +25,9 @@ if ($argv[1]) { $id = getidbyname($host); if ($id) { echo delete_device($id)."\n"; - } - else { + } else { echo "Host doesn't exist!\n"; } -} -else { +} else { echo "Host Removal Tool\nUsage: ./delhost.php \n"; } diff --git a/discovery.php b/discovery.php index 86f3c11567..bafd95adc2 100755 --- a/discovery.php +++ b/discovery.php @@ -23,7 +23,7 @@ require 'includes/discovery/functions.inc.php'; $start = microtime(true); $runtime_stats = array(); $sqlparams = array(); -$options = getopt('h:m:i:n:d::v::a::q',array('os:','type:')); +$options = getopt('h:m:i:n:d::v::a::q', array('os:','type:')); if (!isset($options['q'])) { echo $config['project_name_version']." Discovery\n"; @@ -42,25 +42,20 @@ if (isset($options['h'])) { if ($options['h'] == 'odd') { $options['n'] = '1'; $options['i'] = '2'; - } - else if ($options['h'] == 'even') { + } elseif ($options['h'] == 'even') { $options['n'] = '0'; $options['i'] = '2'; - } - else if ($options['h'] == 'all') { + } elseif ($options['h'] == 'all') { $where = ' '; $doing = 'all'; - } - else if ($options['h'] == 'new') { + } elseif ($options['h'] == 'new') { $where = 'AND `last_discovered` IS NULL'; $doing = 'new'; - } - else if ($options['h']) { + } elseif ($options['h']) { if (is_numeric($options['h'])) { $where = "AND `device_id` = '".$options['h']."'"; $doing = $options['h']; - } - else { + } else { $where = "AND `hostname` LIKE '".str_replace('*', '%', mres($options['h']))."'"; $doing = $options['h']; } @@ -92,8 +87,7 @@ if (isset($options['d']) || isset($options['v'])) { ini_set('display_startup_errors', 1); ini_set('log_errors', 1); ini_set('error_reporting', 1); -} -else { +} else { $debug = false; // ini_set('display_errors', 0); ini_set('display_startup_errors', 0); @@ -129,7 +123,7 @@ if (!empty($config['distributed_poller_group'])) { $where .= ' AND poller_group IN('.$config['distributed_poller_group'].')'; } -foreach (dbFetch("SELECT * FROM `devices` WHERE status = 1 AND disabled = 0 $where ORDER BY device_id DESC",$sqlparams) as $device) { +foreach (dbFetch("SELECT * FROM `devices` WHERE status = 1 AND disabled = 0 $where ORDER BY device_id DESC", $sqlparams) as $device) { discover_device($device, $options); } diff --git a/dist-pollers.php b/dist-pollers.php index e3f016af4d..24f314a32c 100755 --- a/dist-pollers.php +++ b/dist-pollers.php @@ -21,7 +21,6 @@ require 'includes/definitions.inc.php'; require 'includes/functions.php'; require 'includes/polling/functions.inc.php'; require 'includes/alerts.inc.php'; -require 'includes/console_table.php'; $options = getopt('l:u:r::'); @@ -34,8 +33,7 @@ if (isset($options['l'])) { } echo $tbl->getTable(); - } - else if ($options['l'] == 'groups') { + } elseif ($options['l'] == 'groups') { $tbl = new Console_Table(); $tbl->setHeaders(array('ID', 'Group Name', 'Description')); foreach (dbFetchRows('SELECT * FROM `poller_groups`') as $groups) { @@ -44,25 +42,21 @@ if (isset($options['l'])) { echo $tbl->getTable(); } -} -else if (isset($options['u']) && !empty($options['u'])) { +} elseif (isset($options['u']) && !empty($options['u'])) { if (is_numeric($options['u'])) { $db_column = 'id'; - } - else { + } else { $db_column = 'poller_name'; } if (dbDelete('pollers', "`$db_column` = ?", array($options['u'])) >= 0) { echo 'Poller '.$options['u']." has been removed\n"; } -} -else if (isset($options['r'])) { +} elseif (isset($options['r'])) { if (dbInsert(array('poller_name' => $config['distributed_poller_name'], 'last_polled' => '0000-00-00 00:00:00', 'devices' => 0, 'time_taken' => 0), 'pollers') >= 0) { echo 'Poller '.$config['distributed_poller_name']." has been registered\n"; } -} -else { +} else { echo "-l pollers | groups List registered pollers or poller groups\n"; echo "-u | Unregister a poller\n"; echo "-r Register this install as a poller\n"; diff --git a/doc/API/API-Docs.md b/doc/API/API-Docs.md index 1afa98fe03..320c434285 100644 --- a/doc/API/API-Docs.md +++ b/doc/API/API-Docs.md @@ -52,6 +52,10 @@ source: API/API-Docs.md - [`get_bill`](#api-route-23) - [`resources`](#api-resources) - [`list_arp`](#api-resources-list_arp) + - [`services`](#api-services) + - [`list_services`](#api-services-list_services) + - [`get_service_for_host`](#api-services-get_service_for_host) + Describes the API structure. # `Structure` [`top`](#top) @@ -786,56 +790,19 @@ Output: ```text [ { - "status": "error", - "message": "Found 1 in group LinuxServers", - "count": 1, + "status": "ok", + "message": "Found 3 in group LinuxServers", + "count": 3, "devices": [ - { - "device_id": "1", - "hostname": "localhost", - "sysName": "hostname", - "community": "librenms", - "authlevel": null, - "authname": null, - "authpass": null, - "authalgo": null, - "cryptopass": null, - "cryptoalgo": null, - "snmpver": "v2c", - "port": "161", - "transport": "udp", - "timeout": null, - "retries": null, - "bgpLocalAs": null, - "sysObjectID": ".1.3.6.1.4.1.8072.3.2.10", - "sysDescr": "Linux li1045-133.members.linode.com 4.1.5-x86_64-linode61 #7 SMP Mon Aug 24 13:46:31 EDT 2015 x86_64", - "sysContact": "", - "version": "4.1.5-x86_64-linode61", - "hardware": "Generic x86 64-bit", - "features": "CentOS 7.1.1503", - "location": "", - "os": "linux", - "status": "1", - "status_reason": "", - "ignore": "0", - "disabled": "0", - "uptime": "4615964", - "agent_uptime": "0", - "last_polled": "2015-12-12 13:20:04", - "last_poll_attempted": null, - "last_polled_timetaken": "1.90", - "last_discovered_timetaken": "79.53", - "last_discovered": "2015-12-12 12:34:21", - "last_ping": "2015-12-12 13:20:04", - "last_ping_timetaken": "0.08", - "purpose": null, - "type": "server", - "serial": null, - "icon": null, - "poller_group": "0", - "override_sysLocation": "0", - "notes": "Nope" - } + { + "device_id": "15" + }, + { + "device_id": "18" + }, + { + "device_id": "20" + } ] } ] @@ -1440,3 +1407,110 @@ Output: ] } ``` + +### Function: `list_services` [`top`](#top) + +Retrieve all services + +Route: /api/v0/services + +Input: + + - state: only which have a certain state (valid options are 0=Ok, 1=Warning, 2=Critical). + - type: service type, used sql LIKE to find services, so for tcp, use type=tcp for http use type=http + +Example: +```curl +curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/services +curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/services?state=2 +curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/services?state=0&type=tcp +``` + +Output: +```text +{ + "status": "ok", + "err-msg": "", + "count": 1, + "services": [ + [ + { + "service_id": "13", + "device_id": "1", + "service_ip": "demo1.yourdomian.net", + "service_type": "ntp_peer", + "service_desc": "NTP", + "service_param": "-H 192.168.1.10", + "service_ignore": "0", + "service_status": "0", + "service_changed": "1470962470", + "service_message": "NTP OK: Offset -0.000717 secs", + "service_disabled": "0", + "service_ds": "{\"offset\":\"s\"}" + } + ], + [ + { + "service_id": "2", + "device_id": "2", + "service_ip": "demo2.yourdomian.net", + "service_type": "esxi_hardware.py", + "service_desc": "vmware hardware", + "service_param": "-H 192.168.1.11 -U USER -P PASS -p", + "service_ignore": "0", + "service_status": "0", + "service_changed": "1471702206", + "service_message": "OK - Server: Supermicro X9SCL/X9SCM s/n: 0123456789 System BIOS: 2.2 2015-02-20", + "service_disabled": "0", + "service_ds": "{\"P2Vol_0_Processor_1_Vcore\":\"\",\"P2Vol_1_System_Board_1_-12V\":\"\",\"P2Vol_2_System_Board_1_12V\":\"\",\"P2Vol_3_System_Board_1_3.3VCC\":\"\",\"P2Vol_4_System_Board_1_5VCC\":\"\",\"P2Vol_5_System_Board_1_AVCC\":\"\",\"P2Vol_6_System_Board_1_VBAT\":\"\",\"P2Vol_7_System_Board_1_" + } + ] + ] +} +``` +### Function: `get_service_for_host` [`top`](#top) + +Retrieve services for device + +Route: /api/v0/services/:hostname + + - id or hostname is the specific device + +Input: + + - state: only which have a certain state (valid options are 0=Ok, 1=Warning, 2=Critical). + - type: service type, used sql LIKE to find services, so for tcp, use type=tcp for http use type=http + +Example: +```curl +curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/services/:hostname +curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/services/:hostname?state=2 +curl -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/services/:hostname?state=0&type=tcp +``` + +Output: +```text +{ + "status": "ok", + "err-msg": "", + "count": 1, + "services": [ + [ + { + "service_id": "2", + "device_id": "2", + "service_ip": "demo2.yourdomian.net", + "service_type": "esxi_hardware.py", + "service_desc": "vmware hardware", + "service_param": "-H 192.168.1.11 -U USER -P PASS -p", + "service_ignore": "0", + "service_status": "0", + "service_changed": "1471702206", + "service_message": "OK - Server: Supermicro X9SCL/X9SCM s/n: 0123456789 System BIOS: 2.2 2015-02-20", + "service_disabled": "0", + "service_ds": "{\"P2Vol_0_Processor_1_Vcore\":\"\",\"P2Vol_1_System_Board_1_-12V\":\"\",\"P2Vol_2_System_Board_1_12V\":\"\",\"P2Vol_3_System_Board_1_3.3VCC\":\"\",\"P2Vol_4_System_Board_1_5VCC\":\"\",\"P2Vol_5_System_Board_1_AVCC\":\"\",\"P2Vol_6_System_Board_1_VBAT\":\"\",\"P2Vol_7_System_Board_1_" + } + ] + ] +} +``` diff --git a/doc/Developing/Creating-Release.md b/doc/Developing/Creating-Release.md new file mode 100644 index 0000000000..d53752ec23 --- /dev/null +++ b/doc/Developing/Creating-Release.md @@ -0,0 +1,28 @@ +Developing/Creating-Release.md +# Creating a release + +### GitHub +You can create a new release on [GitHub](https://github.com/librenms/librenms/releases/new). + +Enter the tag version that month, i.e for September 2016 you would enter `201609`. + +Enter a title, we usually use `August 2016 Release` + +Enter a placeholder for the body, we will edit this later. + +### Create changelog +We utilise [Readmegen](https://github.com/fojuth/readmegen) to automatically populate the Changelog. + +Install `readmegen` using `composer`: + +```bash +./composer.phar update +``` + +You can now create the update change log by running (201608 was our last release): + +```bash +./vendor/bin/readmegen --from 201608 --release 201609 +``` + +Now commit and push the change that has been made to `doc\General\Changelog.md` diff --git a/doc/Developing/Merging-Pull-Requests.md b/doc/Developing/Merging-Pull-Requests.md new file mode 100644 index 0000000000..cc5fc27044 --- /dev/null +++ b/doc/Developing/Merging-Pull-Requests.md @@ -0,0 +1,27 @@ +Developing/Merging-Pull-Requests.md +# Merging Pull Requests + +### GitHub +We will now build the monthly change log from our GitHub commits. When merging a commit, please +ensure you: + + - Click the `Merge pull request` button + - Give the merge a descriptive but short title + - For the commit message prepend it with one of the following tags for the pull request to appear in the changelog: + - devices: or newdevice: For new device support. + - feature: or feat: To indicate this is a new or updated feature + - webui: or web: To indicate this is an update to the WebUI + - fix: or bugfix: To show this is a bug fix. + - refactoring: or refactor: When the changes are refactoring a large portion of code + - You can reference an issue number with `#xyz`, i.e `#1234` + - Use the `Confirm squash and merge` button to merge. + +### Example commits + +#### Feature + +feature: Added new availability map #4401 + +#### New device + +newdevice: Added support for Cisco ASA #4402 diff --git a/doc/Developing/Using-Git.md b/doc/Developing/Using-Git.md index 35738285e6..c0dddd3a9e 100644 --- a/doc/Developing/Using-Git.md +++ b/doc/Developing/Using-Git.md @@ -80,11 +80,13 @@ pull request then commit away. ```bash git add path/to/new/files/or/folders git commit -a -m 'Added feature to do X, Y and Z' -git checkout master +git push origin issue-123 +``` + +If you need to rebase against master then you can do this with: + +```bash git pull upstream master -git push origin master -git checkout issue-123 -git pull origin master git push origin issue-123 ``` @@ -97,13 +99,7 @@ Now you will be ready to submit a pull request from within GitHub. To do this, g repo. Now select the branch you have just been working on (issue-123) from the drop down to the left and then click 'Pull Request'. Fill in the details to describe the work you have done and click 'Create pull request'. -Thanks for your first pull request :) Now, that might have been a simple update, if things get a bit more complicated -then you will need to break down your pull request into separate commits (still a single pull request). This is usually -done when: - -- You want to add / update MIBS. Do this in a separate commit including the link to where you got them from. -- You are adding say 3 related features in one go, try and break them down into 3 separate commits. -- Icons for new OS support need to be added as a separate commit including a link to where you got the logo from. +Thanks for your first pull request :) Ok, that should get you started on the contributing path. If you have any other questions then stop by our IRC Channel on Freenode ##librenms. diff --git a/doc/Developing/Validating-Code.md b/doc/Developing/Validating-Code.md new file mode 100644 index 0000000000..885c738f82 --- /dev/null +++ b/doc/Developing/Validating-Code.md @@ -0,0 +1,28 @@ +source: Developing/Validating-Code.md + +As part of the pull request process with GitHub we run some automated build tests to ensure that +the code is error free, standards [compliant](http://docs.librenms.org/Developing/Code-Guidelines/) +and our test suite builds successfully. + +Rather than submit a pull request and wait for the results, you can run these checks yourself to ensure +a more seamless merge. + +> All of these commands should be run from within the librenms directory and can be run as the librenms user +unless otherwise noted. + +Install composer (you can skip this if composer is already installed). + +`curl -sS https://getcomposer.org/installer | php` + +Composer will now be installed into /opt/librenms/composer.phar. + +Now install the dependencies we require: + +`composer install` + +Once composer is installed you can now run the code validation script: + +`./scripts/pre-commit.php` + +If you see `Tests ok, submit away :)` then all is well. If you see other output then it should contain +what you need to resolve the issues and re-test. diff --git a/doc/Extensions/Alerting.md b/doc/Extensions/Alerting.md index 78b6a6f4ba..0e74c1f1a2 100644 --- a/doc/Extensions/Alerting.md +++ b/doc/Extensions/Alerting.md @@ -130,6 +130,18 @@ Placeholders: - Transport name: `%transport` - Contacts, must be iterated in a foreach, `%key` holds email and `%value` holds name: `%contacts` +> NOTE: Placeholder names which are contained within another need to be ordered correctly. As an example: + +```text +Limit: %value.sensor_limit / %value.sensor_limit_low +``` + +Should be done as: + +```text +Limit: %value.sensor_limit_low / %value.sensor_limit +``` + The Default Template is a 'one-size-fit-all'. We highly recommend defining own templates for your rules to include more specific information. Templates can be matched against several rules. diff --git a/doc/Extensions/Applications.md b/doc/Extensions/Applications.md index 54e457a992..bc2361123b 100644 --- a/doc/Extensions/Applications.md +++ b/doc/Extensions/Applications.md @@ -28,7 +28,7 @@ Different applications support a variety of ways collect data: by direct connect ##### SNMP Extend 1. Download the script onto the desired host (the host must be added to LibreNMS devices) ``` -wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/apache-stats.py -o /etc/snmp/apache-stats.py +wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/apache-stats.py -O /etc/snmp/apache-stats.py ``` 2. Make the script executable (chmod +x /etc/snmp/apache-stats.py) 3. Edit your snmpd.conf file (usually /etc/snmp/snmpd.conf) and add: @@ -37,7 +37,7 @@ extend apache /etc/snmp/apache-stats.py ``` 4. Restart snmpd on your host 5. On the device page in Librenms, edit your host and check the `Apache` under the Applications tab. - +(In some cases urlgrabber needs to be installed, in Debian it can be achieved by: apt-get install python-urlgrabber) ### BIND9 aka named @@ -88,7 +88,7 @@ extend dhcpstats /opt/dhcp-status.sh ##### SNMP Extend 1. Download the script onto the desired host (the host must be added to LibreNMS devices) ``` -wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/mailscanner.php -o /etc/snmp/mailscanner.php +wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/mailscanner.php -O /etc/snmp/mailscanner.php ``` 2. Make the script executable (chmod +x /etc/snmp/mailscanner.php) 3. Edit your snmpd.conf file (usually /etc/snmp/snmpd.conf) and add: @@ -158,7 +158,7 @@ Supports NTPD Server (not client, that is separate) ##### SNMP Extend 1. Download the script onto the desired host (the host must be added to LibreNMS devices) ``` -wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/ntpd-server.php -o /etc/snmp/ntpd-server.php +wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/ntpd-server.php -O /etc/snmp/ntpd-server.php ``` 2. Make the script executable (chmod +x /etc/snmp/ntdp-server.php) 3. Edit your snmpd.conf file (usually /etc/snmp/snmpd.conf) and add: @@ -222,7 +222,7 @@ This script uses `rec_control get-all` to collect stats. ### Proxmox 1. Download the script onto the desired host (the host must be added to LibreNMS devices) -`wget https://github.com/librenms/librenms-agent/blob/master/agent-local/proxmox -o /usr/local/bin/proxmox` +`wget https://github.com/librenms/librenms-agent/blob/master/agent-local/proxmox -O /usr/local/bin/proxmox` 2. Make the script executable: `chmod +x /usr/local/proxmox` 3. Edit your snmpd.conf file (usually `/etc/snmp/snmpd.conf`) and add: `extend proxmox /usr/local/bin/proxmox` diff --git a/doc/Extensions/Device-Groups.md b/doc/Extensions/Device-Groups.md index ae2ebe8982..cf10427a2e 100644 --- a/doc/Extensions/Device-Groups.md +++ b/doc/Extensions/Device-Groups.md @@ -9,12 +9,12 @@ Patterns work in the same was as Entities within the alerting system, the format as __tablename.columnname__. If you are ensure of what the entity is you want then have a browse around inside MySQL using `show tables` and `desc `. As a working example and a common question, let's assume you want to group devices by hostname. If you hostname format is dcX.[devicetype].example.com. You would use the pattern -devices.hostname. Select the condition which in this case would Like and then enter `dc1\..*\.example.com`. This would then match dc1.sw01.example.com, dc1.rtr01.example.com but not +`devices.hostname`. Select the condition which in this case would be `Like` and then enter `dc1\..*\.example.com`. This would then match dc1.sw01.example.com, dc1.rtr01.example.com but not dc2.sw01.example.com. #### Wildcards -As with alerts, the `Like` operation allows RegExp. +As with alerts, the `Like` operation allows MySQL Regular expressions. A list of common entities is maintained in our [Alerting docs](http://docs.librenms.org/Extensions/Alerting/#entities). @@ -25,7 +25,7 @@ Please see our [Alerting docs](http://docs.librenms.org/Extensions/Alerting/#syn ### Connection If you only want to group based on one pattern then select And. If however you want to build a group based on multiple patterns then you can build a SQL like -query using And / Or. As an example, we want to base our group on the devices hostname AND it's type. Use the pattern as before, devices.hostname, select the condition which in this case would Like and then enter dc1.@.example.com then click And. Now enter devices.type in the pattern, select Equals and enter firewall. This would then match dc1.fw01.example.com but not dc1.sw01.example.com as that is a network type. +query using And / Or. As an example, we want to base our group on the devices hostname AND it's type. Use the pattern as before, `devices.hostname`, select the condition which in this case would be `Like` and then enter `dc1.@.example.com` then click And. Now enter `devices.type` in the pattern, select `Equals` and enter `firewall`. This would then match dc1.fw01.example.com but not dc1.sw01.example.com as that is a network type. You can now select this group from the Devices -> All Devices link in the navigation at the top. You can also use the group to map alert rules to by creating an alert mapping -Overview -> Alerts -> Rule Mapping. +`Overview -> Alerts -> Rule Mapping`. diff --git a/doc/Extensions/Globe-Frontpage.md b/doc/Extensions/Globe-Frontpage.md index c9f391bfd5..74b29df279 100644 --- a/doc/Extensions/Globe-Frontpage.md +++ b/doc/Extensions/Globe-Frontpage.md @@ -1,23 +1,21 @@ source: Extensions/Globe-Frontpage.md # Globe Frontpage Configuration -LibreNMS comes with a configurable geochart based frontpage to visualize where your gear is located geographically. +LibreNMS comes with a configurable geochart based widget to visualize where your equipment is located geographically. -### Experimental map +### World Map -An new experimental map is available, this requires you to have properly formatted addresses in sysLocation or sysLocation override. As part of the standard poller these addresses will be Geocoded by Google and stored in the database. To enable this please set the following config: +An new map is available, this requires you to have properly formatted addresses in sysLocation or sysLocation override. As part of the standard poller these addresses will be Geocoded by Google and stored in the database. To enable this please set the following config: ```php -$config['front_page'] = "pages/front/map.php"; $config['geoloc']['latlng'] = true; $config['geoloc']['engine'] = "google";//Only one available at present ``` Location resolution happens as follows (when `$config['geoloc']['latlng'] == true;`): - 1. if `device['location']` contains `[lat, lng]` (note the square brackets), that is used - 1. if there is a location overide in the `locations` table where `locations.location == device['location']`, that is used - * currently, no web UI - 1. attempt to resolve lat, lng using `$config['geoloc']['engine']` + 1. If `device['location']` contains `[lat, lng]` (note the square brackets), that is used + 1. If there is a location overide for the device in the WebUI and it contains `[lat, lng]` (note the square brackets), that is used. + 1. Attempt to resolve lat, lng using `$config['geoloc']['engine']` We have two current mapping engines available: @@ -56,13 +54,3 @@ $config['mapael']['default_zoom'] = 20; ``` A list of maps can be found in html/js/maps/ or html/js/mapael-maps/. - -### Standard Globe map - -To enable it, set `$config['front_page'] = "pages/front/globe.php";` in your `config.php`. - -You can use any of these config-parameters to adjust some aspects of it: - -- `$config['frontpage_globe']['markers']` is used to change what is being shown on the Markers of the map. It can be either `devices` or `ports` -- `$config['frontpage_globe']['region']` defines the Region to chart. Any region supported by Google's GeoChart API is allowed (https://developers.google.com/chart/interactive/docs/gallery/geochart#continent-hierarchy-and-codes) -- `$config['frontpage_globe']['resolution']` can be 'countries', 'provinces' or 'metros' (latter two are mostly US only due to google-limits). diff --git a/doc/Extensions/Memcached.md b/doc/Extensions/Memcached.md index 5b852f7d4c..036fd6259d 100644 --- a/doc/Extensions/Memcached.md +++ b/doc/Extensions/Memcached.md @@ -12,6 +12,9 @@ $config['memcached']['port'] = 11211; ``` By default values are kept for 4 Minutes inside the memcached, you can adjust this retention time by modifying the `$config['memcached']['ttl']` value to any desired amount of seconds. + +> This means that you can see what appears to be stale data for up to 4 minutes. If you edit an alert rule for example then those changes may not show immediately. + It's strongly discouraged to set this above `300` (5 Minutes) to avoid interference with the polling, discovery and alerting processes. If you use the Distributed Poller, you can point this to the same memcached instance. However a local memcached will perform better in any case. diff --git a/doc/Extensions/Oxidized.md b/doc/Extensions/Oxidized.md index 29161206c9..cba3b94be5 100644 --- a/doc/Extensions/Oxidized.md +++ b/doc/Extensions/Oxidized.md @@ -57,13 +57,13 @@ LibreNMS is able to reload the Oxidized list of nodes, each time a device is add To do so, edit the option in Global Settings>External Settings>Oxidized Integration or add the following to your config.php. ```php -$config['oxidized']['reload_nodes'] = TRUE; +$config['oxidized']['reload_nodes'] = true; ``` #### Using Groups -To return a group to Oxidized you can do this by matching a regex for either hostname, os or location. The order is hostname is matched first, if nothing is found then os is tried and then location is attempted. +To return a group to Oxidized you can do this by matching a regex for either `hostname`, `os` or `location`. The order is `hostname` is matched first, if nothing is found then `os` is tried and then `location` is attempted. The first match found will be used. To match on the device hostnames that contain 'lon-sw' or if the location contains 'London' then you would place the following within config.php: ```php diff --git a/doc/Extensions/Plugin-System.md b/doc/Extensions/Plugin-System.md index 446422fc6c..b905f8c32d 100644 --- a/doc/Extensions/Plugin-System.md +++ b/doc/Extensions/Plugin-System.md @@ -1,6 +1,8 @@ source: Extensions/Plugin-System.md # Developing for the Plugin System +> This will most likely be deprecated in favour of adding the possible extensions to the core code base. + This documentation will hopefully give you a basis for how to write a plugin for LibreNMS. A test plugin is available on GitHub: https://github.com/laf/Test diff --git a/doc/General/Acknowledgement.md b/doc/General/Acknowledgement.md index 67fb3479ba..d8b80bffcd 100644 --- a/doc/General/Acknowledgement.md +++ b/doc/General/Acknowledgement.md @@ -35,5 +35,3 @@ LibreNMS 3rd party acknowledgements - html/graph-realtime.php: BSD (original?) - html/includes/collectd/: GPLv2 only - overLIB (html/js/overlib_mini.js): modified Artistic 1.0? - - scripts/*/mysql: GPLv2 only - - check_mk (scripts/check_mk*): GPLv2 diff --git a/doc/General/Changelog.md b/doc/General/Changelog.md index 0cfa0b08e1..e5f4d3606d 100644 --- a/doc/General/Changelog.md +++ b/doc/General/Changelog.md @@ -1,4 +1,90 @@ source: General/Changelog.md +### August 2016 + +#### Bug fixes + - WebUI + - Fix Infoblox dhcp messages graph ([PR3898](https://github.com/librenms/librenms/pull/3898)) + - Fix version_info output in Safari ([PR3914](https://github.com/librenms/librenms/pull/3914)) + - Added missing apps to Application page ([PR3964](https://github.com/librenms/librenms/pull/3964)) + - Discovery / Polling + - Clear our stale IPSEC sessions from the DB ([PR3904](https://github.com/librenms/librenms/pull/3904)) + - Fixed some InfluxDB bugs in check-services and ports ([PR4031](https://github.com/librenms/librenms/pull/4031)) + - Fixed Promox and Ceph rrd's ([PR4038](https://github.com/librenms/librenms/pull/4038), [PR4037](https://github.com/librenms/librenms/pull/4037), [PR4047](https://github.com/librenms/librenms/pull/4047), [PR4041](https://github.com/librenms/librenms/pull/4041)) + - Fixed LLDP Remote port in discovery-protocols module ([PR4070](https://github.com/librenms/librenms/pull/4070)) + - Billing + - Check if ifSpeed is returned for calculating billing ([PR3921](https://github.com/librenms/librenms/pull/3921)) + - Applications + - NFS-V3 stats fixed ([PR3963](https://github.com/librenms/librenms/pull/3963)) + - Misc + - Dell Equallogic storage fix ([PR3956](https://github.com/librenms/librenms/pull/3956)) + - Fix syslog bug where entries would log to the wrong device ([PR3996](https://github.com/librenms/librenms/pull/3996)) + +#### Improvements + - Added / improved detection for: + - Cisco WAAS / WAVE ([PR3899](https://github.com/librenms/librenms/pull/3899)) + - Maipu MyPower ([PR3909](https://github.com/librenms/librenms/pull/3909)) + - TPLink Switches ([PR3919](https://github.com/librenms/librenms/pull/3919)) + - Dell N3024 ([PR3941](https://github.com/librenms/librenms/pull/3941)) + - Cisco FXOS ([PR3943](https://github.com/librenms/librenms/pull/3943)) + - Brocade FABOS ([PR3959](https://github.com/librenms/librenms/pull/3959), [PR3988](https://github.com/librenms/librenms/pull/3988)) + - JunOS ([PR3976](https://github.com/librenms/librenms/pull/3976)) + - Dell PowerConnect ([PR3998](https://github.com/librenms/librenms/pull/3998), [PR4007](https://github.com/librenms/librenms/pull/4007)) + - Comware ([PR3967](https://github.com/librenms/librenms/pull/3967)) + - Calix E5 ([PR3864](https://github.com/librenms/librenms/pull/3864)) + - Raisecom ([PR3992](https://github.com/librenms/librenms/pull/3864)) + - Cisco ISE ([PR4063](https://github.com/librenms/librenms/pull/4063)) + - Acano ([PR4064](https://github.com/librenms/librenms/pull/4064)) + - McAfee SIEM Nitro ([PR4066](https://github.com/librenms/librenms/pull/4064)) + - HP Bladesystem C3000/C7000 OA ([PR4035](https://github.com/librenms/librenms/pull/4035)) + - Cisco VCS (Expressway) ([PR4086](https://github.com/librenms/librenms/pull/4086)) + - Cisco Telepresence Conductor ([PR4087](https://github.com/librenms/librenms/pull/4087)) + - Avaya VSP ([PR4048](https://github.com/librenms/librenms/pull/4048)) + - Cisco/Tandberg Video Conferencing ([PR4065](https://github.com/librenms/librenms/pull/4065)) + - Cisco Prime Infrastructure ([PR4088](https://github.com/librenms/librenms/pull/4088)) + - HWGroup STE2 ([PR4116](https://github.com/librenms/librenms/pull/4116)) + - HP 2530 Procurve / Arube ([PR4119](https://github.com/librenms/librenms/pull/4119)) + - Brother Printers ([PR4141](https://github.com/librenms/librenms/pull/4141)) + - Hytera Repeater ([PR4163](https://github.com/librenms/librenms/pull/4163)) + - Sonus ([PR4176](https://github.com/librenms/librenms/pull/4176)) + - Freeswitch ([PR4203](https://github.com/librenms/librenms/pull/4203)) + - WebUI + - Improved OSPF display ([PR3908](https://github.com/librenms/librenms/pull/3908)) + - Improved Apps overview page ([PR3954](https://github.com/librenms/librenms/pull/3954)) + - Improved Syslog page ([PR3955](https://github.com/librenms/librenms/pull/3955), [PR3971](https://github.com/librenms/librenms/pull/3971)) + - Rewrite availability map ([PR4043](https://github.com/librenms/librenms/pull/4043)) + - Add predicted usage to billing overview ([PR4049](https://github.com/librenms/librenms/pull/4049)) + - API + - Added services calls to API ([PR4215](https://github.com/librenms/librenms/pull/4215)) + - Discovery / Polling + - Added CPU detection for Dell PowerConnect 8024F ([PR3966](https://github.com/librenms/librenms/pull/3966)) + - Cisco VSS state discovery ([PR3977](https://github.com/librenms/librenms/pull/3977)) + - Refactor of BGP Discovery and Polling (mainly JunOS) ([PR3938](https://github.com/librenms/librenms/pull/3938)) + - Added Sensors for Brocade NOS ([PR3969](https://github.com/librenms/librenms/pull/3969)) + - Cisco ASA HA States ([PR4012](https://github.com/librenms/librenms/pull/4012)) + - Improved IPSLA Support ([PR4006](https://github.com/librenms/librenms/pull/4006)) + - Added support for CISCO-NTP-MIB ([PR4005](https://github.com/librenms/librenms/pull/4005)) + - Improved toner support for Ricoh devices ([PR4180](https://github.com/librenms/librenms/pull/4180)) + - Documentation + - New doc site live http://docs.librenms.org/ + - Added rsyslog 5 example to syslog docs ([PR3912](https://github.com/librenms/librenms/pull/3912)) + - Application doc updates ([PR3928](https://github.com/librenms/librenms/pull/3928)) + - Applications + - App OS Updates support ([PR3935](https://github.com/librenms/librenms/pull/3935)) + - PowerDNS Recursor improvements ([PR3932](https://github.com/librenms/librenms/pull/3932)) + - Add DHCP Stats support ([PR3970](https://github.com/librenms/librenms/pull/3970)) + - Added snmp support to Memcached ([PR3949](https://github.com/librenms/librenms/pull/3949)) + - Added Unbound support ([PR4074](https://github.com/librenms/librenms/pull/4074)) + - Added snmp support to Proxmox ([PR4052](https://github.com/librenms/librenms/pull/4052)) + - Added Raspberry Pi Sensor support ([PR4057](https://github.com/librenms/librenms/pull/4057)) + - Updated NTPD support ([PR4077](https://github.com/librenms/librenms/pull/4077)) + - Misc + - Added cleanup of old RRD files to daily.sh ([PR3907](https://github.com/librenms/librenms/pull/3907)) + - Refactored addHost event logs ([PR3929](https://github.com/librenms/librenms/pull/3929), [PR3997](https://github.com/librenms/librenms/pull/3997)) + - Refactored RRD Functions ([PR3800](https://github.com/librenms/librenms/pull/3800), [PR4081](https://github.com/librenms/librenms/pull/4081)) + - Added support for nets-exclude in snmp-scan ([PR4000](https://github.com/librenms/librenms/pull/4045)) + - Refactored files in html (Libraries and PSR2 style ([PR4071](https://github.com/librenms/librenms/pull/4071), [PR4101](https://github.com/librenms/librenms/pull/4101), [PR4117](https://github.com/librenms/librenms/pull/4117)) + - Various IRC updates and fixes ([PR4200](https://github.com/librenms/librenms/pull/4200), [PR4204](https://github.com/librenms/librenms/pull/4204), [PR4201](https://github.com/librenms/librenms/pull/4201)) + ### July 2016 #### Bug fixes diff --git a/doc/General/Contributing.md b/doc/General/Contributing.md index b875441353..7268c2c42d 100644 --- a/doc/General/Contributing.md +++ b/doc/General/Contributing.md @@ -34,9 +34,9 @@ To agree with these assertions, please submit a GitHub pull request against [AUTHORS.md][5], adding or altering a **single line** *containing your name, email address, and GitHub user id* in the file (so that it can be matched to your commits), and stating in the *commit log* (not the pull request text): + ``` - I agree to the conditions of the Contributor Agreement - contained in doc/General/Contributing.md. +I agree to the conditions of the Contributor Agreement contained in doc/General/Contributing.md. ``` Local patches @@ -61,8 +61,6 @@ the package information to the header. ``` - * * 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 diff --git a/doc/General/Credits.md b/doc/General/Credits.md index fc0a05e95e..253c68ac4f 100644 --- a/doc/General/Credits.md +++ b/doc/General/Credits.md @@ -50,9 +50,3 @@ Other components (needs details filled in): - html/includes/collectd/: GPLv2 only - overLIB (html/js/overlib_mini.js): modified Artistic 1.0? - -- scripts/*/mysql: GPLv2 only - -- check_mk (scripts/observium_agent*): GPLv2 - -- qTip (html/css/jquery.qtip.min.css and html/js/qtip/jquery.qtip.min.js): GPLv2 diff --git a/doc/General/Releases.md b/doc/General/Releases.md new file mode 100644 index 0000000000..2e3636c4a4 --- /dev/null +++ b/doc/General/Releases.md @@ -0,0 +1,16 @@ +source: General/Releases.md +# LibreNMS Releases + +We try to ensure that breaking changes aren't introduced by utilising various automated +code testing, syntax testing and unit testing along with manual code review. However +bugs can and do get introduced as well as major refactoring to improve the quality of +the code base. + +With this in mind, we provide a monthly stable release which is released on or around +the last Sunday of the month. Code pull requests (aside from Bug fixes) are stopped days +leading up to the release to ensure that we have a clean working branch at that point. + +The releases are titled after that month in the format `YYYYMM`, i.e `201608`. The +Changelog is also updated and will reference the release number and date so you can see +what changes have been made since the last release. + diff --git a/doc/General/Updating.md b/doc/General/Updating.md index 9c56e32625..fcffdc9b5a 100644 --- a/doc/General/Updating.md +++ b/doc/General/Updating.md @@ -4,7 +4,7 @@ source: General/Updating.md If you would like to perform a manual update then you can do this by running the following command as the **librenms** user: - ./daily.sh +`./daily.sh` This will update both the core LibreNMS files but also update the database structure if updates are available. @@ -13,12 +13,12 @@ structure if updates are available. LibreNMS follows the master branch on github for daily updates. You can change to the monthly releases by setting: - $config['update_channel'] = 'release'; +`$config['update_channel'] = 'release';` ## Disabling automatic updates ## LibreNMS by default performs updates on a daily basis. This can be disabled by ensuring: - $config['update'] = 0; +`$config['update'] = 0;` is no longer commented out. diff --git a/doc/General/Welcome-to-Observium-users.md b/doc/General/Welcome-to-Observium-users.md index 89874c88b8..b374833e4a 100644 --- a/doc/General/Welcome-to-Observium-users.md +++ b/doc/General/Welcome-to-Observium-users.md @@ -59,8 +59,6 @@ Reasons why you might want to use LibreNMS instead of Observium: "LibreNMS README" [3]: http://fisheye.observium.org/rdiff/Observium?csid=3251&u&N "Link to Observium license change" -[4]: https://github.com/librenms/librenms/blob/master/doc/General/Roadmap.md -"LibreNMS ROADMAP" [5]: https://github.com/librenms/librenms/blob/master/LICENSE.txt "LibreNMS copy of GPL v3" [6]: http://www.gnu.org/philosophy/free-sw.html diff --git a/doc/Installation/Installation-CentOS-7-Apache.md b/doc/Installation/Installation-CentOS-7-Apache.md index 546ae0f812..a0b997e867 100644 --- a/doc/Installation/Installation-CentOS-7-Apache.md +++ b/doc/Installation/Installation-CentOS-7-Apache.md @@ -145,7 +145,7 @@ systemctl enable httpd systemctl enable mariadb ``` -Now run validate your install and make sure everything is ok: +Run validate.php as root in the librenms directory: ```bash cd /opt/librenms @@ -162,10 +162,10 @@ We now suggest that you add localhost as your first device from within the WebUI Now that you've installed LibreNMS, we'd suggest that you have a read of a few other docs to get you going: - - (Performance tuning)[http://docs.librenms.org/Support/Performance] - - (Alerting)[http://docs.librenms.org/Extensions/Alerting/] - - (Device Groups)[http://docs.librenms.org/Extensions/Device-Groups/] - - (Auto discovery)[http://docs.librenms.org/Extensions/Auto-Discovery/] + - [Performance tuning](http://docs.librenms.org/Support/Performance) + - [Alerting](http://docs.librenms.org/Extensions/Alerting/) + - [Device Groups](http://docs.librenms.org/Extensions/Device-Groups/) + - [Auto discovery](http://docs.librenms.org/Extensions/Auto-Discovery/) #### Closing diff --git a/doc/Installation/Installation-CentOS-7-Nginx.md b/doc/Installation/Installation-CentOS-7-Nginx.md index 58e5d182ab..65cfdeb9e3 100644 --- a/doc/Installation/Installation-CentOS-7-Nginx.md +++ b/doc/Installation/Installation-CentOS-7-Nginx.md @@ -156,7 +156,7 @@ systemctl enable nginx systemctl enable mariadb ``` -Now run validate your install and make sure everything is ok: +Run validate.php as root in the librenms directory: ```bash cd /opt/librenms @@ -173,10 +173,10 @@ We now suggest that you add localhost as your first device from within the WebUI Now that you've installed LibreNMS, we'd suggest that you have a read of a few other docs to get you going: - - (Performance tuning)[http://docs.librenms.org/Support/Performance] - - (Alerting)[http://docs.librenms.org/Extensions/Alerting/] - - (Device Groups)[http://docs.librenms.org/Extensions/Device-Groups/] - - (Auto discovery)[http://docs.librenms.org/Extensions/Auto-Discovery/] + - [Performance tuning](http://docs.librenms.org/Support/Performance) + - [Alerting](http://docs.librenms.org/Extensions/Alerting/) + - [Device Groups](http://docs.librenms.org/Extensions/Device-Groups/) + - [Auto discovery](http://docs.librenms.org/Extensions/Auto-Discovery/) #### Closing diff --git a/doc/Installation/Installation-Ubuntu-1604-Apache.md b/doc/Installation/Installation-Ubuntu-1604-Apache.md index 56bc1df13a..3452b7e8d5 100644 --- a/doc/Installation/Installation-Ubuntu-1604-Apache.md +++ b/doc/Installation/Installation-Ubuntu-1604-Apache.md @@ -105,8 +105,8 @@ Now head to: http://librenms.example.com/install.php and follow the on-screen in #### Configure snmpd ```bash -cp /opt/librenms/snmpd.conf.example /etc/snmpd.conf -vim /etc/snmpd.conf +cp /opt/librenms/snmpd.conf.example /etc/snmp/snmpd.conf +vim /etc/snmp/snmpd.conf ``` Edit the text which says `RANDOMSTRINGGOESHERE` and set your own community string. @@ -127,7 +127,7 @@ service snmpd restart chown -R librenms:librenms /opt/librenms ``` -Now run validate your install and make sure everything is ok: +Run validate.php as root in the librenms directory: ```bash cd /opt/librenms diff --git a/doc/Installation/Installation-Ubuntu-1604-Nginx.md b/doc/Installation/Installation-Ubuntu-1604-Nginx.md index 1aa8975dcf..4a06dfefb3 100644 --- a/doc/Installation/Installation-Ubuntu-1604-Nginx.md +++ b/doc/Installation/Installation-Ubuntu-1604-Nginx.md @@ -108,8 +108,8 @@ Now head to: http://librenms.example.com/install.php and follow the on-screen in #### Configure snmpd ```bash -cp /opt/librenms/snmpd.conf.example /etc/snmpd.conf -vim /etc/snmpd.conf +cp /opt/librenms/snmpd.conf.example /etc/snmpd/snmpd.conf +vim /etc/snmpd/snmpd.conf ``` Edit the text which says `RANDOMSTRINGGOESHERE` and set your own community string. @@ -130,7 +130,7 @@ service snmpd restart chown -R librenms:librenms /opt/librenms ``` -Now run validate your install and make sure everything is ok: +Run validate.php as root in the librenms directory: ```bash cd /opt/librenms diff --git a/doc/Installation/Installing-LibreNMS.md b/doc/Installation/Installing-LibreNMS.md index 3ff838892f..732380d8b8 100644 --- a/doc/Installation/Installing-LibreNMS.md +++ b/doc/Installation/Installing-LibreNMS.md @@ -9,7 +9,7 @@ We have some pre-built VirtualBox images you can use to get started: If you want to install yourself then we have some new documentation which should make it easy. -> Please note the following docs are new and may not be 100% complate, please provide feedback on your experience. +> Please note the following docs are new and may not be 100% complete, please provide feedback on your experience. [Ubuntu 16.04 Apache](http://docs.librenms.org/Installation/Installation-Ubuntu-1604-Apache/) diff --git a/doc/Support/Discovery Support.md b/doc/Support/Discovery Support.md index 1fc6ae4c9c..3086a25b9a 100644 --- a/doc/Support/Discovery Support.md +++ b/doc/Support/Discovery Support.md @@ -6,18 +6,21 @@ This document will explain how to use discovery.php to debug issues or manually #### Command options ```bash -h | Poll single device - -h odd Poll odd numbered devices (same as -i 2 -n 0) - -h even Poll even numbered devices (same as -i 2 -n 1) - -h all Poll all devices - -h new Poll all devices that have not had a discovery run before +-h odd Poll odd numbered devices (same as -i 2 -n 0) +-h even Poll even numbered devices (same as -i 2 -n 1) +-h all Poll all devices +-h new Poll all devices that have not had a discovery run before +--os Poll devices only with specified operating system +--type Poll devices only with specified type +-i -n Poll as instance of + Instances start at 0. 0-3 for -n 4 - -i -n Poll as instance of - Instances start at 0. 0-3 for -n 4 +Debugging and testing options: +-d Enable debugging output +-v Enable verbose debugging output +-m Specify single module to be run - Debugging and testing options: - -d Enable debugging output - -m Specify single module to be run ``` `-h` Use this to specify a device via either id or hostname (including wildcard using *). You can also specify odd and @@ -26,15 +29,16 @@ new will poll only those devices that have recently been added or have been sele `-i` This can be used to stagger the discovery process. -`-d` Enables debugging output (verbose output) so that you can see what is happening during a discovery run. This includes -things like rrd updates, SQL queries and response from snmp. +`-d` Enables debugging output (verbose output but with most sensitive data masked) so that you can see what is happening during a discovery run. This includes things like rrd updates, SQL queries and response from snmp. + +`-v` Enables verbose debugging output with all data in tact. `-m` This enables you to specify the module you want to run for discovery. #### Discovery config These are the default discovery config items. You can globally disable a module by setting it to 0. If you just want to -disable it for one device then you can do this within the WebUI -> Settings -> Modules. +disable it for one device then you can do this within the WebUI -> Device -> Settings -> Modules. ```php $config['discovery_modules']['os'] = 1; @@ -160,15 +164,12 @@ Multiple Modules ./discovery.php -h localhost -m ports,entity-physical -d ``` -It is then advisable to sanitise the output before pasting it somewhere as the debug output will contain snmp details -amongst other items including port descriptions. +Using `-d` shouldn't output much sensitive information, `-v` will so it is then advisable to sanitise the output before pasting it somewhere as the debug output will contain snmp details amongst other items including port descriptions. The output will contain: DB Updates -RRD Updates - SNMP Response ### SNMP Scan diff --git a/doc/Support/Install Validation.md b/doc/Support/Install Validation.md index 248ec8d0d1..67eeb9b6c7 100644 --- a/doc/Support/Install Validation.md +++ b/doc/Support/Install Validation.md @@ -2,7 +2,7 @@ source: Install Validation.md Install validation ------------------ -With a lot of configuration possibilities and at present the only way to do this being by manually editing config.php then it's not +With a lot of configuration possibilities, manually editing config.php means it's not uncommon that mistakes get made. It's also impossible to validate user input in config.php when you're just using a text editor :) So, to try and help with some of the general issues people come across we've put together a simple validation tool which at present will: @@ -22,10 +22,12 @@ Optionally you can also pass -m and a module name for that to be tested. Current - dist-poller - This will test your distributed poller configuration. - rrdcheck - This will test your rrd files to see if they are unreadable or corrupted (source of broken graphs). -Output, this is color coded to try and make things a little easier: +You can run validate.php as `root` by executing `./validate.php` within your install directory. -Green OK - This is a good thing, you can skip over these :) +The output will provide you either a clean bill of health or a list of things you need to fix: -Yellow WARN - You probably want to check this out. +OK - This is a good thing, you can skip over these :) -Red FAIL - This is going to need your attention! +WARN - You probably want to check this out. + +FAIL - This is going to need your attention! diff --git a/doc/Support/Poller Support.md b/doc/Support/Poller Support.md index 591d789623..a906b246ef 100644 --- a/doc/Support/Poller Support.md +++ b/doc/Support/Poller Support.md @@ -17,7 +17,9 @@ This document will explain how to use poller.php to debug issues or manually run Debugging and testing options: -r Do not create or update RRDs +-f Do not insert data into InfluxDB -d Enable debugging output +-v Enable verbose debugging output -m Specify module(s) to be run ``` @@ -28,8 +30,9 @@ even. all will run poller against all devices. `-r` This option will suppress the creation or update of RRD files. -`-d` Enables debugging output (verbose output) so that you can see what is happening during a poller run. This includes -things like rrd updates, SQL queries and response from snmp. +`-d` Enables debugging output (verbose output but with most sensitive data masked) so that you can see what is happening during a poller run. This includes things like rrd updates, SQL queries and response from snmp. + +`-v` Enables verbose debugging output with all data in tact. `-m` This enables you to specify the module you want to run for poller. @@ -170,8 +173,7 @@ Multiple Modules ./poller.php -h localhost -m ports,entity-physical -d ``` -It is then advisable to sanitise the output before pasting it somewhere as the debug output will contain snmp details -amongst other items including port descriptions. +Using `-d` shouldn't output much sensitive information, `-v` will so it is then advisable to sanitise the output before pasting it somewhere as the debug output will contain snmp details amongst other items including port descriptions. The output will contain: diff --git a/doc/Support/Support-New-OS.md b/doc/Support/Support-New-OS.md index 64d6141ef3..f60924ee7b 100644 --- a/doc/Support/Support-New-OS.md +++ b/doc/Support/Support-New-OS.md @@ -105,8 +105,6 @@ Polling At this step we should see all the values retrieved in LibreNMS. - - #### FULL SUPPORT FOR A NEW OS ### MIB diff --git a/doc/librenms.css b/doc/librenms.css index fea7803bb8..ba686743f6 100644 --- a/doc/librenms.css +++ b/doc/librenms.css @@ -8,10 +8,9 @@ body { overflow-x: hidden !important; } -/* pushdown the content when the header flows to two lines */ -.navbar-fixed-top { - top: -70px; - position: relative; +/* push down the content when the header flows to two lines */ +.bs-sidebar { + margin-top: 45px; } /* hide the menu called hidden, used to generate unlinked docs */ diff --git a/html/api_v0.php b/html/api_v0.php index 7ee1053870..dbfba3cb05 100644 --- a/html/api_v0.php +++ b/html/api_v0.php @@ -154,6 +154,15 @@ $app->group( } ); // End Resources + // Service section + $app->group( + '/services', + function () use ($app) { + $app->get('/:hostname', 'authToken', 'list_services')->name('get_service_for_host'); + } + ); + $app->get('/services', 'authToken', 'list_services')->name('list_services'); + // End Service } ); $app->get('/v0', 'authToken', 'show_endpoints'); diff --git a/html/css/styles.css b/html/css/styles.css index a5fc4f9057..b00bf3feef 100644 --- a/html/css/styles.css +++ b/html/css/styles.css @@ -1881,6 +1881,7 @@ label { padding:8px; border-radius:5px; text-align:center; + white-space: nowrap; } .device-availability.up, .service-availability.up { @@ -1948,11 +1949,6 @@ label { padding-left:10px; } -.page-availability-report-service { - float:right; - text-align:right; -} - .widget-availability { float:left; margin:2px; @@ -1997,4 +1993,4 @@ label { width:12px; float:left; background-color: #D9534F; -} \ No newline at end of file +} diff --git a/html/graph.php b/html/graph.php index 84ed9bfd3d..8411fca3dd 100644 --- a/html/graph.php +++ b/html/graph.php @@ -32,9 +32,9 @@ if (isset($_GET['debug'])) { require_once '../includes/defaults.inc.php'; require_once '../config.php'; +require_once '../includes/common.php'; require_once '../includes/definitions.inc.php'; -require_once '../includes/common.php'; require_once '../includes/dbFacile.php'; require_once '../includes/rewrites.php'; require_once 'includes/functions.inc.php'; @@ -42,9 +42,12 @@ require_once '../includes/rrdtool.inc.php'; if ($config['allow_unauth_graphs'] != true) { require_once 'includes/authenticate.inc.php'; } + +rrdtool_initialize(false); + require 'includes/graphs/graph.inc.php'; -$console_color = new Console_Color2(); +rrdtool_close(); $end = microtime(true); $run = ($end - $start); diff --git a/html/images/os/ddn.png b/html/images/os/ddn.png new file mode 100644 index 0000000000..64c6a0114d Binary files /dev/null and b/html/images/os/ddn.png differ diff --git a/html/images/os/fujitsu.png b/html/images/os/fujitsu.png new file mode 100644 index 0000000000..ea780f4db4 Binary files /dev/null and b/html/images/os/fujitsu.png differ diff --git a/html/images/os/lanier.png b/html/images/os/lanier.png new file mode 100644 index 0000000000..64165b852a Binary files /dev/null and b/html/images/os/lanier.png differ diff --git a/html/includes/api_functions.inc.php b/html/includes/api_functions.inc.php index 7d0fcbf302..46c91f82ac 100644 --- a/html/includes/api_functions.inc.php +++ b/html/includes/api_functions.inc.php @@ -1222,6 +1222,7 @@ function get_devices_by_group() $message = 'No devices found in group ' . $name; } else { $message = "Found $count in group $name"; + $status = 'ok'; $code = 200; } } @@ -1299,3 +1300,70 @@ function list_arp() $app->response->headers->set('Content-Type', 'application/json'); echo _json_encode($output); } +function list_services() +{ + global $config; + $app = \Slim\Slim::getInstance(); + $router = $app->router()->getCurrentRoute()->getParams(); + $status = 'ok'; + $code = 200; + $message = ''; + $host_par = array(); + $sql_param = array(); + $services = array(); + $where = ''; + $devicewhere = ''; + + // Filter BY STATE + if (isset($_GET['state'])) { + $where = " AND S.service_status= ? AND S.service_disabled='0' AND S.service_ignore='0'"; + $host_par[] = $_GET['state']; + + if (!is_numeric($_GET['state'])) { + $status = 'error'; + $message = "No valid service state provided, valid option is 0=Ok, 1=Warning, 2=Critical"; + } + } + + // GET BY HOST + if (isset($router['hostname'])) { + $hostname = $router['hostname']; + $device_id = ctype_digit($hostname) ? $hostname : getidbyname($hostname); + + $where .= " AND S.device_id = ?"; + $host_par[] = $device_id; + + if (!is_numeric($device_id)) { + $status = 'error'; + $message = "No valid hostname or device id provided"; + } + } + + // DEVICE + $host_sql = 'SELECT * FROM devices AS D, services AS S WHERE D.device_id = S.device_id '.$where.' GROUP BY D.hostname ORDER BY D.hostname'; + + // SERVICE + foreach (dbFetchRows($host_sql, $host_par) as $device) { + $device_id = $device['device_id']; + $sql_param[0] = $device_id; + + // FILTER BY TYPE + if (isset($_GET['type'])) { + $devicewhere = " AND `service_type` LIKE ?"; + $sql_param[1] = $_GET['type']; + } + + $services = dbFetchRows("SELECT * FROM `services` WHERE `device_id` = ?".$devicewhere, $sql_param); + } + $count = count($services); + $output = array( + 'status' => $status, + 'err-msg' => $message, + 'count' => $count, + 'services' => $services, + ); + + $app->response->setStatus($code); + $app->response->headers->set('Content-Type', 'application/json'); + echo _json_encode($output); +} diff --git a/html/includes/common/availability-map.inc.php b/html/includes/common/availability-map.inc.php index 4fd15f5bf9..d2a5e6b50e 100644 --- a/html/includes/common/availability-map.inc.php +++ b/html/includes/common/availability-map.inc.php @@ -12,9 +12,25 @@ * the source code distribution for details. */ +$select_modes = array( + '0' => 'only devices', + '1' => 'only services', + '2' => 'devices and services', +); + if (defined('SHOW_SETTINGS')) { - $current_mode = isset($widget_settings['mode']) ? $widget_settings['mode'] : 0; - $current_width = isset($widget_settings['tile_width']) ? $widget_settings['tile_width'] : 10; + if (isset($widget_settings['mode'])) { + $mode = $widget_settings['mode']; + } else { + $mode = 0; + } + + if (isset($widget_settings['tile_width'])) { + $current_width = $widget_settings['tile_width']; + } else { + $current_width = 10; + } + $common_output[] = '
@@ -31,12 +47,15 @@ if (defined('SHOW_SETTINGS')) { if ($config['show_services'] == 0) { $common_output[] = ''; } else { - $common_output[] = ' - - - '; + foreach ($select_modes as $mode_select => $option) { + if ($mode_select == $mode) { + $selected = 'selected'; + } else { + $selected = ''; + } + $common_output[] = ''; + } } - $common_output[] ='
@@ -50,7 +69,12 @@ if (defined('SHOW_SETTINGS')) { $sql = dbFetchRow('SELECT `settings` FROM `users_widgets` WHERE `user_id` = ? AND `widget_id` = ?', array($_SESSION["user_id"], '1')); $widget_mode = json_decode($sql['settings']); - $mode = isset($_SESSION["mapView"]) ? $_SESSION["mapView"] : $widget_mode->{'mode'}; + + if (isset($_SESSION["mapView"])) { + $mode = $_SESSION["mapView"]; + } else { + $mode = $widget_mode->{'mode'}; + } $host_up_count = 0; $host_warn_count = 0; @@ -59,9 +83,17 @@ if (defined('SHOW_SETTINGS')) { $service_warn_count = 0; $service_down_count = 0; + if ($config['webui']['availability_map_sort_status'] == 1) { + $deviceOrderBy = 'status'; + $serviceOrderBy = '`S`.`service_status` DESC'; + } else { + $deviceOrderBy = 'hostname'; + $serviceOrderBy = '`D`.`hostname`'; + } + if ($mode == 0 || $mode == 2) { // Only show devices if mode is 0 or 2 (Only Devices or both) - $sql = 'SELECT `D`.`hostname`,`D`.`device_id`,`D`.`status`,`D`.`uptime`, `D`.`os`, `D`.`icon` FROM `devices` AS `D`'; + $sql = 'SELECT `D`.`hostname`, `D`.`sysName`, `D`.`device_id`, `D`.`status`, `D`.`uptime`, `D`.`os`, `D`.`icon` FROM `devices` AS `D`'; if (is_normal_user() === true) { $sql .= ' , `devices_perms` AS P WHERE D.`device_id` = P.`device_id` AND P.`user_id` = ? AND'; $param = array( @@ -70,7 +102,7 @@ if (defined('SHOW_SETTINGS')) { } else { $sql .= ' WHERE'; } - $sql .= " `D`.`ignore` = '0' AND `D`.`disabled` = '0' ORDER BY `hostname`"; + $sql .= " `D`.`ignore` = '0' AND `D`.`disabled` = '0' ORDER BY `".$deviceOrderBy."`"; $temp_output = array(); foreach (dbFetchRows($sql, $param) as $device) { @@ -101,7 +133,7 @@ if (defined('SHOW_SETTINGS')) {
'.$deviceState.' '.$deviceIcon.'
- '.$device["hostname"].' + '.shorthost(ip_to_sysname($device, $device['hostname'])).'
'; } else { @@ -117,7 +149,7 @@ if (defined('SHOW_SETTINGS')) { } if (($mode == 1 || $mode == 2) && ($config['show_services'] != 0)) { - $service_query = 'select `S`.`service_type`, `S`.`service_id`, `S`.`service_desc`, `S`.`service_status`, `D`.`hostname`, `D`.`device_id`, `D`.`os`, `D`.`icon` from services S, devices D where `S`.`device_id` = `D`.`device_id`;'; + $service_query = 'select `S`.`service_type`, `S`.`service_id`, `S`.`service_desc`, `S`.`service_status`, `D`.`hostname`, `D`.`sysName`, `D`.`device_id`, `D`.`os`, `D`.`icon` from services S, devices D where `S`.`device_id` = `D`.`device_id` ORDER BY '.$serviceOrderBy.';'; $services = dbFetchRows($service_query); if (count($services) > 0) { foreach ($services as $service) { @@ -142,22 +174,22 @@ if (defined('SHOW_SETTINGS')) { if ($directpage == "yes") { $deviceIcon = getImage($service); $temp_output[] = ' - -
- ' . $service["service_type"] . ' - ' . $serviceState . ' - ' . $deviceIcon . '
- ' . $service["hostname"] . ' +
+
+ '.$service["service_type"].' + '.$serviceState.' + '.$deviceIcon.'
+ '.shorthost(ip_to_sysname($service, $service['hostname'])).'
'; } else { $temp_output[] = ' - - ' . $service['service_type'] . ' - ' . $serviceState . ' + + '.$service['service_type'].' - '.$serviceState.' '; } } else { - $temp_output[] = '
'; + $temp_output[] = '
'; } } } else { @@ -165,8 +197,6 @@ if (defined('SHOW_SETTINGS')) { } } - - if ($directpage == "yes") { $temp_header[] = '
@@ -174,12 +204,16 @@ if (defined('SHOW_SETTINGS')) {