feature: Show composer status in web validate. (#8181)

* Show composer status in web validate.
Don't duplicate in validate.php

* Create variable to check if a group has been completed.
No longer skips database checks.
Extract a base class.
Fix locate_binary and find_executable issues (mostly exposed by lack of db)

* Update Validator.php
This commit is contained in:
Tony Murray
2018-02-27 09:57:20 -06:00
committed by Neil Lathwood
parent f57e92102a
commit 3c3fbd3731
20 changed files with 218 additions and 165 deletions

View File

@@ -43,4 +43,18 @@ interface ValidationGroup
* @return bool * @return bool
*/ */
public function isDefault(); public function isDefault();
/**
* Returns true if this group has been run
*
* @return bool
*/
public function isCompleted();
/**
* Mark this group as completed
*
* @return void
*/
public function markCompleted();
} }

View File

@@ -0,0 +1,64 @@
<?php
/**
* BaseValidation.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 2018 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Validations;
use LibreNMS\Interfaces\ValidationGroup;
abstract class BaseValidation implements ValidationGroup
{
protected $completed = false;
protected static $RUN_BY_DEFAULT = true;
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return static::$RUN_BY_DEFAULT;
}
/**
* Returns true if this group has been run
*
* @return bool
*/
public function isCompleted()
{
return $this->completed ;
}
/**
* Mark this group as completed
*
* @return void
*/
public function markCompleted()
{
$this->completed = true;
}
}

View File

@@ -26,10 +26,9 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\Validator; use LibreNMS\Validator;
class Configuration implements ValidationGroup class Configuration extends BaseValidation
{ {
/** /**
* Validate this module. * Validate this module.
@@ -44,14 +43,4 @@ class Configuration implements ValidationGroup
$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'); $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;
}
} }

View File

@@ -26,12 +26,11 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\ValidationResult; use LibreNMS\ValidationResult;
use LibreNMS\Validator; use LibreNMS\Validator;
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
class Database implements ValidationGroup class Database extends BaseValidation
{ {
public function validate(Validator $validator) public function validate(Validator $validator)
{ {
@@ -308,14 +307,4 @@ FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '" . Config::get('db_name'
return sprintf($index, $columns); return sprintf($index, $columns);
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return true;
}
} }

View File

@@ -0,0 +1,68 @@
<?php
/**
* Dependencies.php
*
* Checks libraries
*
* 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 2018 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Validations;
use LibreNMS\ValidationResult;
use LibreNMS\Validator;
class Dependencies extends BaseValidation
{
/**
* Validate this module.
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator
*
* @param Validator $validator
*/
public function validate(Validator $validator)
{
$composer_output = trim(shell_exec($validator->getBaseDir() . '/scripts/composer_wrapper.php --version'));
$found = preg_match('/Composer version ([.0-9]+)/', $composer_output, $matches);
if (!$found) {
$validator->fail("No composer available, please install composer", "https://getcomposer.org/");
return;
} else {
$validator->ok("Composer Version: " . $matches[1]);
}
$dep_check = shell_exec($validator->getBaseDir() . '/scripts/composer_wrapper.php install --no-dev --dry-run');
preg_match_all('/Installing ([^ ]+\/[^ ]+) \(/', $dep_check, $dep_missing);
if (!empty($dep_missing[0])) {
$result = ValidationResult::fail("Missing dependencies!", "composer install --no-dev");
$result->setList("Dependencies", $dep_missing[1]);
$validator->result($result);
}
preg_match_all('/Updating ([^ ]+\/[^ ]+) \(/', $dep_check, $dep_outdated);
if (!empty($dep_outdated[0])) {
$result = ValidationResult::fail("Outdated dependencies", "composer install --no-dev");
$result->setList("Dependencies", $dep_outdated[1]);
}
if (empty($dep_missing[0]) && empty($dep_outdated[0])) {
$validator->ok("Dependencies up-to-date.");
}
}
}

View File

@@ -26,10 +26,9 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\Validator; use LibreNMS\Validator;
class Disk implements ValidationGroup class Disk extends BaseValidation
{ {
/** /**
* Validate this module. * Validate this module.
@@ -56,14 +55,4 @@ class Disk implements ValidationGroup
$validator->fail("Disk space where $rrd_dir is located is empty!!!"); $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;
}
} }

View File

@@ -33,11 +33,12 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\Validator; use LibreNMS\Validator;
class DistributedPoller implements ValidationGroup class DistributedPoller extends BaseValidation
{ {
protected static $RUN_BY_DEFAULT = false;
/** /**
* Validate this module. * Validate this module.
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator * To return ValidationResults, call ok, warn, fail, or result methods on the $validator
@@ -74,14 +75,4 @@ class DistributedPoller implements ValidationGroup
Rrd::checkRrdcached($validator); Rrd::checkRrdcached($validator);
} }
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return false;
}
} }

View File

@@ -26,11 +26,11 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\Validator; use LibreNMS\Validator;
class Mail implements ValidationGroup class Mail extends BaseValidation
{ {
protected static $RUN_BY_DEFAULT = false;
/** /**
* Validate this module. * Validate this module.
@@ -79,14 +79,4 @@ class Mail implements ValidationGroup
} }
}//end if }//end if
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return false;
}
} }

View File

@@ -26,11 +26,10 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\ValidationResult; use LibreNMS\ValidationResult;
use LibreNMS\Validator; use LibreNMS\Validator;
class Php implements ValidationGroup class Php extends BaseValidation
{ {
/** /**
* Validate this module. * Validate this module.
@@ -161,14 +160,4 @@ class Php implements ValidationGroup
} }
} }
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return true;
}
} }

View File

@@ -25,11 +25,10 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\ValidationResult; use LibreNMS\ValidationResult;
use LibreNMS\Validator; use LibreNMS\Validator;
class Poller implements ValidationGroup class Poller extends BaseValidation
{ {
/** /**
* Validate this module. * Validate this module.
@@ -145,14 +144,4 @@ class Poller implements ValidationGroup
); );
} }
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return true;
}
} }

View File

@@ -26,10 +26,9 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\Validator; use LibreNMS\Validator;
class Programs implements ValidationGroup class Programs extends BaseValidation
{ {
/** /**
* Validate this module. * Validate this module.
@@ -99,16 +98,11 @@ class Programs implements ValidationGroup
return Config::get($bin); return Config::get($bin);
} }
return is_executable(locate_binary($bin)); $located = locate_binary($bin);
if (is_executable($located)) {
return $located;
} }
/** return false;
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return true;
} }
} }

View File

@@ -26,10 +26,9 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\Validator; use LibreNMS\Validator;
class Rrd implements ValidationGroup class Rrd extends BaseValidation
{ {
/** /**
* Validate this module. * Validate this module.
@@ -86,14 +85,4 @@ class Rrd implements ValidationGroup
} }
} }
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return true;
}
} }

View File

@@ -26,14 +26,15 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\RRDRecursiveFilterIterator; use LibreNMS\RRDRecursiveFilterIterator;
use LibreNMS\Validator; use LibreNMS\Validator;
use RecursiveDirectoryIterator; use RecursiveDirectoryIterator;
use RecursiveIteratorIterator; use RecursiveIteratorIterator;
class RrdCheck implements ValidationGroup class RrdCheck extends BaseValidation
{ {
protected static $RUN_BY_DEFAULT = false;
/** /**
* Validate this module. * Validate this module.
* To return ValidationResults, call ok, warn, fail, or result methods on the $validator * To return ValidationResults, call ok, warn, fail, or result methods on the $validator
@@ -79,14 +80,4 @@ class RrdCheck implements ValidationGroup
echo "\033[" . $screenpad . "D"; echo "\033[" . $screenpad . "D";
echo "Status: " . $loopcount . "/" . $rrd_total . " - Complete\n"; 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;
}
} }

View File

@@ -29,11 +29,10 @@ use DateTime;
use DateTimeZone; use DateTimeZone;
use Exception; use Exception;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\ValidationResult; use LibreNMS\ValidationResult;
use LibreNMS\Validator; use LibreNMS\Validator;
class Updates implements ValidationGroup class Updates extends BaseValidation
{ {
public function validate(Validator $validator) public function validate(Validator $validator)
{ {
@@ -90,14 +89,4 @@ class Updates implements ValidationGroup
$validator->result($result); $validator->result($result);
} }
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return true;
}
} }

View File

@@ -26,11 +26,10 @@
namespace LibreNMS\Validations; namespace LibreNMS\Validations;
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\ValidationResult; use LibreNMS\ValidationResult;
use LibreNMS\Validator; use LibreNMS\Validator;
class User implements ValidationGroup class User extends BaseValidation
{ {
/** /**
* Validate this module. * Validate this module.
@@ -99,16 +98,4 @@ class User implements ValidationGroup
$validator->fail("The log folder has improper permissions.", "chmod ug+rw $log_dir"); $validator->fail("The log folder has improper permissions.", "chmod ug+rw $log_dir");
} }
} }
/**
* Returns if this test should be run by default or not.
*
* @return bool
*/
public function isDefault()
{
return true;
}
} }

View File

@@ -25,6 +25,9 @@
namespace LibreNMS; namespace LibreNMS;
use LibreNMS\Interfaces\ValidationGroup;
use ReflectionClass;
class Validator class Validator
{ {
private $validation_groups = array(); private $validation_groups = array();
@@ -40,16 +43,20 @@ class Validator
public function __construct() public function __construct()
{ {
// load all validations // load all validations
$pattern = Config::get('install_dir') . '/LibreNMS/Validations/*.php'; $pattern = $this->getBaseDir() . '/LibreNMS/Validations/*.php';
foreach (glob($pattern) as $file) { foreach (glob($pattern) as $file) {
$class_name = basename($file, '.php'); $class_name = basename($file, '.php');
$class = '\LibreNMS\Validations\\' . $class_name; $class = '\LibreNMS\Validations\\' . $class_name;
$rc = new ReflectionClass($class);
if (!$rc->isAbstract()) {
$validation_name = strtolower($class_name); $validation_name = strtolower($class_name);
$this->validation_groups[$validation_name] = new $class(); $this->validation_groups[$validation_name] = new $class();
$this->results[$validation_name] = array(); $this->results[$validation_name] = array();
} }
} }
}
/** /**
@@ -61,11 +68,17 @@ class Validator
public function validate($validation_groups = array(), $print_group_status = false) public function validate($validation_groups = array(), $print_group_status = false)
{ {
foreach ($this->validation_groups as $group_name => $group) { foreach ($this->validation_groups as $group_name => $group) {
// only run each group once
if ($group->isCompleted()) {
continue;
}
if ((empty($validation_groups) && $group->isDefault()) || in_array($group_name, $validation_groups)) { if ((empty($validation_groups) && $group->isDefault()) || in_array($group_name, $validation_groups)) {
if ($print_group_status && isCli()) { if ($print_group_status && isCli()) {
echo "Checking $group_name:"; echo "Checking $group_name:";
} }
/** @var ValidationGroup $group */
$group->validate($this); $group->validate($this);
if (isCli()) { if (isCli()) {
@@ -76,6 +89,9 @@ class Validator
$this->printResults($group_name); $this->printResults($group_name);
} }
// validation is complete for this group
$group->markCompleted();
} }
} }
} }
@@ -270,4 +286,9 @@ class Validator
$url = function_exists('get_url') ? get_url() : Config::get('base_url'); $url = function_exists('get_url') ? get_url() : Config::get('base_url');
return rtrim(str_replace('validate', '', $url), '/'); // get base_url from current url return rtrim(str_replace('validate', '', $url), '/'); // get base_url from current url
} }
public function getBaseDir()
{
return realpath(__DIR__ . '/..');
}
} }

View File

@@ -88,9 +88,9 @@ foreach ($validator->getAllResults() as $group => $results) {
if ($result->hasFix() || $result->hasList()) { if ($result->hasFix() || $result->hasList()) {
echo '<div class="panel-body">'; echo '<div class="panel-body">';
if ($result->hasFix()) { if ($result->hasFix()) {
echo '<code>' . linkify($result->getFix()) . '</code>'; echo 'Fix: <code>' . linkify($result->getFix()) . '</code>';
if ($result->hasList()) { if ($result->hasList()) {
echo '<br />'; echo '<br /><br />';
} }
} }

View File

@@ -2420,12 +2420,15 @@ function locate_binary($binary)
{ {
if (!str_contains($binary, '/')) { if (!str_contains($binary, '/')) {
$output = `whereis -b $binary`; $output = `whereis -b $binary`;
$target = trim(substr($output, strpos($output, ':') + 1)); $list = trim(substr($output, strpos($output, ':') + 1));
$targets = explode(' ', $list);
if (file_exists($target)) { foreach ($targets as $target) {
if (is_executable($target)) {
return $target; return $target;
} }
} }
}
return $binary; return $binary;
} }

View File

@@ -44,7 +44,7 @@ require_once $install_dir . '/includes/common.php';
if (!is_file($install_dir . '/vendor/autoload.php')) { if (!is_file($install_dir . '/vendor/autoload.php')) {
c_echo("%RError: Missing dependencies%n, run: %B./scripts/composer_wrapper.php install --no-dev%n\n\n"); c_echo("%RError: Missing dependencies%n, run: %B./scripts/composer_wrapper.php install --no-dev%n\n\n");
} }
require $install_dir . '/vendor/autoload.php'; require_once $install_dir . '/vendor/autoload.php';
if (!function_exists('module_selected')) { if (!function_exists('module_selected')) {
function module_selected($module, $modules) function module_selected($module, $modules)

View File

@@ -14,10 +14,13 @@
*/ */
use LibreNMS\Config; use LibreNMS\Config;
use LibreNMS\ValidationResult;
use LibreNMS\Validator; use LibreNMS\Validator;
chdir(__DIR__); // cwd to the directory containing this script chdir(__DIR__); // cwd to the directory containing this script
ini_set('display_errors', 1);
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';
@@ -39,6 +42,7 @@ if (isset($options['h'])) {
Default groups: Default groups:
- configuration: checks various config settings are correct - configuration: checks various config settings are correct
- database: checks the database for errors - database: checks the database for errors
- dependencies: checks that all required libraries are installed and up-to-date
- disk: checks for disk space and other disk related issues - disk: checks for disk space and other disk related issues
- php: check that various PHP modules and functions exist - php: check that various PHP modules and functions exist
- poller: check that the poller and discovery are running properly - poller: check that the poller and discovery are running properly
@@ -92,13 +96,12 @@ if (str_contains(`tail config.php`, '?>')) {
// Composer checks // Composer checks
if (!file_exists('vendor/autoload.php')) { if (!file_exists('vendor/autoload.php')) {
print_fail('Composer has not been run, dependencies are missing', 'composer install --no-dev'); print_fail('Composer has not been run, dependencies are missing', 'composer install --no-dev');
$pre_checks_failed = true; exit;
} }
if (!str_contains(shell_exec('php scripts/composer_wrapper.php --version'), 'Composer version')) { // init autoloading
print_fail("No composer available, please install composer", "https://getcomposer.org/"); require_once 'vendor/autoload.php';
$pre_checks_failed = true;
}
$dep_check = shell_exec('php scripts/composer_wrapper.php install --no-dev --dry-run'); $dep_check = shell_exec('php scripts/composer_wrapper.php install --no-dev --dry-run');
preg_match_all('/Installing ([^ ]+\/[^ ]+) \(/', $dep_check, $dep_missing); preg_match_all('/Installing ([^ ]+\/[^ ]+) \(/', $dep_check, $dep_missing);
@@ -113,6 +116,12 @@ if (!empty($dep_outdated[0])) {
print_list($dep_outdated[1], "\t %s\n"); print_list($dep_outdated[1], "\t %s\n");
} }
$validator = new Validator();
$validator->validate(array('dependencies'));
if ($validator->getGroupStatus('dependencies') == ValidationResult::FAILURE) {
$pre_checks_failed = true;
}
if ($pre_checks_failed) { if ($pre_checks_failed) {
exit; exit;
} }
@@ -122,13 +131,11 @@ 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::get('install_dir').'/config.php')) { if (!file_exists(Config::get('install_dir').'/config.php')) {
$suggested = realpath(__DIR__ . '/../..'); $suggested = realpath(__DIR__);
print_fail('$config[\'install_dir\'] is not set correctly.', "It should probably be set to: $suggested"); print_fail('$config[\'install_dir\'] is not set correctly.', "It should probably be set to: $suggested");
exit; exit;
} }
$validator = new Validator();
// Connect to MySQL // Connect to MySQL
try { try {
@@ -160,7 +167,7 @@ $validator->validate($modules, isset($options['s'])||!empty($modules));
function print_header($versions) function print_header($versions)
{ {
$output = ob_get_clean(); $output = ob_get_clean();
ob_end_clean(); @ob_end_clean();
echo <<< EOF echo <<< EOF
==================================== ====================================