mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
feature: Added web validation (#7474)
* refactor: convert validations to modules to prep for gui integration * accidentally dropped, schema update * fix accidental output to webui * mention discovery-wrapper.py and re-arrange. * refine some fix statements * rename the Config validation group to Configuration. * fix some scrutinizer issues remove as many local functions from validator.php as possible move extensions from pre-check remove duplicate timezone check looks like there is some db schema differences between mariadb 10.1 and 10.2, investigating * mariadb version diff take2 * Check schema version first for database. Remove stop to go back to command line for install docs. Add helpful link when there is no devices added to /addhost * fix incorrect validation for empty string defaults * Fix style * Add additional file permissions checks * catch exception and fail for invalid timezone Change visuals a bit. * add php version warning * fix space
This commit is contained in:
committed by
Neil Lathwood
parent
383557f628
commit
51ba934e11
@@ -171,7 +171,7 @@ class IRCBot
|
|||||||
if ($this->config['irc_alert']) {
|
if ($this->config['irc_alert']) {
|
||||||
$this->alertData();
|
$this->alertData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->config['irc_conn_timeout']) {
|
if ($this->config['irc_conn_timeout']) {
|
||||||
$inactive_seconds = time() - $this->last_activity;
|
$inactive_seconds = time() - $this->last_activity;
|
||||||
$max_inactive = $this->config['irc_conn_timeout'];
|
$max_inactive = $this->config['irc_conn_timeout'];
|
||||||
@@ -677,7 +677,7 @@ class IRCBot
|
|||||||
|
|
||||||
private function _version($params)
|
private function _version($params)
|
||||||
{
|
{
|
||||||
$versions = version_info(false);
|
$versions = version_info();
|
||||||
$schema_version = $versions['db_schema'];
|
$schema_version = $versions['db_schema'];
|
||||||
$version = substr($versions['local_sha'], 0, 7);
|
$version = substr($versions['local_sha'], 0, 7);
|
||||||
|
|
||||||
|
|||||||
46
LibreNMS/Interfaces/ValidationGroup.php
Normal file
46
LibreNMS/Interfaces/ValidationGroup.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ValidationGroup.php
|
||||||
|
*
|
||||||
|
* An interface for validation groups, this will be run by Validator.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Interfaces;
|
||||||
|
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
interface ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault();
|
||||||
|
}
|
||||||
198
LibreNMS/ValidationResult.php
Normal file
198
LibreNMS/ValidationResult.php
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ValidationResult.php
|
||||||
|
*
|
||||||
|
* Encapsulates the result of a validation test.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS;
|
||||||
|
|
||||||
|
class ValidationResult
|
||||||
|
{
|
||||||
|
const FAILURE = 0;
|
||||||
|
const WARNING = 1;
|
||||||
|
const SUCCESS = 2;
|
||||||
|
|
||||||
|
private $message;
|
||||||
|
private $status;
|
||||||
|
private $list_description = '';
|
||||||
|
private $list;
|
||||||
|
private $fix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ValidationResult constructor.
|
||||||
|
* @param string $message The message to describe this result
|
||||||
|
* @param int $status The status of this result FAILURE, WARNING, or SUCCESS
|
||||||
|
* @param string $fix a suggested fix to highlight for the user
|
||||||
|
*/
|
||||||
|
public function __construct($message, $status, $fix = null)
|
||||||
|
{
|
||||||
|
$this->message = $message;
|
||||||
|
$this->status = $status;
|
||||||
|
$this->fix = $fix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ok Validation result
|
||||||
|
* @param string $message The message to describe this result
|
||||||
|
* @param string $fix a suggested fix to highlight for the user
|
||||||
|
* @return ValidationResult
|
||||||
|
*/
|
||||||
|
public static function ok($message, $fix = null)
|
||||||
|
{
|
||||||
|
return new self($message, self::SUCCESS, $fix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new warning Validation result
|
||||||
|
* @param string $message The message to describe this result
|
||||||
|
* @param string $fix a suggested fix to highlight for the user
|
||||||
|
* @return ValidationResult
|
||||||
|
*/
|
||||||
|
public static function warn($message, $fix = null)
|
||||||
|
{
|
||||||
|
return new self($message, self::WARNING, $fix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new failure Validation result
|
||||||
|
* @param string $message The message to describe this result
|
||||||
|
* @param string $fix a suggested fix to highlight for the user
|
||||||
|
* @return ValidationResult
|
||||||
|
*/
|
||||||
|
public static function fail($message, $fix = null)
|
||||||
|
{
|
||||||
|
return new self($message, self::FAILURE, $fix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status an int representing
|
||||||
|
* ValidationResult::FAILURE, ValidationResult::WARNING, or ValidationResult::SUCCESS
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getStatus()
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMessage()
|
||||||
|
{
|
||||||
|
return $this->message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasList()
|
||||||
|
{
|
||||||
|
return !empty($this->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getList()
|
||||||
|
{
|
||||||
|
return $this->list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setList($description, array $list)
|
||||||
|
{
|
||||||
|
$this->list_description = $description;
|
||||||
|
$this->list = $list;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasFix()
|
||||||
|
{
|
||||||
|
return !empty($this->fix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFix()
|
||||||
|
{
|
||||||
|
return $this->fix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFix($fix)
|
||||||
|
{
|
||||||
|
$this->fix = $fix;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print out this result to the console. Formatted nicely and with color.
|
||||||
|
*/
|
||||||
|
public function consolePrint()
|
||||||
|
{
|
||||||
|
c_echo(str_pad('[' . $this->getStatusText($this->status) . ']', 12) . $this->message . PHP_EOL);
|
||||||
|
|
||||||
|
if (isset($this->fix)) {
|
||||||
|
c_echo("\t[%BFIX%n] %B$this->fix%n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->list)) {
|
||||||
|
echo "\t" . $this->getListDescription() . ":\n";
|
||||||
|
$this->printList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the colorized string that represents the status of a ValidatonResult
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getStatusText($status)
|
||||||
|
{
|
||||||
|
if ($status === self::SUCCESS) {
|
||||||
|
return '%gOK%n';
|
||||||
|
} elseif ($status === self::WARNING) {
|
||||||
|
return '%YWARN%n';
|
||||||
|
} elseif ($status === self::FAILURE) {
|
||||||
|
return '%RFAIL%n';
|
||||||
|
}
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getListDescription()
|
||||||
|
{
|
||||||
|
return $this->list_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a list of items up to a max amount
|
||||||
|
* If over that number, a line will print the total items
|
||||||
|
*
|
||||||
|
* @param string $format format as consumed by printf()
|
||||||
|
* @param int $max the max amount of items to print, default 15
|
||||||
|
*/
|
||||||
|
private function printList($format = "\t %s\n", $max = 15)
|
||||||
|
{
|
||||||
|
if (is_array(current($this->list))) {
|
||||||
|
$this->list = array_map(function ($item) {
|
||||||
|
return implode(' ', $item);
|
||||||
|
}, $this->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (array_slice($this->list, 0, $max) as $item) {
|
||||||
|
printf($format, $item);
|
||||||
|
}
|
||||||
|
|
||||||
|
$extra = count($this->list) - $max;
|
||||||
|
if ($extra > 0) {
|
||||||
|
printf($format, " and $extra more...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
LibreNMS/Validations/Configuration.php
Normal file
57
LibreNMS/Validations/Configuration.php
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Configuration.php
|
||||||
|
*
|
||||||
|
* Checks various config settings are correct.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Configuration implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
// Test transports
|
||||||
|
if (Config::get('alerts.email.enable') == true) {
|
||||||
|
$validator->warn('You have the old alerting system enabled - this is to be deprecated on the 1st of June 2015: https://groups.google.com/forum/#!topic/librenms-project/1llxos4m0p4');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
321
LibreNMS/Validations/Database.php
Normal file
321
LibreNMS/Validations/Database.php
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Database.php
|
||||||
|
*
|
||||||
|
* Checks the database for errors
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\ValidationResult;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
class Database implements ValidationGroup
|
||||||
|
{
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
if (!dbIsConnected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->checkMode($validator);
|
||||||
|
|
||||||
|
// check database schema version
|
||||||
|
$current = get_db_schema();
|
||||||
|
|
||||||
|
$schemas = get_schema_list();
|
||||||
|
end($schemas);
|
||||||
|
$latest = key($schemas);
|
||||||
|
|
||||||
|
if ($current < $latest) {
|
||||||
|
$validator->fail(
|
||||||
|
"Your database schema ($current) is older than the latest ($latest).",
|
||||||
|
"Manually run ./daily.sh, and check for any errors."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} elseif ($current > $latest) {
|
||||||
|
$validator->warn("Your schema ($current) is newer than than expected ($latest). If you just switch to the stable release from the daily release, your database is in between releases and this will be resolved with the next release.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->checkCollation($validator);
|
||||||
|
$this->checkSchema($validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkMode(Validator $validator)
|
||||||
|
{
|
||||||
|
// Test for MySQL Strict mode
|
||||||
|
$strict_mode = dbFetchCell("SELECT @@global.sql_mode");
|
||||||
|
if (str_contains($strict_mode, 'STRICT_TRANS_TABLES')) {
|
||||||
|
//FIXME - Come back to this once other MySQL modes are fixed
|
||||||
|
//$valid->fail('You have MySQL STRICT_TRANS_TABLES enabled, please disable this until full support has been added: https://dev.mysql.com/doc/refman/5.0/en/sql-mode.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for lower case table name support
|
||||||
|
$lc_mode = dbFetchCell("SELECT @@global.lower_case_table_names");
|
||||||
|
if ($lc_mode != 0) {
|
||||||
|
$validator->fail(
|
||||||
|
'You have lower_case_table_names set to 1 or true in mysql config.',
|
||||||
|
'Set lower_case_table_names=0 in your mysql config file in the [mysqld] section.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($strict_mode) === false) {
|
||||||
|
$validator->fail(
|
||||||
|
"You have not set sql_mode='' in your mysql config.",
|
||||||
|
"Set sql-mode='' in your mysql config file in the [mysqld] section."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkCollation(Validator $validator)
|
||||||
|
{
|
||||||
|
// Test for correct character set and collation
|
||||||
|
$db_collation_sql = "SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
|
||||||
|
FROM information_schema.SCHEMATA S
|
||||||
|
WHERE schema_name = '" . Config::get('db_name') .
|
||||||
|
"' AND ( DEFAULT_CHARACTER_SET_NAME != 'utf8' OR DEFAULT_COLLATION_NAME != 'utf8_unicode_ci')";
|
||||||
|
$collation = dbFetchRows($db_collation_sql);
|
||||||
|
if (empty($collation) !== true) {
|
||||||
|
$validator->fail(
|
||||||
|
'MySQL Database collation is wrong: ' . implode(' ', $collation[0]),
|
||||||
|
'Check https://t.libren.ms/-zdwk for info on how to fix.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table_collation_sql = "SELECT T.TABLE_NAME, C.CHARACTER_SET_NAME, C.COLLATION_NAME
|
||||||
|
FROM information_schema.TABLES AS T, information_schema.COLLATION_CHARACTER_SET_APPLICABILITY AS C
|
||||||
|
WHERE C.collation_name = T.table_collation AND T.table_schema = '" . Config::get('db_name') .
|
||||||
|
"' AND ( C.CHARACTER_SET_NAME != 'utf8' OR C.COLLATION_NAME != 'utf8_unicode_ci' );";
|
||||||
|
$collation_tables = dbFetchRows($table_collation_sql);
|
||||||
|
if (empty($collation_tables) !== true) {
|
||||||
|
$result = ValidationResult::fail('MySQL tables collation is wrong: ')
|
||||||
|
->setFix('Check http://bit.ly/2lAG9H8 for info on how to fix.')
|
||||||
|
->setList('Tables', $collation_tables);
|
||||||
|
$validator->result($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
$column_collation_sql = "SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME
|
||||||
|
FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . Config::get('db_name') .
|
||||||
|
"' AND ( CHARACTER_SET_NAME != 'utf8' OR COLLATION_NAME != 'utf8_unicode_ci' );";
|
||||||
|
$collation_columns = dbFetchRows($column_collation_sql);
|
||||||
|
if (empty($collation_columns) !== true) {
|
||||||
|
$result = ValidationResult::fail('MySQL column collation is wrong: ')
|
||||||
|
->setFix('Check https://t.libren.ms/-zdwk for info on how to fix.')
|
||||||
|
->setList('Columns', $collation_columns);
|
||||||
|
$validator->result($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkSchema(Validator $validator)
|
||||||
|
{
|
||||||
|
$schema_file = Config::get('install_dir') . '/misc/db_schema.yaml';
|
||||||
|
|
||||||
|
if (!is_file($schema_file)) {
|
||||||
|
$validator->warn("We haven't detected the db_schema.yaml file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$master_schema = Yaml::parse(file_get_contents($schema_file));
|
||||||
|
$current_schema = dump_db_schema();
|
||||||
|
$schema_update = array();
|
||||||
|
|
||||||
|
foreach ((array)$master_schema as $table => $data) {
|
||||||
|
if (empty($current_schema[$table])) {
|
||||||
|
$validator->fail("Database: missing table ($table)");
|
||||||
|
$schema_update[] = $this->addTableSql($table, $data);
|
||||||
|
} else {
|
||||||
|
$current_columns = array_reduce($current_schema[$table]['Columns'], function ($array, $item) {
|
||||||
|
$array[$item['Field']] = $item;
|
||||||
|
return $array;
|
||||||
|
}, array());
|
||||||
|
|
||||||
|
foreach ($data['Columns'] as $index => $cdata) {
|
||||||
|
$column = $cdata['Field'];
|
||||||
|
if (empty($current_columns[$column])) {
|
||||||
|
$validator->fail("Database: missing column ($table/$column)");
|
||||||
|
$schema_update[] = $this->addColumnSql($table, $cdata, $data['Columns'][$index - 1]['Field']);
|
||||||
|
} elseif ($cdata !== $current_columns[$column]) {
|
||||||
|
$validator->fail("Database: incorrect column ($table/$column)");
|
||||||
|
$schema_update[] = $this->updateTableSql($table, $column, $cdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($current_columns[$column]); // remove checked columns
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($current_columns as $column => $_unused) {
|
||||||
|
$validator->fail("Database: extra column ($table/$column)");
|
||||||
|
$schema_update[] = $this->dropColumnSql($table, $column);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['Indexes'])) {
|
||||||
|
foreach ($data['Indexes'] as $name => $index) {
|
||||||
|
if (empty($current_schema[$table]['Indexes'][$name])) {
|
||||||
|
$validator->fail("Database: missing index ($table/$name)");
|
||||||
|
$schema_update[] = $this->addIndexSql($table, $index);
|
||||||
|
} elseif ($index != $current_schema[$table]['Indexes'][$name]) {
|
||||||
|
$validator->fail("Database: incorrect index ($table/$name)");
|
||||||
|
$schema_update[] = $this->updateIndexSql($table, $name, $index);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($current_schema[$table]['Indexes'][$name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($current_schema[$table]['Indexes'])) {
|
||||||
|
foreach ($current_schema[$table]['Indexes'] as $name => $_unused) {
|
||||||
|
$validator->fail("Database: extra index ($table/$name)");
|
||||||
|
$schema_update[] = $this->dropIndexSql($table, $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($current_schema[$table]); // remove checked tables
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($current_schema as $table => $data) {
|
||||||
|
$validator->fail("Database: extra table ($table)");
|
||||||
|
$schema_update[] = $this->dropTableSql($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($schema_update)) {
|
||||||
|
$validator->ok('Database schema correct');
|
||||||
|
} else {
|
||||||
|
$result = ValidationResult::fail("We have detected that your database schema may be wrong, please report the following to us on IRC or the community site (https://t.libren.ms/5gscd):")
|
||||||
|
->setFix('Run the following SQL statements to fix.')
|
||||||
|
->setList('SQL Statements', $schema_update);
|
||||||
|
$validator->result($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addTableSql($table, $table_schema)
|
||||||
|
{
|
||||||
|
$columns = array_map(array($this, 'columnToSql'), $table_schema['Columns']);
|
||||||
|
$indexes = array_map(array($this, 'indexToSql'), $table_schema['Indexes']);
|
||||||
|
|
||||||
|
$def = implode(', ', array_merge(array_values($columns), array_values($indexes)));
|
||||||
|
|
||||||
|
return "CREATE TABLE `$table` ($def);";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addColumnSql($table, $schema, $previous_column)
|
||||||
|
{
|
||||||
|
$sql = "ALTER TABLE `$table` ADD " . $this->columnToSql($schema);
|
||||||
|
if (!empty($previous_column)) {
|
||||||
|
$sql .= " AFTER `$previous_column`";
|
||||||
|
}
|
||||||
|
return $sql . ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateTableSql($table, $column, $column_schema)
|
||||||
|
{
|
||||||
|
return "ALTER TABLE `$table` CHANGE `$column` " . $this->columnToSql($column_schema) . ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function dropColumnSql($table, $column)
|
||||||
|
{
|
||||||
|
return "ALTER TABLE `$table` DROP `$column`;";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addIndexSql($table, $index_schema)
|
||||||
|
{
|
||||||
|
return "ALTER TABLE `$table` ADD " . $this->indexToSql($index_schema) . ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function updateIndexSql($table, $name, $index_schema)
|
||||||
|
{
|
||||||
|
return "ALTER TABLE `$table` DROP INDEX `$name`, " . $this->indexToSql($index_schema) . ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function dropIndexSql($table, $name)
|
||||||
|
{
|
||||||
|
return "ALTER TABLE `$table` DROP INDEX `$name`;";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function dropTableSql($table)
|
||||||
|
{
|
||||||
|
return "DROP TABLE `$table`;";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an SQL segment to create the column based on data from dump_db_schema()
|
||||||
|
*
|
||||||
|
* @param array $column_data The array of data for the column
|
||||||
|
* @return string sql fragment, for example: "`ix_id` int(10) unsigned NOT NULL"
|
||||||
|
*/
|
||||||
|
private function columnToSql($column_data)
|
||||||
|
{
|
||||||
|
if ($column_data['Extra'] == 'on update current_timestamp()') {
|
||||||
|
$extra = 'on update CURRENT_TIMESTAMP';
|
||||||
|
} else {
|
||||||
|
$extra = $column_data['Extra'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$null = $column_data['Null'] ? 'NULL' : 'NOT NULL';
|
||||||
|
|
||||||
|
if (!isset($column_data['Default'])) {
|
||||||
|
$default = '';
|
||||||
|
} elseif ($column_data['Default'] === 'CURRENT_TIMESTAMP') {
|
||||||
|
$default = 'DEFAULT CURRENT_TIMESTAMP';
|
||||||
|
} elseif ($column_data['Default'] == 'NULL') {
|
||||||
|
$default = 'DEFAULT NULL';
|
||||||
|
} else {
|
||||||
|
$default = "DEFAULT '${column_data['Default']}'";
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim("`${column_data['Field']}` ${column_data['Type']} $null $default $extra");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an SQL segment to create the index based on data from dump_db_schema()
|
||||||
|
*
|
||||||
|
* @param array $index_data The array of data for the index
|
||||||
|
* @return string sql fragment, for example: "PRIMARY KEY (`device_id`)"
|
||||||
|
*/
|
||||||
|
private function indexToSql($index_data)
|
||||||
|
{
|
||||||
|
if ($index_data['Name'] == 'PRIMARY') {
|
||||||
|
$index = 'PRIMARY KEY (%s)';
|
||||||
|
} elseif ($index_data['Unique']) {
|
||||||
|
$index = "UNIQUE `{$index_data['Name']}` (%s)";
|
||||||
|
} else {
|
||||||
|
$index = "INDEX `{$index_data['Name']}` (%s)";
|
||||||
|
}
|
||||||
|
|
||||||
|
$columns = implode(',', array_map(function ($col) {
|
||||||
|
return "`$col`";
|
||||||
|
}, $index_data['Columns']));
|
||||||
|
|
||||||
|
return sprintf($index, $columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
69
LibreNMS/Validations/Disk.php
Normal file
69
LibreNMS/Validations/Disk.php
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Disk.php
|
||||||
|
*
|
||||||
|
* -Description-
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Disk implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
// Disk space and permission checks
|
||||||
|
$temp_dir = Config::get('temp_dir');
|
||||||
|
if (substr(sprintf('%o', fileperms($temp_dir)), -3) != 777) {
|
||||||
|
$validator->warn("Your tmp directory ($temp_dir) " .
|
||||||
|
"is not set to 777 so graphs most likely won't be generated");
|
||||||
|
}
|
||||||
|
|
||||||
|
$rrd_dir = Config::get('rrd_dir');
|
||||||
|
$space_check = (disk_free_space($rrd_dir) / 1024 / 1024);
|
||||||
|
if ($space_check < 512 && $space_check > 1) {
|
||||||
|
$validator->warn("Disk space where $rrd_dir is located is less than 512Mb");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($space_check < 1) {
|
||||||
|
$validator->fail("Disk space where $rrd_dir is located is empty!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
87
LibreNMS/Validations/DistributedPoller.php
Normal file
87
LibreNMS/Validations/DistributedPoller.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DistributedPoller.php
|
||||||
|
*
|
||||||
|
* -Description-
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by IntelliJ IDEA.
|
||||||
|
* User: murrant
|
||||||
|
* Date: 10/8/17
|
||||||
|
* Time: 2:16 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class DistributedPoller implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
if (!Config::get('distributed_poller')) {
|
||||||
|
$validator->fail('You have not enabled distributed_poller');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!Config::get('distributed_poller_memcached_host')) {
|
||||||
|
$validator->fail('You have not configured $config[\'distributed_poller_memcached_host\']');
|
||||||
|
} elseif (!Config::get('distributed_poller_memcached_port')) {
|
||||||
|
$validator->fail('You have not configured $config[\'distributed_poller_memcached_port\']');
|
||||||
|
} else {
|
||||||
|
$connection = @fsockopen(Config::get('distributed_poller_memcached_host'), Config::get('distributed_poller_memcached_port'));
|
||||||
|
if (!is_resource($connection)) {
|
||||||
|
$validator->fail('We could not get memcached stats, it is possible that we cannot connect to your memcached server, please check');
|
||||||
|
} else {
|
||||||
|
fclose($connection);
|
||||||
|
$validator->ok('Connection to memcached is ok');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config::get('rrdcached')) {
|
||||||
|
$validator->fail('You have not configured $config[\'rrdcached\']');
|
||||||
|
} elseif (!is_dir(Config::get('rrd_dir'))) {
|
||||||
|
$validator->fail('You have not configured $config[\'rrd_dir\']');
|
||||||
|
} else {
|
||||||
|
Rrd::checkRrdcached($validator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
LibreNMS/Validations/Mail.php
Normal file
92
LibreNMS/Validations/Mail.php
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Mail.php
|
||||||
|
*
|
||||||
|
* -Description-
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Mail implements ValidationGroup
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
if (Config::get('alert.transports.mail') === true) {
|
||||||
|
$run_test = 1;
|
||||||
|
if (!Config::has('alert.default_mail')) {
|
||||||
|
$validator->fail('default_mail config option needs to be specified to test email');
|
||||||
|
$run_test = 0;
|
||||||
|
} elseif (Config::get('email_backend') == 'sendmail') {
|
||||||
|
if (Config::has('email_sendmail_path')) {
|
||||||
|
$validator->fail("You have selected sendmail but not configured email_sendmail_path");
|
||||||
|
$run_test = 0;
|
||||||
|
} elseif (!file_exists(Config::get('email_sendmail_path'))) {
|
||||||
|
$validator->fail("The configured email_sendmail_path is not valid");
|
||||||
|
$run_test = 0;
|
||||||
|
}
|
||||||
|
} elseif (Config::get('email_backend') == 'smtp') {
|
||||||
|
if (!Config::has('email_smtp_host')) {
|
||||||
|
$validator->fail('You have selected SMTP but not configured an SMTP host');
|
||||||
|
$run_test = 0;
|
||||||
|
}
|
||||||
|
if (!Config::has('email_smtp_port')) {
|
||||||
|
$validator->fail('You have selected SMTP but not configured an SMTP port');
|
||||||
|
$run_test = 0;
|
||||||
|
}
|
||||||
|
if (Config::get('email_smtp_auth')
|
||||||
|
&& (!Config::has('email_smtp_username') || !Config::has('email_smtp_password'))
|
||||||
|
) {
|
||||||
|
$validator->fail('You have selected SMTP auth but have not configured both username and password');
|
||||||
|
$run_test = 0;
|
||||||
|
}
|
||||||
|
}//end if
|
||||||
|
if ($run_test == 1) {
|
||||||
|
$email = Config::get('alert.default_mail');
|
||||||
|
if ($err = send_mail($email, 'Test email', 'Testing email from NMS')) {
|
||||||
|
$validator->ok('Email has been sent');
|
||||||
|
} else {
|
||||||
|
$validator->fail("Issue sending email to $email with error $err");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}//end if
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
120
LibreNMS/Validations/Php.php
Normal file
120
LibreNMS/Validations/Php.php
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Php.php
|
||||||
|
*
|
||||||
|
* Check that various PHP modules and functions exist.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Php implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
$this->checkVersion($validator);
|
||||||
|
$this->checkExtensions($validator);
|
||||||
|
$this->checkFunctions($validator);
|
||||||
|
$this->checkTimezone($validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkVersion(Validator$validator)
|
||||||
|
{
|
||||||
|
$min_version = '5.6.4';
|
||||||
|
|
||||||
|
// if update is not set to false and version is min or newer
|
||||||
|
if (Config::get('update') && version_compare(PHP_VERSION, $min_version, '<')) {
|
||||||
|
$validator->warn('PHP version 5.6.4 will be the minimum supported version on January 10, 2018. We recommend you update to PHP a supported version of PHP (7.1 suggested) to continue to receive updates. If you do not update PHP, LibreNMS will continue to function but stop receiving bug fixes and updates.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkExtensions(Validator $validator)
|
||||||
|
{
|
||||||
|
$required_modules = array('mysqli','pcre','curl','session','snmp','mcrypt', 'xml', 'gd');
|
||||||
|
foreach ($required_modules as $extension) {
|
||||||
|
if (!extension_loaded($extension)) {
|
||||||
|
$validator->fail("Missing PHP extension: $extension", "Please install $extension");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkFunctions(Validator $validator)
|
||||||
|
{
|
||||||
|
$disabled_functions = explode(',', ini_get('disable_functions'));
|
||||||
|
$required_functions = array(
|
||||||
|
'exec',
|
||||||
|
'passthru',
|
||||||
|
'shell_exec',
|
||||||
|
'escapeshellarg',
|
||||||
|
'escapeshellcmd',
|
||||||
|
'proc_close',
|
||||||
|
'proc_open',
|
||||||
|
'popen'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($required_functions as $function) {
|
||||||
|
if (in_array($function, $disabled_functions)) {
|
||||||
|
$validator->fail("$function is disabled in php.ini");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!function_exists('openssl_random_pseudo_bytes')) {
|
||||||
|
$validator->warn("openssl_random_pseudo_bytes is not being used for user password hashing. This is a recommended function (https://secure.php.net/openssl_random_pseudo_bytes)");
|
||||||
|
if (!is_readable('/dev/urandom')) {
|
||||||
|
$validator->warn("It also looks like we can't use /dev/urandom for user password hashing. We will fall back to generating our own hash - be warned");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkTimezone(Validator $validator)
|
||||||
|
{
|
||||||
|
$ini_tz = ini_get('date.timezone');
|
||||||
|
$sh_tz = rtrim(shell_exec('date +%Z'));
|
||||||
|
$php_tz = date('T');
|
||||||
|
if (empty($ini_tz)) {
|
||||||
|
$validator->fail(
|
||||||
|
'You have no timezone set for php.',
|
||||||
|
'http://php.net/manual/en/datetime.configuration.php#ini.date.timezone'
|
||||||
|
);
|
||||||
|
} elseif ($sh_tz !== $php_tz) {
|
||||||
|
$validator->fail("You have a different system timezone ($sh_tz) specified to the php configured timezone ($php_tz), please correct this.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
104
LibreNMS/Validations/Poller.php
Normal file
104
LibreNMS/Validations/Poller.php
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Poller.php
|
||||||
|
*
|
||||||
|
* Check that the poller and discovery are running properly.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\ValidationResult;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Poller implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
if (dbFetchCell('SELECT COUNT(*) FROM `devices`') == 0) {
|
||||||
|
$result = ValidationResult::warn("You have not added any devices yet.");
|
||||||
|
|
||||||
|
if (isCli()) {
|
||||||
|
$result->setFix("You can add a device in the webui or with ./addhost.php");
|
||||||
|
} else {
|
||||||
|
$base_url = $validator->getBaseURL();
|
||||||
|
$result->setFix("You can add a device by visiting $base_url/addhost");
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator->result($result);
|
||||||
|
return; // can't check poller/discovery if there are no devices.
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME pollers table is only updated by poller-wrapper.py
|
||||||
|
// check poller
|
||||||
|
if (dbFetchCell('SELECT COUNT(*) FROM `pollers`')) {
|
||||||
|
$pollers = dbFetchColumn('SELECT `poller_name` FROM `pollers` WHERE `last_polled` <= DATE_ADD(NOW(), INTERVAL - 5 MINUTE)');
|
||||||
|
if (count($pollers) > 0) {
|
||||||
|
foreach ($pollers as $poller) {
|
||||||
|
$validator->fail("The poller ($poller) has not complete within the last 5 minutes, check the cron job");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$validator->fail('The poller has never run, check the cron job');
|
||||||
|
}
|
||||||
|
|
||||||
|
// check devices polling
|
||||||
|
if (count($devices = dbFetchColumn("SELECT `hostname` FROM `devices` WHERE (`last_polled` < DATE_ADD(NOW(), INTERVAL - 5 MINUTE) OR `last_polled` IS NULL) AND `ignore` = 0 AND `disabled` = 0 AND `status` = 1")) > 0) {
|
||||||
|
$result = ValidationResult::warn("Some devices have not been polled in the last 5 minutes. You may have performance issues.")
|
||||||
|
->setFix('Check your poll log and see: http://docs.librenms.org/Support/Performance/')
|
||||||
|
->setList('Devices', $devices);
|
||||||
|
$validator->result($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($devices = dbFetchColumn('SELECT `hostname` FROM `devices` WHERE last_polled_timetaken > 300 AND `ignore` = 0 AND `disabled` = 0 AND `status` = 1')) > 0) {
|
||||||
|
$result = ValidationResult::fail("Some devices have not completed their polling run in 5 minutes, this will create gaps in data.")
|
||||||
|
->setFix("Check your poll log and refer to http://docs.librenms.org/Support/Performance/")
|
||||||
|
->setList('Devices', $devices);
|
||||||
|
$validator->result($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check discovery last run
|
||||||
|
if (dbFetchCell('SELECT COUNT(*) FROM `devices` WHERE `last_discovered` IS NOT NULL') == 0) {
|
||||||
|
$validator->fail('Discovery has never run.", "Check the cron job');
|
||||||
|
} elseif (dbFetchCell("SELECT COUNT(*) FROM `devices` WHERE `last_discovered` <= DATE_ADD(NOW(), INTERVAL - 24 HOUR) AND `ignore` = 0 AND `disabled` = 0 AND `status` = 1") > 0) {
|
||||||
|
$validator->fail(
|
||||||
|
"Discovery has not completed in the last 24 hours.",
|
||||||
|
"Check the cron job to make sure it is running and using discovery-wrapper.py"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
99
LibreNMS/Validations/Programs.php
Normal file
99
LibreNMS/Validations/Programs.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Programs.php
|
||||||
|
*
|
||||||
|
* Check that external programs exist and are executable.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Programs implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
// Check programs
|
||||||
|
$bins = array('fping', 'fping6', 'rrdtool', 'snmpwalk', 'snmpget', 'snmpbulkwalk');
|
||||||
|
foreach ($bins as $bin) {
|
||||||
|
if (!($cmd = $this->findExecutable($bin))) {
|
||||||
|
$validator->fail(
|
||||||
|
"$bin location is incorrect or bin not installed.",
|
||||||
|
"Install $bin or manually set the path to $bin by placing the following in config.php: " .
|
||||||
|
"\$config['$bin'] = '/path/to/$bin';"
|
||||||
|
);
|
||||||
|
} elseif (in_array($bin, array('fping', 'fping6'))) {
|
||||||
|
if ($validator->getUsername() == 'root' && ($getcap = $this->findExecutable('getcap'))) {
|
||||||
|
if (!str_contains(shell_exec("$getcap $cmd"), "$cmd = cap_net_raw+ep")) {
|
||||||
|
$validator->fail(
|
||||||
|
"$bin should have CAP_NET_RAW!",
|
||||||
|
"getcap c $cmd"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!(fileperms($cmd) & 2048)) {
|
||||||
|
$msg = "$bin should be suid!";
|
||||||
|
$fix = "chmod u+s $cmd";
|
||||||
|
if ($validator->getUsername() == 'root') {
|
||||||
|
$msg .= ' (Note: suid may not be needed if CAP_NET_RAW is set, which requires root to check)';
|
||||||
|
$validator->warn($msg, $fix);
|
||||||
|
} else {
|
||||||
|
$validator->fail($msg, $fix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findExecutable($bin)
|
||||||
|
{
|
||||||
|
if (is_executable(Config::get($bin))) {
|
||||||
|
return Config::get($bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path_dirs = explode(':', getenv('PATH'));
|
||||||
|
foreach ($path_dirs as $dir) {
|
||||||
|
$file = "$dir/$bin";
|
||||||
|
if (is_executable($file)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
99
LibreNMS/Validations/Rrd.php
Normal file
99
LibreNMS/Validations/Rrd.php
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Rrd.php
|
||||||
|
*
|
||||||
|
* -Description-
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Rrd implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
$versions = $validator->getVersions();
|
||||||
|
|
||||||
|
// Check that rrdtool config version is what we see
|
||||||
|
if (Config::has('rrdtool_version')
|
||||||
|
&& version_compare(Config::get('rrdtool_version'), $versions['rrdtool_ver'], '>')
|
||||||
|
) {
|
||||||
|
$validator->fail(
|
||||||
|
'The rrdtool version you have specified is newer than what is installed.',
|
||||||
|
"Either comment out \$config['rrdtool_version'] = '" .
|
||||||
|
Config::get('rrdtool_version') . "'; or set \$config['rrdtool_version'] = '{$versions['rrdtool_ver']}';"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (Config::get('rrdcached')) {
|
||||||
|
self::checkRrdcached($validator);
|
||||||
|
} else {
|
||||||
|
$rrd_dir = Config::get('rrd_dir');
|
||||||
|
|
||||||
|
$dir_stat = stat($rrd_dir);
|
||||||
|
if ($dir_stat[4] == 0 || $dir_stat[5] == 0) {
|
||||||
|
$validator->warn('Your RRD directory is owned by root, please consider changing over to user a non-root user');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (substr(sprintf('%o', fileperms($rrd_dir)), -3) != 775) {
|
||||||
|
$validator->warn('Your RRD directory is not set to 0775', "chmod 775 $rrd_dir}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkRrdcached(Validator $validator)
|
||||||
|
{
|
||||||
|
list($host,$port) = explode(':', Config::get('rrdcached'));
|
||||||
|
if ($host == 'unix') {
|
||||||
|
// Using socket, check that file exists
|
||||||
|
if (!file_exists($port)) {
|
||||||
|
$validator->fail("$port doesn't appear to exist, rrdcached test failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$connection = @fsockopen($host, $port);
|
||||||
|
if (is_resource($connection)) {
|
||||||
|
fclose($connection);
|
||||||
|
} else {
|
||||||
|
$validator->fail('Cannot connect to rrdcached instance');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
LibreNMS/Validations/RrdCheck.php
Normal file
92
LibreNMS/Validations/RrdCheck.php
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* RrdCheck.php
|
||||||
|
*
|
||||||
|
* Scan RRD files for errors.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\RRDRecursiveFilterIterator;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
|
||||||
|
class RrdCheck implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
// Loop through the rrd_dir
|
||||||
|
$rrd_directory = new RecursiveDirectoryIterator(Config::get('rrd_dir'));
|
||||||
|
// Filter out any non rrd files
|
||||||
|
$rrd_directory_filter = new RRDRecursiveFilterIterator($rrd_directory);
|
||||||
|
$rrd_iterator = new RecursiveIteratorIterator($rrd_directory_filter);
|
||||||
|
$rrd_total = iterator_count($rrd_iterator);
|
||||||
|
$rrd_iterator->rewind(); // Rewind iterator in case iterator_count left iterator in unknown state
|
||||||
|
|
||||||
|
echo "\nScanning " . $rrd_total . " rrd files in " . Config::get('rrd_dir') . "...\n";
|
||||||
|
|
||||||
|
// Count loops so we can push status to the user
|
||||||
|
$loopcount = 0;
|
||||||
|
$screenpad = 0;
|
||||||
|
|
||||||
|
foreach ($rrd_iterator as $filename => $file) {
|
||||||
|
$rrd_test_result = rrdtest($filename, $output, $error);
|
||||||
|
|
||||||
|
$loopcount++;
|
||||||
|
if (($loopcount % 50) == 0) {
|
||||||
|
//This lets us update the previous status update without spamming in most consoles
|
||||||
|
echo "\033[" . $screenpad . "D";
|
||||||
|
$test_status = 'Status: ' . $loopcount . '/' . $rrd_total;
|
||||||
|
echo $test_status;
|
||||||
|
$screenpad = strlen($test_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A non zero result means there was some kind of error
|
||||||
|
if ($rrd_test_result > 0) {
|
||||||
|
echo "\033[" . $screenpad . "D";
|
||||||
|
$validator->fail('Error parsing "' . $filename . '" RRD ' . trim($error));
|
||||||
|
$screenpad = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\033[" . $screenpad . "D";
|
||||||
|
echo "Status: " . $loopcount . "/" . $rrd_total . " - Complete\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
96
LibreNMS/Validations/Updates.php
Normal file
96
LibreNMS/Validations/Updates.php
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Updates.php
|
||||||
|
*
|
||||||
|
* Checks the status of git and updates.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
|
use Exception;
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\ValidationResult;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class Updates implements ValidationGroup
|
||||||
|
{
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
// if git is not available, we cannot do the other tests
|
||||||
|
if (!check_git_exists()) {
|
||||||
|
$validator->warn('Unable to locate git. This should probably be installed.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$versions = $validator->getVersions(true);
|
||||||
|
|
||||||
|
// check if users on master update channel are up to date
|
||||||
|
if (Config::get('update_channel') == 'master') {
|
||||||
|
if ($versions['local_sha'] != $versions['github']['sha']) {
|
||||||
|
try {
|
||||||
|
$commit_date = new DateTime('@' . $versions['local_date'], new DateTimeZone(date_default_timezone_get()));
|
||||||
|
if ($commit_date->diff(new DateTime())->days > 0) {
|
||||||
|
$validator->warn(
|
||||||
|
"Your install is over 24 hours out of date, last update: " . $commit_date->format('r'),
|
||||||
|
'Make sure your daily.sh cron is running and run ./daily.sh by hand to see if there are any errors.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$validator->fail($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($versions['local_branch'] != 'master') {
|
||||||
|
$validator->warn(
|
||||||
|
"Your local git branch is not master, this will prevent automatic updates.",
|
||||||
|
"You can switch back to master with git checkout master"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO check update channel stable version
|
||||||
|
|
||||||
|
// check for modified files
|
||||||
|
$modifiedcmd = 'git diff --name-only --exit-code';
|
||||||
|
$validator->execAsUser($modifiedcmd, $cmdoutput, $code);
|
||||||
|
if ($code !== 0 && !empty($cmdoutput)) {
|
||||||
|
$result = ValidationResult::warn(
|
||||||
|
"Your local git contains modified files, this could prevent automatic updates.",
|
||||||
|
"You can fix this with ./scripts/github-remove"
|
||||||
|
);
|
||||||
|
$result->setList('Modified Files', $cmdoutput);
|
||||||
|
$validator->result($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
129
LibreNMS/Validations/User.php
Normal file
129
LibreNMS/Validations/User.php
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* User.php
|
||||||
|
*
|
||||||
|
* Check that user is set properly and we are running as the correct user. Check that user is the owner of install_dir.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS\Validations;
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Interfaces\ValidationGroup;
|
||||||
|
use LibreNMS\ValidationResult;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
class User implements ValidationGroup
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate this module.
|
||||||
|
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
|
||||||
|
*
|
||||||
|
* @param Validator $validator
|
||||||
|
*/
|
||||||
|
public function validate(Validator $validator)
|
||||||
|
{
|
||||||
|
// Check we are running this as the root user
|
||||||
|
$username = $validator->getUsername();
|
||||||
|
$lnms_username = Config::get('user');
|
||||||
|
$lnms_groupname = Config::get('group', $lnms_username); // if group isn't set, fall back to user
|
||||||
|
|
||||||
|
if (!($username === 'root' || $username === $lnms_username)) {
|
||||||
|
if (isCli()) {
|
||||||
|
$validator->fail('You need to run this script as root' .
|
||||||
|
(Config::has('user') ? ' or ' . $lnms_username : ''));
|
||||||
|
} else {
|
||||||
|
$lnms_group = posix_getgrnam($lnms_groupname);
|
||||||
|
if (!in_array($username, $lnms_group['members'])) {
|
||||||
|
$validator->fail(
|
||||||
|
"Your web server or php-fpm is not running as user '$lnms_username' or in the group '$lnms_groupname''",
|
||||||
|
"usermod -a -G $lnms_groupname $username"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Let's test the user configured if we have it
|
||||||
|
if (Config::has('user')) {
|
||||||
|
$dir = Config::get('install_dir');
|
||||||
|
|
||||||
|
$find_result = rtrim(`find $dir \! -user $lnms_username -o \! -group $lnms_groupname &> /dev/null`);
|
||||||
|
if (!empty($find_result)) {
|
||||||
|
// Ignore the two logs that may be created by the
|
||||||
|
$files = array_diff(explode(PHP_EOL, $find_result), array(
|
||||||
|
"$dir/logs/error_log",
|
||||||
|
"$dir/logs/access_log",
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!empty($files)) {
|
||||||
|
$result = ValidationResult::fail(
|
||||||
|
"We have found some files that are owned by a different user than $lnms_username, this " .
|
||||||
|
'will stop you updating automatically and / or rrd files being updated causing graphs to fail.'
|
||||||
|
)
|
||||||
|
->setFix("chown -R $lnms_username:$lnms_groupname $dir")
|
||||||
|
->setList('Files', $files);
|
||||||
|
|
||||||
|
$validator->result($result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$validator->warn("You don't have \$config['user'] set, this most likely needs to be set to librenms");
|
||||||
|
}
|
||||||
|
|
||||||
|
// check permissions
|
||||||
|
$rrd_dir = Config::get('rrd_dir');
|
||||||
|
if (!$this->checkFilePermissions($rrd_dir, '660')) {
|
||||||
|
$validator->fail("The rrd folder has improper permissions.", "chmod ug+rw $rrd_dir");
|
||||||
|
}
|
||||||
|
|
||||||
|
$log_dir = Config::get('log_dir');
|
||||||
|
if (!$this->checkFilePermissions($log_dir, '660')) {
|
||||||
|
$validator->fail("The log folder has improper permissions.", "chmod ug+rw $log_dir");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks file permissions against a minimum permissions mask.
|
||||||
|
* This only check that bits are enabled, not disabled.
|
||||||
|
* The mask is in the same format as posix permissions. For example, 600 means user read and write.
|
||||||
|
*
|
||||||
|
* @param string $file the name of the file to check
|
||||||
|
* @param $mask
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkFilePermissions($file, $mask)
|
||||||
|
{
|
||||||
|
$perms = fileperms($file);
|
||||||
|
$mask = octdec($mask);
|
||||||
|
|
||||||
|
return ($perms & $mask) === $mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if this test should be run by default or not.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDefault()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
273
LibreNMS/Validator.php
Normal file
273
LibreNMS/Validator.php
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Validator.php
|
||||||
|
*
|
||||||
|
* Class to run validations. Also allows sharing data between ValidationGroups.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace LibreNMS;
|
||||||
|
|
||||||
|
class Validator
|
||||||
|
{
|
||||||
|
private $validation_groups = array();
|
||||||
|
private $results = array();
|
||||||
|
|
||||||
|
// data cache
|
||||||
|
private $username;
|
||||||
|
private $versions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validator constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// load all validations
|
||||||
|
$pattern = Config::get('install_dir') . '/LibreNMS/Validations/*.php';
|
||||||
|
|
||||||
|
foreach (glob($pattern) as $file) {
|
||||||
|
$class_name = basename($file, '.php');
|
||||||
|
$class = '\LibreNMS\Validations\\' . $class_name;
|
||||||
|
$validation_name = strtolower($class_name);
|
||||||
|
$this->validation_groups[$validation_name] = new $class();
|
||||||
|
$this->results[$validation_name] = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run validations. An empty array will run all default validations.
|
||||||
|
*
|
||||||
|
* @param array $validation_groups selected validation groups to run
|
||||||
|
* @param bool $print_group_status print out group status
|
||||||
|
*/
|
||||||
|
public function validate($validation_groups = array(), $print_group_status = false)
|
||||||
|
{
|
||||||
|
foreach ($this->validation_groups as $group_name => $group) {
|
||||||
|
if ((empty($validation_groups) && $group->isDefault()) || in_array($group_name, $validation_groups)) {
|
||||||
|
if ($print_group_status && isCli()) {
|
||||||
|
echo "Checking $group_name:";
|
||||||
|
}
|
||||||
|
|
||||||
|
$group->validate($this);
|
||||||
|
|
||||||
|
if (isCli()) {
|
||||||
|
if ($print_group_status) {
|
||||||
|
$status = ValidationResult::getStatusText($this->getGroupStatus($group_name));
|
||||||
|
c_echo(" $status\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->printResults($group_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the overall status of a validation group.
|
||||||
|
*
|
||||||
|
* @param string $validation_group
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getGroupStatus($validation_group)
|
||||||
|
{
|
||||||
|
$results = $this->getResults($validation_group);
|
||||||
|
|
||||||
|
$status = array_reduce($results, function ($compound, $result) {
|
||||||
|
/** @var ValidationResult $result */
|
||||||
|
return min($compound, $result->getStatus());
|
||||||
|
}, ValidationResult::SUCCESS);
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ValidationResults for a specific validation group.
|
||||||
|
*
|
||||||
|
* @param string $validation_group
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResults($validation_group = null)
|
||||||
|
{
|
||||||
|
if (isset($validation_group)) {
|
||||||
|
if (isset($this->results[$validation_group])) {
|
||||||
|
return $this->results[$validation_group];
|
||||||
|
} else {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_reduce($this->results, 'array_merge', array());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all of the ValidationResults that have been submitted.
|
||||||
|
* ValidationResults will be grouped by the validation group.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllResults()
|
||||||
|
{
|
||||||
|
return $this->results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print all ValidationResults or a group of them.
|
||||||
|
*
|
||||||
|
* @param string $validation_group
|
||||||
|
*/
|
||||||
|
public function printResults($validation_group = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
$results = $this->getResults($validation_group);
|
||||||
|
|
||||||
|
foreach ($results as $result) {
|
||||||
|
/** @var ValidationResult $result */
|
||||||
|
$result->consolePrint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a validation result.
|
||||||
|
* This allows customizing ValidationResults before submitting.
|
||||||
|
*
|
||||||
|
* @param ValidationResult $result
|
||||||
|
* @param string $group manually specify the group, otherwise this will be inferred from the callers class name
|
||||||
|
*/
|
||||||
|
public function result(ValidationResult $result, $group = null)
|
||||||
|
{
|
||||||
|
// get the name of the validation that submitted this result
|
||||||
|
if (empty($group)) {
|
||||||
|
$group = 'unknown';
|
||||||
|
$bt = debug_backtrace();
|
||||||
|
foreach ($bt as $entry) {
|
||||||
|
if (starts_with($entry['class'], 'LibreNMS\Validations')) {
|
||||||
|
$group = str_replace('LibreNMS\Validations\\', '', $entry['class']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->results[strtolower($group)][] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit an ok validation result.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param string $fix
|
||||||
|
* @param string $group manually specify the group, otherwise this will be inferred from the callers class name
|
||||||
|
|
||||||
|
*/
|
||||||
|
public function ok($message, $fix = null, $group = null)
|
||||||
|
{
|
||||||
|
$this->result(new ValidationResult($message, ValidationResult::SUCCESS, $fix), $group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a warning validation result.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param string $fix
|
||||||
|
* @param string $group manually specify the group, otherwise this will be inferred from the callers class name
|
||||||
|
*/
|
||||||
|
public function warn($message, $fix = null, $group = null)
|
||||||
|
{
|
||||||
|
$this->result(new ValidationResult($message, ValidationResult::WARNING, $fix), $group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a failed validation result.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param string $fix
|
||||||
|
* @param string $group manually specify the group, otherwise this will be inferred from the callers class name
|
||||||
|
*/
|
||||||
|
public function fail($message, $fix = null, $group = null)
|
||||||
|
{
|
||||||
|
$this->result(new ValidationResult($message, ValidationResult::FAILURE, $fix), $group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get version_info() array. This will cache the result and add remote data if requested and not already existing.
|
||||||
|
*
|
||||||
|
* @param bool $remote
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getVersions($remote = false)
|
||||||
|
{
|
||||||
|
if (!isset($this->versions)) {
|
||||||
|
$this->versions = version_info($remote);
|
||||||
|
} else {
|
||||||
|
if ($remote && !isset($this->versions['github'])) {
|
||||||
|
$this->versions = version_info($remote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a command, but don't run it as root. If we are root, run as the LibreNMS user.
|
||||||
|
* Arguments match exec()
|
||||||
|
*
|
||||||
|
* @param string $command the command to run
|
||||||
|
* @param array $output will hold the output of the command
|
||||||
|
* @param int $code will hold the return code from the command
|
||||||
|
*/
|
||||||
|
public function execAsUser($command, &$output = null, &$code = null)
|
||||||
|
{
|
||||||
|
if (self::getUsername() === 'root') {
|
||||||
|
$command = 'su ' . Config::get('user') . ' -c "' . $command . '"';
|
||||||
|
}
|
||||||
|
exec($command, $output, $code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the username of the user running this and cache it for future requests.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUsername()
|
||||||
|
{
|
||||||
|
if (!isset($this->username)) {
|
||||||
|
if (function_exists('posix_getpwuid')) {
|
||||||
|
$userinfo = posix_getpwuid(posix_geteuid());
|
||||||
|
$this->username = $userinfo['name'];
|
||||||
|
} else {
|
||||||
|
$this->username = getenv('USERNAME') ?: getenv('USER');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the base url for this LibreNMS install, this will only work from web pages.
|
||||||
|
* (unless base_url is set)
|
||||||
|
*
|
||||||
|
* @return string the base url without a trailing /
|
||||||
|
*/
|
||||||
|
public function getBaseURL()
|
||||||
|
{
|
||||||
|
$url = Config::get('base_url', get_url());
|
||||||
|
return rtrim(str_replace('validate', '', $url), '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,7 +63,7 @@ if (isset($options['i']) && $options['i'] && isset($options['n'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['d']) || isset($options['v'])) {
|
if (isset($options['d']) || isset($options['v'])) {
|
||||||
$versions = version_info(false);
|
$versions = version_info();
|
||||||
echo <<<EOH
|
echo <<<EOH
|
||||||
===================================
|
===================================
|
||||||
Version info:
|
Version info:
|
||||||
|
|||||||
@@ -143,16 +143,20 @@ Now head to the web installer and follow the on-screen instructions.
|
|||||||
|
|
||||||
### Final steps
|
### Final steps
|
||||||
|
|
||||||
Run validate.php as root in the librenms directory:
|
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
||||||
|
|
||||||
|
#### Add the first device
|
||||||
|
|
||||||
|
We now suggest that you add localhost as your first device from within the WebUI.
|
||||||
|
|
||||||
|
#### Troubleshooting
|
||||||
|
|
||||||
|
If you ever have issues with your install, run validate.php as root in the librenms directory:
|
||||||
|
|
||||||
cd /opt/librenms
|
cd /opt/librenms
|
||||||
./validate.php
|
./validate.php
|
||||||
|
|
||||||
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
There are various options for getting help listed on the LibreNMS web site: https://www.librenms.org/#support
|
||||||
|
|
||||||
#### Add first device
|
|
||||||
|
|
||||||
We now suggest that you add localhost as your first device from within the WebUI.
|
|
||||||
|
|
||||||
### What next?
|
### What next?
|
||||||
|
|
||||||
@@ -167,4 +171,4 @@ Now that you've installed LibreNMS, we'd suggest that you have a read of a few o
|
|||||||
|
|
||||||
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
||||||
|
|
||||||
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [support our Collective](https://t.libren.ms/donations).
|
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [back LibreNMS on Open Collective](https://t.libren.ms/donations).
|
||||||
|
|||||||
@@ -178,16 +178,20 @@ Now head to the web installer and follow the on-screen instructions.
|
|||||||
|
|
||||||
### Final steps
|
### Final steps
|
||||||
|
|
||||||
Run validate.php as root in the librenms directory:
|
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
||||||
|
|
||||||
|
#### Add the first device
|
||||||
|
|
||||||
|
We now suggest that you add localhost as your first device from within the WebUI.
|
||||||
|
|
||||||
|
#### Troubleshooting
|
||||||
|
|
||||||
|
If you ever have issues with your install, run validate.php as root in the librenms directory:
|
||||||
|
|
||||||
cd /opt/librenms
|
cd /opt/librenms
|
||||||
./validate.php
|
./validate.php
|
||||||
|
|
||||||
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
There are various options for getting help listed on the LibreNMS web site: https://www.librenms.org/#support
|
||||||
|
|
||||||
#### Add first device
|
|
||||||
|
|
||||||
We now suggest that you add localhost as your first device from within the WebUI.
|
|
||||||
|
|
||||||
### What next?
|
### What next?
|
||||||
|
|
||||||
@@ -202,4 +206,4 @@ Now that you've installed LibreNMS, we'd suggest that you have a read of a few o
|
|||||||
|
|
||||||
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
||||||
|
|
||||||
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [support our Collective](https://t.libren.ms/donations).
|
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [back LibreNMS on Open Collective](https://t.libren.ms/donations).
|
||||||
|
|||||||
@@ -120,16 +120,20 @@ Now head to the web installer and follow the on-screen instructions.
|
|||||||
|
|
||||||
### Final steps
|
### Final steps
|
||||||
|
|
||||||
Run validate.php as root in the librenms directory:
|
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
||||||
|
|
||||||
|
#### Add the first device
|
||||||
|
|
||||||
|
We now suggest that you add localhost as your first device from within the WebUI.
|
||||||
|
|
||||||
|
#### Troubleshooting
|
||||||
|
|
||||||
|
If you ever have issues with your install, run validate.php as root in the librenms directory:
|
||||||
|
|
||||||
cd /opt/librenms
|
cd /opt/librenms
|
||||||
./validate.php
|
./validate.php
|
||||||
|
|
||||||
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
There are various options for getting help listed on the LibreNMS web site: https://www.librenms.org/#support
|
||||||
|
|
||||||
#### Add first device
|
|
||||||
|
|
||||||
We now suggest that you add localhost as your first device from within the WebUI.
|
|
||||||
|
|
||||||
### What next?
|
### What next?
|
||||||
|
|
||||||
@@ -144,4 +148,4 @@ Now that you've installed LibreNMS, we'd suggest that you have a read of a few o
|
|||||||
|
|
||||||
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
||||||
|
|
||||||
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [support our Collective](https://t.libren.ms/donations).
|
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [back LibreNMS on Open Collective](https://t.libren.ms/donations).
|
||||||
|
|||||||
@@ -126,16 +126,20 @@ Now head to the web installer and follow the on-screen instructions.
|
|||||||
|
|
||||||
### Final steps
|
### Final steps
|
||||||
|
|
||||||
Run validate.php as root in the librenms directory:
|
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
||||||
|
|
||||||
|
#### Add the first device
|
||||||
|
|
||||||
|
We now suggest that you add localhost as your first device from within the WebUI.
|
||||||
|
|
||||||
|
#### Troubleshooting
|
||||||
|
|
||||||
|
If you ever have issues with your install, run validate.php as root in the librenms directory:
|
||||||
|
|
||||||
cd /opt/librenms
|
cd /opt/librenms
|
||||||
./validate.php
|
./validate.php
|
||||||
|
|
||||||
That's it! You now should be able to log in to http://librenms.example.com/. Please note that we have not covered HTTPS setup in this example, so your LibreNMS install is not secure by default. Please do not expose it to the public Internet unless you have configured HTTPS and taken appropriate web server hardening steps.
|
There are various options for getting help listed on the LibreNMS web site: https://www.librenms.org/#support
|
||||||
|
|
||||||
#### Add first device
|
|
||||||
|
|
||||||
We now suggest that you add localhost as your first device from within the WebUI.
|
|
||||||
|
|
||||||
### What next?
|
### What next?
|
||||||
|
|
||||||
@@ -150,4 +154,4 @@ Now that you've installed LibreNMS, we'd suggest that you have a read of a few o
|
|||||||
|
|
||||||
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
We hope you enjoy using LibreNMS. If you do, it would be great if you would consider opting into the stats system we have, please see [this page](http://docs.librenms.org/General/Callback-Stats-and-Privacy/) on what it is and how to enable it.
|
||||||
|
|
||||||
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [support our Collective](https://t.libren.ms/donations).
|
If you would like to help make LibreNMS better there are [many ways to help](http://docs.librenms.org/Support/FAQ/#what-can-i-do-to-help). You can also [back LibreNMS on Open Collective](https://t.libren.ms/donations).
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ function nicecase($item)
|
|||||||
|
|
||||||
case 'nfs-v3-stats':
|
case 'nfs-v3-stats':
|
||||||
return 'NFS v3 Stats';
|
return 'NFS v3 Stats';
|
||||||
|
|
||||||
case 'nfs-server':
|
case 'nfs-server':
|
||||||
return 'NFS Server';
|
return 'NFS Server';
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ function nicecase($item)
|
|||||||
|
|
||||||
case 'fbsd-nfs-server':
|
case 'fbsd-nfs-server':
|
||||||
return 'FreeBSD NFS Server';
|
return 'FreeBSD NFS Server';
|
||||||
|
|
||||||
case 'php-fpm':
|
case 'php-fpm':
|
||||||
return 'PHP-FPM';
|
return 'PHP-FPM';
|
||||||
|
|
||||||
@@ -163,6 +163,20 @@ function toner2colour($descr, $percent)
|
|||||||
}//end toner2colour()
|
}//end toner2colour()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all links in some text and turn them into html links.
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function linkify($text)
|
||||||
|
{
|
||||||
|
$regex = "/(http|https|ftp|ftps):\/\/[a-z0-9\-.]+\.[a-z]{2,5}(\/\S*)?/i";
|
||||||
|
|
||||||
|
return preg_replace($regex, '<a href="$0">$0</a>', $text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function generate_link($text, $vars, $new_vars = array())
|
function generate_link($text, $vars, $new_vars = array())
|
||||||
{
|
{
|
||||||
return '<a href="'.generate_url($vars, $new_vars).'">'.$text.'</a>';
|
return '<a href="'.generate_url($vars, $new_vars).'">'.$text.'</a>';
|
||||||
|
|||||||
@@ -641,6 +641,7 @@ if ($_SESSION['authenticated']) {
|
|||||||
<?php
|
<?php
|
||||||
if ($_SESSION['userlevel'] >= '10') {
|
if ($_SESSION['userlevel'] >= '10') {
|
||||||
echo('<li><a href="settings/"><i class="fa fa-cogs fa-fw fa-lg" aria-hidden="true"></i> Global Settings</a></li>');
|
echo('<li><a href="settings/"><i class="fa fa-cogs fa-fw fa-lg" aria-hidden="true"></i> Global Settings</a></li>');
|
||||||
|
echo('<li><a href="validate/"><i class="fa fa-check-circle fa-fw fa-lg" aria-hidden="true"></i> Validate Config</a></li>');
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -11,14 +11,15 @@ if (empty($_POST) && !empty($_SESSION) && !isset($_REQUEST['stage'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$stage = isset($_POST['stage']) ? $_POST['stage'] : 0;
|
//$stage = isset($_POST['stage']) ? $_POST['stage'] : 0;
|
||||||
|
$stage = 6;
|
||||||
|
|
||||||
// Before we do anything, if we see config.php, redirect back to the homepage.
|
// Before we do anything, if we see config.php, redirect back to the homepage.
|
||||||
if (file_exists('../config.php') && $stage != 6) {
|
//if (file_exists('../config.php') && $stage != 6) {
|
||||||
unset($_SESSION['stage']);
|
// unset($_SESSION['stage']);
|
||||||
header("Location: /");
|
// header("Location: /");
|
||||||
exit;
|
// exit;
|
||||||
}
|
//}
|
||||||
|
|
||||||
// do not use the DB in init, we'll bring it up ourselves
|
// do not use the DB in init, we'll bring it up ourselves
|
||||||
$init_modules = array('web', 'nodb');
|
$init_modules = array('web', 'nodb');
|
||||||
@@ -507,16 +508,19 @@ if (auth_usermanagement()) {
|
|||||||
?>
|
?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-offset-3 col-md-6">
|
<div class="col-md-offset-3 col-md-6">
|
||||||
<div class="alert alert-danger">You haven't quite finished yet - please go back to the install docs and carry on the necessary steps to finish the setup!</div>
|
<div class="alert alert-danger">
|
||||||
|
<p>You haven't quite finished yet!</p>
|
||||||
|
<p>First, you need to <a href="validate/">validate your install and fix any issues.</a></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="alert alert-success">Thank you for setting up LibreNMS.<br />
|
<div class="alert alert-success">
|
||||||
It would be great if you would consider contributing to our statistics, you can do this on the <a href="about/">/about/</a> page and check the box under Statistics.<br />
|
<p>Thank you for setting up LibreNMS.</p>
|
||||||
You can now click <a href="/">here to login to your new install.</a></div>
|
<p>It would be great if you would consider contributing to our statistics, you can do this on the <a href="about/">About LibreNMS Page</a> and check the box under Statistics.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ echo "
|
|||||||
|
|
||||||
<h3>LibreNMS is an autodiscovering PHP/MySQL-based network monitoring system.</h3>
|
<h3>LibreNMS is an autodiscovering PHP/MySQL-based network monitoring system.</h3>
|
||||||
<?php
|
<?php
|
||||||
$versions = version_info(false);
|
$versions = version_info();
|
||||||
$project_name = $config['project_name'];
|
$project_name = $config['project_name'];
|
||||||
$webserv_version = $_SERVER['SERVER_SOFTWARE'];
|
$webserv_version = $_SERVER['SERVER_SOFTWARE'];
|
||||||
$php_version = $versions['php_ver'];
|
$php_version = $versions['php_ver'];
|
||||||
|
|||||||
140
html/pages/validate.inc.php
Normal file
140
html/pages/validate.inc.php
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* validate.inc.php
|
||||||
|
*
|
||||||
|
* -Description-
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @package LibreNMS
|
||||||
|
* @link http://librenms.org
|
||||||
|
* @copyright 2017 Tony Murray
|
||||||
|
* @author Tony Murray <murraytony@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
use LibreNMS\ValidationResult;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container-fluid" id="messagebox">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<span id="message"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
$validator = new Validator();
|
||||||
|
$validator->validate();
|
||||||
|
|
||||||
|
foreach ($validator->getAllResults() as $group => $results) {
|
||||||
|
echo '<div class="panel-group"><div class="panel panel-default"><div class="panel-heading"> ';
|
||||||
|
echo "<h4 class='panel-title'><a data-toggle='collapse' data-target='#${group}Body'>";
|
||||||
|
echo ucfirst($group);
|
||||||
|
|
||||||
|
$group_status = $validator->getGroupStatus($group);
|
||||||
|
|
||||||
|
if ($group_status == ValidationResult::SUCCESS) {
|
||||||
|
echo ' <span class="text-success pull-right">Ok</span>';
|
||||||
|
} elseif ($group_status == ValidationResult::WARNING) {
|
||||||
|
echo ' <span class="text-warning pull-right">Warning</span>';
|
||||||
|
} elseif ($group_status == ValidationResult::FAILURE) {
|
||||||
|
echo ' <span class="text-danger pull-right">Failure</span>';
|
||||||
|
}
|
||||||
|
echo "</a></h4>";
|
||||||
|
echo " </div><div id='${group}Body' class='panel-collapse collapse";
|
||||||
|
if ($group_status !== ValidationResult::SUCCESS) {
|
||||||
|
echo ' in';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "'><div class='panel-body'>";
|
||||||
|
|
||||||
|
foreach ($results as $rnum => $result) {
|
||||||
|
/** @var ValidationResult $result */
|
||||||
|
|
||||||
|
echo '<div class="panel"><div class="panel-heading';
|
||||||
|
if ($result->getStatus() == ValidationResult::SUCCESS) {
|
||||||
|
echo ' bg-success"> Ok: ';
|
||||||
|
} elseif ($result->getStatus() == ValidationResult::WARNING) {
|
||||||
|
echo ' bg-warning"> Warning: ';
|
||||||
|
} elseif ($result->getStatus() == ValidationResult::FAILURE) {
|
||||||
|
echo ' bg-danger"> Fail: ';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $result->getMessage();
|
||||||
|
echo '</div>';
|
||||||
|
|
||||||
|
if ($result->hasFix() || $result->hasList()) {
|
||||||
|
echo '<div class="panel-body">';
|
||||||
|
if ($result->hasFix()) {
|
||||||
|
echo '<p class="bg-danger text-danger">' . linkify($result->getFix()) . '</p>';
|
||||||
|
if ($result->hasList()) {
|
||||||
|
echo '<br />';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result->hasList()) {
|
||||||
|
$list = $result->getList();
|
||||||
|
$short_size = 10;
|
||||||
|
|
||||||
|
|
||||||
|
echo "<ul id='shortList$group$rnum' class='list-group' style='margin-bottom: -1px'>";
|
||||||
|
echo "<li class='list-group-item active'>" . $result->getListDescription() . "</li>";
|
||||||
|
|
||||||
|
foreach (array_slice($list, 0, $short_size) as $li) {
|
||||||
|
echo "<li class='list-group-item'>$li</li>";
|
||||||
|
}
|
||||||
|
echo '</ul>';
|
||||||
|
|
||||||
|
if (count($list) > $short_size) {
|
||||||
|
echo "<button style='margin-top: 3px' type='button' class='btn btn-default' id='button$group$rnum'";
|
||||||
|
echo " onclick='expandList(\"$group$rnum\");'>Show all</button>";
|
||||||
|
|
||||||
|
echo "<ul id='extraList$group$rnum' class='list-group' style='display:none'>";
|
||||||
|
|
||||||
|
foreach (array_slice($list, $short_size) as $li) {
|
||||||
|
echo "<li class='list-group-item'>$li</li>";
|
||||||
|
}
|
||||||
|
echo '</ul>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
echo '</div></div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function expandList($id) {
|
||||||
|
var item = $("#extraList" + $id);
|
||||||
|
console.log(item);
|
||||||
|
$("#extraList" + $id).show();
|
||||||
|
$("#button" + $id).hide();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -20,7 +20,7 @@ if ($enabled == 1) {
|
|||||||
|
|
||||||
$uuid = dbFetchCell("SELECT `value` FROM `callback` WHERE `name` = 'uuid'");
|
$uuid = dbFetchCell("SELECT `value` FROM `callback` WHERE `name` = 'uuid'");
|
||||||
|
|
||||||
$version = version_info(false);
|
$version = version_info();
|
||||||
$queries = array(
|
$queries = array(
|
||||||
'alert_rules' => 'SELECT COUNT(`severity`) AS `total`,`severity` FROM `alert_rules` WHERE `disabled`=0 GROUP BY `severity`',
|
'alert_rules' => 'SELECT COUNT(`severity`) AS `total`,`severity` FROM `alert_rules` WHERE `disabled`=0 GROUP BY `severity`',
|
||||||
'alert_templates' => 'SELECT COUNT(`id`) AS `total` FROM `alert_templates`',
|
'alert_templates' => 'SELECT COUNT(`id`) AS `total` FROM `alert_templates`',
|
||||||
|
|||||||
@@ -1104,9 +1104,10 @@ function parse_location($location)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns version info
|
* Returns version info
|
||||||
|
* @param bool $remote fetch remote version info from github
|
||||||
* @return array
|
* @return array
|
||||||
**/
|
*/
|
||||||
function version_info($remote = true)
|
function version_info($remote = false)
|
||||||
{
|
{
|
||||||
global $config;
|
global $config;
|
||||||
$output = array();
|
$output = array();
|
||||||
|
|||||||
@@ -853,7 +853,7 @@ $config['api_demo'] = 0;
|
|||||||
// Set this to 1 if you want to disable some untrusting features for the API
|
// Set this to 1 if you want to disable some untrusting features for the API
|
||||||
// Distributed Poller-Settings
|
// Distributed Poller-Settings
|
||||||
$config['distributed_poller'] = false;
|
$config['distributed_poller'] = false;
|
||||||
$config['distributed_poller_name'] = file_get_contents('/proc/sys/kernel/hostname');
|
$config['distributed_poller_name'] = trim(file_get_contents('/proc/sys/kernel/hostname'));
|
||||||
$config['distributed_poller_group'] = 0;
|
$config['distributed_poller_group'] = 0;
|
||||||
$config['distributed_poller_memcached_host'] = 'example.net';
|
$config['distributed_poller_memcached_host'] = 'example.net';
|
||||||
$config['distributed_poller_memcached_port'] = '11211';
|
$config['distributed_poller_memcached_port'] = '11211';
|
||||||
|
|||||||
@@ -2196,15 +2196,20 @@ function dump_db_schema()
|
|||||||
|
|
||||||
foreach (dbFetchRows("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '{$config['db_name']}' ORDER BY TABLE_NAME;") as $table) {
|
foreach (dbFetchRows("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '{$config['db_name']}' ORDER BY TABLE_NAME;") as $table) {
|
||||||
$table = $table['TABLE_NAME'];
|
$table = $table['TABLE_NAME'];
|
||||||
foreach (dbFetchRows("SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '{$config['db_name']}' AND TABLE_NAME='$table' ORDER BY COLUMN_NAME") as $data) {
|
foreach (dbFetchRows("SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '{$config['db_name']}' AND TABLE_NAME='$table'") as $data) {
|
||||||
$column = $data['COLUMN_NAME'];
|
$def = array(
|
||||||
$output[$table]['Columns'][$column] = array(
|
|
||||||
'Field' => $data['COLUMN_NAME'],
|
'Field' => $data['COLUMN_NAME'],
|
||||||
'Type' => $data['COLUMN_TYPE'],
|
'Type' => $data['COLUMN_TYPE'],
|
||||||
'Null' => $data['IS_NULLABLE'] === 'YES',
|
'Null' => $data['IS_NULLABLE'] === 'YES',
|
||||||
'Default' => isset($data['COLUMN_DEFAULT']) ? trim($data['COLUMN_DEFAULT'], "'") : 'NULL',
|
'Extra' => str_replace('current_timestamp()', 'CURRENT_TIMESTAMP', $data['EXTRA']),
|
||||||
'Extra' => $data['EXTRA'],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isset($data['COLUMN_DEFAULT']) && $data['COLUMN_DEFAULT'] != 'NULL') {
|
||||||
|
$default = trim($data['COLUMN_DEFAULT'], "'");
|
||||||
|
$def['Default'] = str_replace('current_timestamp()', 'CURRENT_TIMESTAMP', $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
$output[$table]['Columns'][] = $def;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (dbFetchRows("SHOW INDEX FROM `$table`") as $key) {
|
foreach (dbFetchRows("SHOW INDEX FROM `$table`") as $key) {
|
||||||
@@ -2224,45 +2229,6 @@ function dump_db_schema()
|
|||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate an SQL segment to create the column based on data from dump_db_schema()
|
|
||||||
*
|
|
||||||
* @param array $column_data The array of data for the column
|
|
||||||
* @return string sql fragment, for example: "`ix_id` int(10) unsigned NOT NULL"
|
|
||||||
*/
|
|
||||||
function column_schema_to_sql($column_data)
|
|
||||||
{
|
|
||||||
$null = $column_data['Null'] ? 'NULL' : 'NOT NULL';
|
|
||||||
$default = $column_data['Default'] == '' ? '' : "DEFAULT '{$column_data['Default']}'";
|
|
||||||
if (str_contains($default, 'CURRENT_TIMESTAMP')) {
|
|
||||||
$default = str_replace("'", "", $default);
|
|
||||||
}
|
|
||||||
return trim("`{$column_data['Field']}` {$column_data['Type']} $null $default {$column_data['Extra']}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate an SQL segment to create the index based on data from dump_db_schema()
|
|
||||||
*
|
|
||||||
* @param array $index_data The array of data for the index
|
|
||||||
* @return string sql fragment, for example: "PRIMARY KEY (`device_id`)"
|
|
||||||
*/
|
|
||||||
function index_schema_to_sql($index_data)
|
|
||||||
{
|
|
||||||
if ($index_data['Name'] == 'PRIMARY') {
|
|
||||||
$index = 'PRIMARY KEY (%s)';
|
|
||||||
} elseif ($index_data['Unique']) {
|
|
||||||
$index = "UNIQUE `{$index_data['Name']}` (%s)";
|
|
||||||
} else {
|
|
||||||
$index = "INDEX `{$index_data['Name']}` (%s)";
|
|
||||||
}
|
|
||||||
|
|
||||||
$columns = implode(',', array_map(function ($col) {
|
|
||||||
return "`$col`";
|
|
||||||
}, $index_data['Columns']));
|
|
||||||
|
|
||||||
return sprintf($index, $columns);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an array of the schema files.
|
* Get an array of the schema files.
|
||||||
* schema_version => full_file_name
|
* schema_version => full_file_name
|
||||||
|
|||||||
2156
misc/db_schema.yaml
2156
misc/db_schema.yaml
File diff suppressed because it is too large
Load Diff
@@ -75,7 +75,7 @@ if (!$where) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['d']) || isset($options['v'])) {
|
if (isset($options['d']) || isset($options['v'])) {
|
||||||
$versions = version_info(false);
|
$versions = version_info();
|
||||||
echo <<<EOH
|
echo <<<EOH
|
||||||
===================================
|
===================================
|
||||||
Version info:
|
Version info:
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ if (function_exists('ad_bind')) {
|
|||||||
} else {
|
} else {
|
||||||
if (!ad_bind($ldap_connection)) {
|
if (!ad_bind($ldap_connection)) {
|
||||||
echo ldap_error($ldap_connection) . PHP_EOL;
|
echo ldap_error($ldap_connection) . PHP_EOL;
|
||||||
print_warn("Could not anonymous bind to AD");
|
print_message("Could not anonymous bind to AD");
|
||||||
} else {
|
} else {
|
||||||
print_message('AD bind anonymous successful');
|
print_message('AD bind anonymous successful');
|
||||||
}
|
}
|
||||||
|
|||||||
1
sql-schema/212.sql
Normal file
1
sql-schema/212.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
DELETE FROM `pollers` WHERE `poller_name` LIKE '%\n';
|
||||||
@@ -50,4 +50,21 @@ class FunctionsTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertFalse(isHexString('a5 fj 53'));
|
$this->assertFalse(isHexString('a5 fj 53'));
|
||||||
$this->assertFalse(isHexString('a5fe53'));
|
$this->assertFalse(isHexString('a5fe53'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testLinkify()
|
||||||
|
{
|
||||||
|
$input = 'foo@demo.net bar.ba@test.co.uk
|
||||||
|
www.demo.com http://foo.co.uk/
|
||||||
|
sdfsd
|
||||||
|
http://regexr.com/foo.html?q=bar
|
||||||
|
https://mediatemple.net.';
|
||||||
|
|
||||||
|
$expected = 'foo@demo.net bar.ba@test.co.uk
|
||||||
|
www.demo.com <a href="http://foo.co.uk/">http://foo.co.uk/</a>
|
||||||
|
sdfsd
|
||||||
|
<a href="http://regexr.com/foo.html?q=bar">http://regexr.com/foo.html?q=bar</a>
|
||||||
|
<a href="https://mediatemple.net">https://mediatemple.net</a>.';
|
||||||
|
|
||||||
|
$this->assertSame($expected, linkify($input));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
559
validate.php
559
validate.php
@@ -13,26 +13,40 @@
|
|||||||
* the source code distribution for details.
|
* the source code distribution for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use LibreNMS\Config;
|
||||||
|
use LibreNMS\Validator;
|
||||||
|
|
||||||
chdir(__DIR__); // cwd to the directory containing this script
|
chdir(__DIR__); // cwd to the directory containing this script
|
||||||
|
|
||||||
require_once 'includes/common.php';
|
require_once 'includes/common.php';
|
||||||
require_once 'includes/functions.php';
|
require_once 'includes/functions.php';
|
||||||
require_once 'includes/dbFacile.php';
|
require_once 'includes/dbFacile.php';
|
||||||
|
|
||||||
$options = getopt('m:h::');
|
$options = getopt('g:m:s::h::');
|
||||||
|
|
||||||
if (isset($options['h'])) {
|
if (isset($options['h'])) {
|
||||||
echo
|
echo
|
||||||
"\n Validate setup tool
|
"\n Validate setup tool
|
||||||
|
|
||||||
Usage: ./validate.php [-m <module>] [-h]
|
Usage: ./validate.php [-g <group>] [-s] [-h]
|
||||||
-h This help section.
|
-h This help section.
|
||||||
-m Any sub modules you want to run, comma separated:
|
-s Print the status of each group
|
||||||
- mail: this will test your email settings (uses default_mail option even if default_only is not set).
|
-g Any validation groups you want to run, comma separated:
|
||||||
- dist-poller: this will test for the install running as a distributed poller.
|
Non-default groups:
|
||||||
|
- mail: this will test your email settings (uses default_mail option even if default_only is not set)
|
||||||
|
- distributedpoller: this will test for the install running as a distributed poller
|
||||||
- rrdcheck: this will check to see if your rrd files are corrupt
|
- rrdcheck: this will check to see if your rrd files are corrupt
|
||||||
|
Default groups:
|
||||||
|
- configuration: checks various config settings are correct
|
||||||
|
- database: checks the database for errors
|
||||||
|
- disk: checks for disk space and other disk related issues
|
||||||
|
- php: check that various PHP modules and functions exist
|
||||||
|
- poller: check that the poller and discovery are running properly
|
||||||
|
- programs: check that external programs exist and are executable
|
||||||
|
- updates: checks the status of git and updates
|
||||||
|
- user: check that the LibreNMS user is set properly
|
||||||
|
|
||||||
Example: ./validate.php -m mail.
|
Example: ./validate.php -g mail.
|
||||||
|
|
||||||
"
|
"
|
||||||
;
|
;
|
||||||
@@ -42,29 +56,13 @@ if (isset($options['h'])) {
|
|||||||
|
|
||||||
// Buffer output
|
// Buffer output
|
||||||
ob_start();
|
ob_start();
|
||||||
|
$precheck_complete = false;
|
||||||
register_shutdown_function(function () {
|
register_shutdown_function(function () {
|
||||||
global $versions;
|
global $precheck_complete;
|
||||||
$output = ob_get_clean();
|
|
||||||
if (!isset($versions)) {
|
if (!$precheck_complete) {
|
||||||
$versions = version_info();
|
print_header(version_info());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ob_end_clean();
|
|
||||||
|
|
||||||
echo <<< EOF
|
|
||||||
====================================
|
|
||||||
Component | Version
|
|
||||||
--------- | -------
|
|
||||||
LibreNMS | {$versions['local_ver']}
|
|
||||||
DB Schema | {$versions['db_schema']}
|
|
||||||
PHP | {$versions['php_ver']}
|
|
||||||
MySQL | {$versions['mysql_ver']}
|
|
||||||
RRDTool | {$versions['rrdtool_ver']}
|
|
||||||
SNMP | {$versions['netsnmp_ver']}
|
|
||||||
====================================
|
|
||||||
|
|
||||||
$output
|
|
||||||
EOF;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// critical config.php checks
|
// critical config.php checks
|
||||||
@@ -97,21 +95,6 @@ if (!file_exists('vendor/autoload.php')) {
|
|||||||
$pre_checks_failed = true;
|
$pre_checks_failed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check php modules we use to make sure they are loaded
|
|
||||||
$extensions = array('mysqli','pcre','curl','session','snmp','mcrypt', 'xml');
|
|
||||||
foreach ($extensions as $extension) {
|
|
||||||
if (extension_loaded($extension) == false) {
|
|
||||||
$missing_extensions[] = $extension;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!empty($missing_extensions)) {
|
|
||||||
print_fail("We couldn't find the following php extensions, please ensure they are installed:");
|
|
||||||
foreach ($missing_extensions as $extension) {
|
|
||||||
echo "$extension\n";
|
|
||||||
}
|
|
||||||
$pre_checks_failed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($pre_checks_failed) {
|
if ($pre_checks_failed) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -120,486 +103,74 @@ $init_modules = array('nodb');
|
|||||||
require 'includes/init.php';
|
require 'includes/init.php';
|
||||||
|
|
||||||
// make sure install_dir is set correctly, or the next includes will fail
|
// make sure install_dir is set correctly, or the next includes will fail
|
||||||
if (!file_exists($config['install_dir'].'/config.php')) {
|
if (!file_exists(Config::get('install_dir').'/config.php')) {
|
||||||
print_fail('$config[\'install_dir\'] is not set correctly. It should probably be set to: ' . getcwd());
|
$suggested = realpath(__DIR__ . '/../..');
|
||||||
|
print_fail('$config[\'install_dir\'] is not set correctly.', "It should probably be set to: $suggested");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check we are running this as the root user
|
$validator = new Validator();
|
||||||
if (function_exists('posix_getpwuid')) {
|
|
||||||
$userinfo = posix_getpwuid(posix_geteuid());
|
|
||||||
$username = $userinfo['name'];
|
|
||||||
} else {
|
|
||||||
$username = getenv('USERNAME') ?: getenv('USER'); //http://php.net/manual/en/function.get-current-user.php
|
|
||||||
}
|
|
||||||
if (!($username === 'root' || (isset($config['user']) && $username === $config['user']))) {
|
|
||||||
print_fail('You need to run this script as root' . (isset($config['user']) ? ' or '.$config['user'] : ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's test the user configured if we have it
|
|
||||||
if (isset($config['user'])) {
|
|
||||||
$tmp_user = $config['user'];
|
|
||||||
$tmp_dir = $config['install_dir'];
|
|
||||||
$find_result = rtrim(`find $tmp_dir \! -user $tmp_user`);
|
|
||||||
if (!empty($find_result)) {
|
|
||||||
// This isn't just the log directory, let's print the list to the user
|
|
||||||
$files = array_diff(explode(PHP_EOL, $find_result), array(
|
|
||||||
"$tmp_dir/logs/error_log",
|
|
||||||
"$tmp_dir/logs/access_log",
|
|
||||||
));
|
|
||||||
if (!empty($files)) {
|
|
||||||
print_fail(
|
|
||||||
"We have found some files that are owned by a different user than $tmp_user, " .
|
|
||||||
'this will stop you updating automatically and / or rrd files being updated causing graphs to fail.',
|
|
||||||
"chown -R $tmp_user:$tmp_user {$config['install_dir']}"
|
|
||||||
);
|
|
||||||
print_list($files, "\t %s\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print_warn('You don\'t have $config["user"] set, this most likely needs to be set to librenms');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run test on MySQL
|
// Connect to MySQL
|
||||||
try {
|
try {
|
||||||
dbConnect();
|
dbConnect();
|
||||||
print_ok('Database connection successful');
|
|
||||||
|
// pull in the database config settings
|
||||||
|
mergedb();
|
||||||
|
require 'includes/process_config.inc.php';
|
||||||
|
|
||||||
|
$validator->ok('Database connection successful', null, 'database');
|
||||||
} catch (\LibreNMS\Exceptions\DatabaseConnectException $e) {
|
} catch (\LibreNMS\Exceptions\DatabaseConnectException $e) {
|
||||||
print_fail('Error connecting to your database '.$e->getMessage());
|
$validator->fail('Error connecting to your database. '.$e->getMessage(), null, 'database');
|
||||||
}
|
|
||||||
// pull in the database config settings
|
|
||||||
mergedb();
|
|
||||||
|
|
||||||
// Test for MySQL Strict mode
|
|
||||||
$strict_mode = dbFetchCell("SELECT @@global.sql_mode");
|
|
||||||
if (str_contains($strict_mode, 'STRICT_TRANS_TABLES')) {
|
|
||||||
//FIXME - Come back to this once other MySQL modes are fixed
|
|
||||||
//print_fail('You have MySQL STRICT_TRANS_TABLES enabled, please disable this until full support has been added: https://dev.mysql.com/doc/refman/5.0/en/sql-mode.html');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for lower case table name support
|
$precheck_complete = true; // disable shutdown function
|
||||||
$lc_mode = dbFetchCell("SELECT @@global.lower_case_table_names");
|
print_header($validator->getVersions());
|
||||||
if ($lc_mode != 0) {
|
|
||||||
print_fail('You have lower_case_table_names set to 1 or true in mysql config.', 'Set lower_case_table_names=0 in your mysql config file');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($strict_mode) === false) {
|
if (isset($options['g'])) {
|
||||||
print_fail("You have not set sql_mode='' in your mysql config");
|
$modules = explode(',', $options['g']);
|
||||||
}
|
} elseif (isset($options['m'])) {
|
||||||
|
$modules = explode(',', $options['m']); // backwards compat
|
||||||
// Test for correct character set and collation
|
|
||||||
$collation = dbFetchRows("SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA S WHERE schema_name = '" . $config['db_name'] . "' AND ( DEFAULT_CHARACTER_SET_NAME != 'utf8' OR DEFAULT_COLLATION_NAME != 'utf8_unicode_ci')");
|
|
||||||
if (empty($collation) !== true) {
|
|
||||||
print_fail('MySQL Database collation is wrong: ' . implode(' ', $collation[0]), 'https://t.libren.ms/-zdwk');
|
|
||||||
}
|
|
||||||
$collation_tables = dbFetchRows("SELECT T.TABLE_NAME, C.CHARACTER_SET_NAME, C.COLLATION_NAME FROM information_schema.TABLES AS T, information_schema.COLLATION_CHARACTER_SET_APPLICABILITY AS C WHERE C.collation_name = T.table_collation AND T.table_schema = '" . $config['db_name'] . "' AND ( C.CHARACTER_SET_NAME != 'utf8' OR C.COLLATION_NAME != 'utf8_unicode_ci' );");
|
|
||||||
if (empty($collation_tables) !== true) {
|
|
||||||
print_fail('MySQL tables collation is wrong: ', 'http://bit.ly/2lAG9H8');
|
|
||||||
print_list($collation_tables, "\t %s\n");
|
|
||||||
}
|
|
||||||
$collation_columns = dbFetchRows("SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . $config['db_name'] . "' AND ( CHARACTER_SET_NAME != 'utf8' OR COLLATION_NAME != 'utf8_unicode_ci' );");
|
|
||||||
if (empty($collation_columns) !== true) {
|
|
||||||
print_fail('MySQL column collation is wrong: ', 'https://t.libren.ms/-zdwk');
|
|
||||||
print_list($collation_columns, "\t %s\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_file('misc/db_schema.yaml')) {
|
|
||||||
$master_schema = Symfony\Component\Yaml\Yaml::parse(
|
|
||||||
file_get_contents('misc/db_schema.yaml')
|
|
||||||
);
|
|
||||||
|
|
||||||
$current_schema = dump_db_schema();
|
|
||||||
$schema_update = array();
|
|
||||||
|
|
||||||
foreach ((array)$master_schema as $table => $data) {
|
|
||||||
if (empty($current_schema[$table])) {
|
|
||||||
print_fail("Database: missing table ($table)");
|
|
||||||
|
|
||||||
$columns = array_map('column_schema_to_sql', $data['Columns']);
|
|
||||||
$indexes = array_map('index_schema_to_sql', $data['Indexes']);
|
|
||||||
$def = implode(', ', array_merge(array_values($columns), array_values($indexes)));
|
|
||||||
|
|
||||||
$schema_update[] = "CREATE TABLE `$table` ($def);";
|
|
||||||
} else {
|
|
||||||
$previous_column = '';
|
|
||||||
foreach ($data['Columns'] as $column => $cdata) {
|
|
||||||
$cur = $current_schema[$table]['Columns'][$column];
|
|
||||||
if ($cur['Default'] == 'current_timestamp()') {
|
|
||||||
$cur['Default'] = 'CURRENT_TIMESTAMP';
|
|
||||||
}
|
|
||||||
if ($cur['Extra'] == 'on update current_timestamp()') {
|
|
||||||
$cur['Extra'] = 'on update CURRENT_TIMESTAMP';
|
|
||||||
}
|
|
||||||
if (empty($current_schema[$table]['Columns'][$column])) {
|
|
||||||
print_fail("Database: missing column ($table/$column)");
|
|
||||||
|
|
||||||
$sql = "ALTER TABLE `$table` ADD " . column_schema_to_sql($cdata);
|
|
||||||
if (!empty($previous_column)) {
|
|
||||||
$sql .= " AFTER `$previous_column`";
|
|
||||||
}
|
|
||||||
$schema_update[] = $sql . ';';
|
|
||||||
} elseif ($cdata != $cur) {
|
|
||||||
print_fail("Database: incorrect column ($table/$column)");
|
|
||||||
$schema_update[] = "ALTER TABLE `$table` CHANGE `$column` " . column_schema_to_sql($cdata) . ';';
|
|
||||||
}
|
|
||||||
$previous_column = $column;
|
|
||||||
unset($current_schema[$table]['Columns'][$column]); // remove checked columns
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($current_schema[$table]['Columns'] as $column => $_unused) {
|
|
||||||
print_fail("Database: extra column ($table/$column)");
|
|
||||||
$schema_update[] = "ALTER TABLE `$table` DROP `$column`;";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach ($data['Indexes'] as $name => $index) {
|
|
||||||
if (empty($current_schema[$table]['Indexes'][$name])) {
|
|
||||||
print_fail("Database: missing index ($table/$name)");
|
|
||||||
$schema_update[] = "ALTER TABLE `$table` ADD " . index_schema_to_sql($index) . ';';
|
|
||||||
} elseif ($index != $current_schema[$table]['Indexes'][$name]) {
|
|
||||||
print_fail("Database: incorrect index ($table/$name)");
|
|
||||||
$schema_update[] = "ALTER TABLE `$table` DROP INDEX `$name`, " . index_schema_to_sql($index) . ';';
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($current_schema[$table]['Indexes'][$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($current_schema[$table]['Indexes'] as $name => $_unused) {
|
|
||||||
print_fail("Database: extra index ($table/$name)");
|
|
||||||
$schema_update[] = "ALTER TABLE `$table` DROP INDEX `$name`;";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($current_schema[$table]); // remove checked tables
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($current_schema as $table => $data) {
|
|
||||||
print_fail("Database: extra table ($table)");
|
|
||||||
$schema_update[] = "DROP TABLE `$table`;";
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
print_warn("We haven't detected the db_schema.yaml file");
|
$modules = array(); // all modules
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($schema_update)) {
|
// run checks
|
||||||
print_ok('Database schema correct');
|
$validator->validate($modules, isset($options['s'])||!empty($modules));
|
||||||
} else {
|
|
||||||
print_fail("We have detected that your database schema may be wrong, please report the following to us on IRC or the community site (https://t.libren.ms/5gscd):");
|
|
||||||
print_list($schema_update, "\t %s\n", 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
$versions = version_info();
|
|
||||||
|
|
||||||
// Check that rrdtool config version is what we see
|
|
||||||
if (isset($config['rrdtool_version']) && (version_compare($config['rrdtool_version'], $versions['rrdtool_ver'], '>'))) {
|
|
||||||
print_fail('The rrdtool version you have specified is newer than what is installed.', "Either comment out \$config['rrdtool_version'] = '{$config['rrdtool_version']}'; or set \$config['rrdtool_version'] = '{$versions['rrdtool_ver']}';");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check_git_exists() === true) {
|
|
||||||
if ($config['update_channel'] == 'master') {
|
|
||||||
if ($versions['local_sha'] != $versions['github']['sha']) {
|
|
||||||
$commit_date = new DateTime('@' . $versions['local_date'], new DateTimeZone(date_default_timezone_get()));
|
|
||||||
if ($commit_date->diff(new DateTime())->days > 0) {
|
|
||||||
print_warn("Your install is over 24 hours out of date, last update: " . $commit_date->format('r'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($versions['local_branch'] != 'master') {
|
|
||||||
print_warn("Your local git branch is not master, this will prevent automatic updates.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for modified files
|
|
||||||
$modifiedcmd = 'git diff --name-only --exit-code';
|
|
||||||
if ($username === 'root') {
|
|
||||||
$modifiedcmd = 'su '.$config['user'].' -c "'.$modifiedcmd.'"';
|
|
||||||
}
|
|
||||||
exec($modifiedcmd, $cmdoutput, $code);
|
|
||||||
if ($code !== 0 && !empty($cmdoutput)) {
|
|
||||||
print_warn("Your local git contains modified files, this could prevent automatic updates.\nModified files:");
|
|
||||||
print_list($cmdoutput, "\t %s\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print_warn('Unable to locate git. This should probably be installed.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$ini_tz = ini_get('date.timezone');
|
|
||||||
$sh_tz = rtrim(shell_exec('date +%Z'));
|
|
||||||
$php_tz = date('T');
|
|
||||||
|
|
||||||
if (empty($ini_tz)) {
|
|
||||||
print_fail(
|
|
||||||
'You have no timezone set for php.',
|
|
||||||
'http://php.net/manual/en/datetime.configuration.php#ini.date.timezone'
|
|
||||||
);
|
|
||||||
} elseif ($sh_tz !== $php_tz) {
|
|
||||||
print_fail("You have a different system timezone ($sh_tz) specified to the php configured timezone ($php_tz), please correct this.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test transports
|
|
||||||
if ($config['alerts']['email']['enable'] === true) {
|
|
||||||
print_warn('You have the old alerting system enabled - this is to be deprecated on the 1st of June 2015: https://groups.google.com/forum/#!topic/librenms-project/1llxos4m0p4');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test rrdcached
|
|
||||||
if (!$config['rrdcached']) {
|
|
||||||
$rrd_dir = stat($config['rrd_dir']);
|
|
||||||
if ($rrd_dir[4] == 0 || $rrd_dir[5] == 0) {
|
|
||||||
print_warn('Your RRD directory is owned by root, please consider changing over to user a non-root user');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (substr(sprintf('%o', fileperms($config['rrd_dir'])), -3) != 775) {
|
|
||||||
print_warn('Your RRD directory is not set to 0775', "chmod 775 {$config['rrd_dir']}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($config['rrdcached'])) {
|
|
||||||
check_rrdcached();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disk space and permission checks
|
|
||||||
if (substr(sprintf('%o', fileperms($config['temp_dir'])), -3) != 777) {
|
|
||||||
print_warn('Your tmp directory ('.$config['temp_dir'].") is not set to 777 so graphs most likely won't be generated");
|
|
||||||
}
|
|
||||||
|
|
||||||
$space_check = (disk_free_space($config['install_dir']) / 1024 / 1024);
|
|
||||||
if ($space_check < 512 && $space_check > 1) {
|
|
||||||
print_warn('Disk space where '.$config['install_dir'].' is located is less than 512Mb');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($space_check < 1) {
|
|
||||||
print_fail('Disk space where '.$config['install_dir'].' is located is empty!!!');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check programs
|
|
||||||
$bins = array('fping','fping6','rrdtool','snmpwalk','snmpget','snmpbulkwalk');
|
|
||||||
foreach ($bins as $bin) {
|
|
||||||
$cmd = rtrim(shell_exec("which {$config[$bin]} 2>/dev/null"));
|
|
||||||
if (!$cmd) {
|
|
||||||
print_fail("$bin location is incorrect or bin not installed. \n\tYou can also manually set the path to $bin by placing the following in config.php: \n\t\$config['$bin'] = \"/path/to/$bin\";");
|
|
||||||
} elseif (in_array($bin, array('fping', 'fping6'))) {
|
|
||||||
if (trim(shell_exec("which getcap 2>/dev/null"))) {
|
|
||||||
if (!str_contains(shell_exec("getcap $cmd"), "$cmd = cap_net_raw+ep")) {
|
|
||||||
print_fail("$bin should have CAP_NET_RAW!", "setcap cap_net_raw+ep $cmd");
|
|
||||||
}
|
|
||||||
} elseif (!(fileperms($cmd) & 2048)) {
|
|
||||||
print_fail("$bin should be suid!", "chmod u+s $cmd");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$disabled_functions = explode(',', ini_get('disable_functions'));
|
|
||||||
$required_functions = array('exec','passthru','shell_exec','escapeshellarg','escapeshellcmd','proc_close','proc_open','popen');
|
|
||||||
foreach ($required_functions as $function) {
|
|
||||||
if (in_array($function, $disabled_functions)) {
|
|
||||||
print_fail("$function is disabled in php.ini");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('openssl_random_pseudo_bytes')) {
|
|
||||||
print_warn("openssl_random_pseudo_bytes is not being used for user password hashing. This is a recommended function (https://secure.php.net/openssl_random_pseudo_bytes)");
|
|
||||||
if (!is_readable('/dev/urandom')) {
|
|
||||||
print_warn("It also looks like we can't use /dev/urandom for user password hashing. We will fall back to generating our own hash - be warned");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check poller
|
|
||||||
if (dbFetchCell('SELECT COUNT(*) FROM `pollers`')) {
|
|
||||||
if (dbFetchCell('SELECT COUNT(*) FROM `pollers` WHERE `last_polled` >= DATE_ADD(NOW(), INTERVAL - 5 MINUTE)') == 0) {
|
|
||||||
print_fail("The poller has not run in the last 5 minutes, check the cron job");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print_fail('The poller has never run, check the cron job');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (dbFetchCell('SELECT COUNT(*) FROM `devices`') == 0) {
|
function print_header($versions)
|
||||||
print_warn("You have not added any devices yet.");
|
|
||||||
} else {
|
|
||||||
// check discovery last run
|
|
||||||
if (dbFetchCell('SELECT COUNT(*) FROM `devices` WHERE `last_discovered` IS NOT NULL') == 0) {
|
|
||||||
print_fail('Discovery has never run, check the cron job');
|
|
||||||
} elseif (dbFetchCell("SELECT COUNT(*) FROM `devices` WHERE `last_discovered` <= DATE_ADD(NOW(), INTERVAL - 24 HOUR) AND `ignore` = 0 AND `disabled` = 0 AND `status` = 1") > 0) {
|
|
||||||
print_fail("Discovery has not completed in the last 24 hours, check the cron job");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check devices polling
|
|
||||||
if (count($devices = dbFetchColumn("SELECT `hostname` FROM `devices` WHERE (`last_polled` < DATE_ADD(NOW(), INTERVAL - 5 MINUTE) OR `last_polled` IS NULL) AND `ignore` = 0 AND `disabled` = 0 AND `status` = 1")) > 0) {
|
|
||||||
print_warn("Some devices have not been polled in the last 5 minutes.
|
|
||||||
You may have performance issues. Check your poll log and see: http://docs.librenms.org/Support/Performance/");
|
|
||||||
print_list($devices, "\t %s\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($devices = dbFetchColumn('SELECT `hostname` FROM `devices` WHERE last_polled_timetaken > 300 AND `ignore` = 0 AND `disabled` = 0 AND `status` = 1')) > 0) {
|
|
||||||
print_fail("Some devices have not completed their polling run in 5 minutes, this will create gaps in data.
|
|
||||||
Check your poll log and refer to http://docs.librenms.org/Support/Performance/");
|
|
||||||
print_list($devices, "\t %s\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Modules test
|
|
||||||
$modules = explode(',', $options['m']);
|
|
||||||
foreach ($modules as $module) {
|
|
||||||
switch ($module) {
|
|
||||||
case 'mail':
|
|
||||||
if ($config['alert']['transports']['mail'] === true) {
|
|
||||||
$run_test = 1;
|
|
||||||
if (empty($config['alert']['default_mail'])) {
|
|
||||||
print_fail('default_mail config option needs to be specified to test email');
|
|
||||||
$run_test = 0;
|
|
||||||
} elseif ($config['email_backend'] == 'sendmail') {
|
|
||||||
if (empty($config['email_sendmail_path'])) {
|
|
||||||
print_fail("You have selected sendmail but not configured email_sendmail_path");
|
|
||||||
$run_test = 0;
|
|
||||||
} elseif (!file_exists($config['email_sendmail_path'])) {
|
|
||||||
print_fail("The configured email_sendmail_path is not valid");
|
|
||||||
$run_test = 0;
|
|
||||||
}
|
|
||||||
} elseif ($config['email_backend'] == 'smtp') {
|
|
||||||
if (empty($config['email_smtp_host'])) {
|
|
||||||
print_fail('You have selected SMTP but not configured an SMTP host');
|
|
||||||
$run_test = 0;
|
|
||||||
}
|
|
||||||
if (empty($config['email_smtp_port'])) {
|
|
||||||
print_fail('You have selected SMTP but not configured an SMTP port');
|
|
||||||
$run_test = 0;
|
|
||||||
}
|
|
||||||
if (($config['email_smtp_auth'] === true) && (empty($config['email_smtp_username']) || empty($config['email_smtp_password']))) {
|
|
||||||
print_fail('You have selected SMTP auth but have not configured both username and password');
|
|
||||||
$run_test = 0;
|
|
||||||
}
|
|
||||||
}//end if
|
|
||||||
if ($run_test == 1) {
|
|
||||||
if ($err = send_mail($config['alert']['default_mail'], 'Test email', 'Testing email from NMS')) {
|
|
||||||
print_ok('Email has been sent');
|
|
||||||
} else {
|
|
||||||
print_fail('Issue sending email to '.$config['alert']['default_mail'].' with error '.$err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//end if
|
|
||||||
break;
|
|
||||||
case 'dist-poller':
|
|
||||||
if ($config['distributed_poller'] !== true) {
|
|
||||||
print_fail('You have not enabled distributed_poller');
|
|
||||||
} else {
|
|
||||||
if (empty($config['distributed_poller_memcached_host'])) {
|
|
||||||
print_fail('You have not configured $config[\'distributed_poller_memcached_host\']');
|
|
||||||
} elseif (empty($config['distributed_poller_memcached_port'])) {
|
|
||||||
print_fail('You have not configured $config[\'distributed_poller_memcached_port\']');
|
|
||||||
} else {
|
|
||||||
$connection = @fsockopen($config['distributed_poller_memcached_host'], $config['distributed_poller_memcached_port']);
|
|
||||||
if (!is_resource($connection)) {
|
|
||||||
print_fail('We could not get memcached stats, it is possible that we cannot connect to your memcached server, please check');
|
|
||||||
} else {
|
|
||||||
fclose($connection);
|
|
||||||
print_ok('Connection to memcached is ok');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (empty($config['rrdcached'])) {
|
|
||||||
print_fail('You have not configured $config[\'rrdcached\']');
|
|
||||||
} elseif (empty($config['rrd_dir'])) {
|
|
||||||
print_fail('You have not configured $config[\'rrd_dir\']');
|
|
||||||
} else {
|
|
||||||
check_rrdcached();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'rrdcheck':
|
|
||||||
// Loop through the rrd_dir
|
|
||||||
$rrd_directory = new RecursiveDirectoryIterator($config['rrd_dir']);
|
|
||||||
// Filter out any non rrd files
|
|
||||||
$rrd_directory_filter = new LibreNMS\RRDRecursiveFilterIterator($rrd_directory);
|
|
||||||
$rrd_iterator = new RecursiveIteratorIterator($rrd_directory_filter);
|
|
||||||
$rrd_total = iterator_count($rrd_iterator);
|
|
||||||
$rrd_iterator->rewind(); // Rewind iterator in case iterator_count left iterator in unknown state
|
|
||||||
|
|
||||||
echo "\nScanning ".$rrd_total." rrd files in ".$config['rrd_dir']."...\n";
|
|
||||||
|
|
||||||
// Count loops so we can push status to the user
|
|
||||||
$loopcount = 0;
|
|
||||||
$screenpad = 0;
|
|
||||||
|
|
||||||
foreach ($rrd_iterator as $filename => $file) {
|
|
||||||
$rrd_test_result = rrdtest($filename, $output, $error);
|
|
||||||
|
|
||||||
$loopcount++;
|
|
||||||
if (($loopcount % 50) == 0) {
|
|
||||||
//This lets us update the previous status update without spamming in most consoles
|
|
||||||
echo "\033[".$screenpad."D";
|
|
||||||
$test_status = 'Status: '.$loopcount.'/'.$rrd_total;
|
|
||||||
echo $test_status;
|
|
||||||
$screenpad = strlen($test_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A non zero result means there was some kind of error
|
|
||||||
if ($rrd_test_result > 0) {
|
|
||||||
echo "\033[".$screenpad."D";
|
|
||||||
print_fail('Error parsing "'.$filename.'" RRD '.trim($error));
|
|
||||||
$screenpad = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo "\033[".$screenpad."D";
|
|
||||||
echo "Status: ".$loopcount."/".$rrd_total." - Complete\n";
|
|
||||||
|
|
||||||
break;
|
|
||||||
}//end switch
|
|
||||||
}//end foreach
|
|
||||||
|
|
||||||
// End
|
|
||||||
|
|
||||||
|
|
||||||
function print_ok($msg)
|
|
||||||
{
|
{
|
||||||
c_echo("[%gOK%n] $msg\n");
|
$output = ob_get_clean();
|
||||||
}//end print_ok()
|
ob_end_clean();
|
||||||
|
|
||||||
|
echo <<< EOF
|
||||||
|
====================================
|
||||||
|
Component | Version
|
||||||
|
--------- | -------
|
||||||
|
LibreNMS | ${versions['local_ver']}
|
||||||
|
DB Schema | ${versions['db_schema']}
|
||||||
|
PHP | ${versions['php_ver']}
|
||||||
|
MySQL | ${versions['mysql_ver']}
|
||||||
|
RRDTool | ${versions['rrdtool_ver']}
|
||||||
|
SNMP | ${versions['netsnmp_ver']}
|
||||||
|
====================================
|
||||||
|
|
||||||
|
$output
|
||||||
|
EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// output matches that of ValidationResult
|
||||||
function print_fail($msg, $fix = null)
|
function print_fail($msg, $fix = null)
|
||||||
{
|
{
|
||||||
c_echo("[%RFAIL%n] $msg");
|
c_echo("[%RFAIL%n] $msg");
|
||||||
if ($fix && strlen($msg) > 72) {
|
if ($fix && strlen($msg) > 72) {
|
||||||
echo PHP_EOL . " ";
|
echo PHP_EOL . " ";
|
||||||
}
|
}
|
||||||
print_fix($fix);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function print_warn($msg, $fix = null)
|
|
||||||
{
|
|
||||||
c_echo("[%YWARN%n] $msg");
|
|
||||||
if ($fix && strlen($msg) > 72) {
|
|
||||||
echo PHP_EOL . " ";
|
|
||||||
}
|
|
||||||
print_fix($fix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $fix
|
|
||||||
*/
|
|
||||||
function print_fix($fix)
|
|
||||||
{
|
|
||||||
if (!empty($fix)) {
|
if (!empty($fix)) {
|
||||||
c_echo(" [%BFIX%n] %B$fix%n");
|
c_echo(" [%BFIX%n] %B$fix%n");
|
||||||
}
|
}
|
||||||
echo PHP_EOL;
|
echo PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_rrdcached()
|
|
||||||
{
|
|
||||||
global $config;
|
|
||||||
list($host,$port) = explode(':', $config['rrdcached']);
|
|
||||||
if ($host == 'unix') {
|
|
||||||
// Using socket, check that file exists
|
|
||||||
if (!file_exists($port)) {
|
|
||||||
print_fail("$port doesn't appear to exist, rrdcached test failed");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$connection = @fsockopen($host, $port);
|
|
||||||
if (is_resource($connection)) {
|
|
||||||
fclose($connection);
|
|
||||||
} else {
|
|
||||||
print_fail('Cannot connect to rrdcached instance');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//end check_rrdcached
|
|
||||||
|
|||||||
Reference in New Issue
Block a user