Port Validation Page to Laravel (#13921)

* Revamp validate web page
 to load page then validate, instead of validate then load page

* style fixes

* lint cleanups

* fixes

* translations and a couple fixes

* style fixes

* move result serialization into the class.
This commit is contained in:
Tony Murray 2022-04-14 11:22:40 -05:00 committed by GitHub
parent e495769f17
commit 0a84098211
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 344 additions and 445 deletions

View File

@ -136,6 +136,19 @@ class Html
return $graph_data;
}
/**
* Find all links in some text and turn them into html links.
*
* @param string|null $text
* @return string
*/
public static function linkify(?string $text): string
{
$regex = "#(http|https|ftp|ftps)://[a-z0-9\-.]*[a-z0-9\-]+(/\S*)?#i";
return preg_replace($regex, '<a href="$0">$0</a>', $text);
}
public static function percentageBar($width, $height, $percent, $left_text = '', $right_text = '', $warn = null, $shadow = null, $colors = null)
{
$percent = min($percent, 100);

View File

@ -25,6 +25,7 @@
namespace LibreNMS\Util;
use Illuminate\Http\Client\ConnectionException;
use LibreNMS\Config;
use LibreNMS\DB\Eloquent;
use Symfony\Component\Process\Process;
@ -32,7 +33,7 @@ use Symfony\Component\Process\Process;
class Version
{
// Update this on release
const VERSION = '22.3.0';
public const VERSION = '22.3.0';
/**
* @var bool
@ -58,6 +59,50 @@ class Version
return self::VERSION;
}
/**
* Compiles local commit data
*
* @return array with keys sha, date, and branch
*/
public function localCommit(): array
{
if ($this->is_git_install) {
[$local_sha, $local_date] = explode('|', rtrim(`git show --pretty='%H|%ct' -s HEAD`));
return [
'sha' => $local_sha,
'date' => $local_date,
'branch' => rtrim(`git rev-parse --abbrev-ref HEAD`),
];
}
return ['sha' => null, 'date' => null, 'branch' => null];
}
/**
* Fetches the remote commit from the github api if on the daily release channel
*
* @return array
*/
public function remoteCommit(): array
{
if ($this->is_git_install && Config::get('update_channel') == 'master') {
try {
$github = \Http::withOptions(['proxy' => Proxy::forGuzzle()])->get(Config::get('github_api') . 'commits/master');
return $github->json();
} catch (ConnectionException $e) {
}
}
return [];
}
public function databaseServer(): string
{
return \LibreNMS\DB\Eloquent::isConnected() ? \LibreNMS\DB\Eloquent::version() : 'Not Connected';
}
public function database(): array
{
if (Eloquent::isConnected()) {

View File

@ -25,17 +25,24 @@
namespace LibreNMS;
use LibreNMS\Util\Html;
class ValidationResult
{
const FAILURE = 0;
const WARNING = 1;
const SUCCESS = 2;
const INFO = 3;
public const FAILURE = 0;
public const WARNING = 1;
public const SUCCESS = 2;
public const INFO = 3;
/** @var string */
private $message;
/** @var int */
private $status;
/** @var string */
private $list_description = '';
/** @var array */
private $list;
/** @var string|null */
private $fix;
/**
@ -43,9 +50,9 @@ class ValidationResult
*
* @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
* @param string|null $fix a suggested fix to highlight for the user
*/
public function __construct($message, $status, $fix = null)
public function __construct(string $message, int $status, string $fix = null)
{
$this->message = $message;
$this->status = $status;
@ -56,10 +63,10 @@ class ValidationResult
* 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
* @param string|null $fix a suggested fix to highlight for the user
* @return ValidationResult
*/
public static function ok($message, $fix = null)
public static function ok(string $message, string $fix = null): ValidationResult
{
return new self($message, self::SUCCESS, $fix);
}
@ -68,10 +75,10 @@ class ValidationResult
* 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
* @param string|null $fix a suggested fix to highlight for the user
* @return ValidationResult
*/
public static function warn($message, $fix = null)
public static function warn(string $message, string $fix = null): ValidationResult
{
return new self($message, self::WARNING, $fix);
}
@ -82,7 +89,7 @@ class ValidationResult
* @param string $message The message to describe this result
* @return ValidationResult
*/
public static function info($message)
public static function info(string $message): ValidationResult
{
return new self($message, self::INFO);
}
@ -91,10 +98,10 @@ class ValidationResult
* 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
* @param string|null $fix a suggested fix to highlight for the user
* @return ValidationResult
*/
public static function fail($message, $fix = null)
public static function fail(string $message, string $fix = null): ValidationResult
{
return new self($message, self::FAILURE, $fix);
}
@ -105,27 +112,27 @@ class ValidationResult
*
* @return int
*/
public function getStatus()
public function getStatus(): int
{
return $this->status;
}
public function getMessage()
public function getMessage(): string
{
return $this->message;
}
public function hasList()
public function hasList(): bool
{
return ! empty($this->list);
}
public function getList()
public function getList(): ?array
{
return $this->list;
}
public function setList($description, array $list)
public function setList(string $description, array $list): ValidationResult
{
if (is_array(current($list))) {
$list = array_map(function ($item) {
@ -139,11 +146,14 @@ class ValidationResult
return $this;
}
public function hasFix()
public function hasFix(): bool
{
return ! empty($this->fix);
}
/**
* @return string|array|null
*/
public function getFix()
{
return $this->fix;
@ -156,7 +166,7 @@ class ValidationResult
* @param string|array $fix
* @return ValidationResult $this
*/
public function setFix($fix)
public function setFix($fix): ValidationResult
{
$this->fix = $fix;
@ -166,7 +176,7 @@ class ValidationResult
/**
* Print out this result to the console. Formatted nicely and with color.
*/
public function consolePrint()
public function consolePrint(): void
{
c_echo(str_pad('[' . $this->getStatusText($this->status) . ']', 12) . $this->message . PHP_EOL);
@ -188,7 +198,7 @@ class ValidationResult
*
* @return string
*/
public static function getStatusText($status)
public static function getStatusText(int $status): string
{
$table = [
self::SUCCESS => '%gOK%n',
@ -200,11 +210,27 @@ class ValidationResult
return $table[$status] ?? 'Unknown';
}
public function getListDescription()
public function getListDescription(): string
{
return $this->list_description;
}
public function toArray(): array
{
$resultStatus = $this->getStatus();
$resultFix = $this->getFix();
$resultList = $this->getList();
return [
'status' => $resultStatus,
'statusText' => $this->getStatusText($resultStatus),
'message' => $this->getMessage(),
'fix' => is_array($resultFix) ? $resultFix : ($resultList ? [Html::linkify($resultFix)] : []),
'listDescription' => $this->getListDescription(),
'list' => is_array($resultList) ? array_values($resultList) : [],
];
}
/**
* Print a list of items up to a max amount
* If over that number, a line will print the total items
@ -212,7 +238,7 @@ class ValidationResult
* @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)
private function printList(string $format = "\t %s\n", int $max = 15): void
{
foreach (array_slice($this->list, 0, $max) as $item) {
printf($format, $item);

View File

@ -26,6 +26,7 @@
namespace LibreNMS\Validations;
use LibreNMS\Config;
use LibreNMS\Util\Version;
use LibreNMS\Validator;
class Rrd extends BaseValidation
@ -38,18 +39,18 @@ class Rrd extends BaseValidation
*/
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'), '1.5.5', '<')
&& 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::has('rrdtool_version')) {
$rrd_version = Version::get()->rrdtool();
if (version_compare(Config::get('rrdtool_version'), '1.5.5', '<')
&& version_compare(Config::get('rrdtool_version'), $rrd_version, '>')
) {
$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'] = '{$rrd_version}';"
);
}
}
if (Config::get('rrdcached')) {

View File

@ -32,6 +32,7 @@ use LibreNMS\ComposerHelper;
use LibreNMS\Config;
use LibreNMS\Util\EnvHelper;
use LibreNMS\Util\Git;
use LibreNMS\Util\Version;
use LibreNMS\ValidationResult;
use LibreNMS\Validator;
@ -58,13 +59,13 @@ class Updates extends BaseValidation
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']) {
$local_ver = Version::get()->localCommit();
$remote_ver = Version::get()->remoteCommit();
if ($local_ver['sha'] != ($remote_ver['sha'] ?? null)) {
try {
$commit_date = new DateTime('@' . $versions['local_date'], new DateTimeZone(date_default_timezone_get()));
$commit_date = new DateTime('@' . $local_ver['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'),
@ -76,13 +77,13 @@ class Updates extends BaseValidation
}
}
if ($versions['local_branch'] != 'master') {
if ($versions['local_branch'] == 'php53') {
if ($local_ver['branch'] != 'master') {
if ($local_ver['branch'] == 'php53') {
$validator->warn(
'You are on the PHP 5.3 support branch, this will prevent automatic updates.',
'Update to PHP 5.6.4 or newer (PHP ' . Php::PHP_RECOMMENDED_VERSION . ' recommended) to continue to receive updates.'
);
} elseif ($versions['local_branch'] == 'php56') {
} elseif ($local_ver['branch'] == 'php56') {
$validator->warn(
'You are on the PHP 5.6/7.0 support branch, this will prevent automatic updates.',
'Update to PHP ' . Php::PHP_MIN_VERSION . ' or newer (PHP ' . Php::PHP_RECOMMENDED_VERSION . ' recommended) to continue to receive updates.'

View File

@ -29,15 +29,16 @@ use Illuminate\Support\Str;
use LibreNMS\Interfaces\ValidationGroup;
use LibreNMS\Util\Laravel;
use ReflectionClass;
use ReflectionException;
class Validator
{
/** @var array */
private $validation_groups = [];
/** @var array */
private $results = [];
// data cache
/** @var string|null */
private $username;
private $versions;
/**
* Validator constructor.
@ -51,11 +52,15 @@ class Validator
$class_name = basename($file, '.php');
$class = '\LibreNMS\Validations\\' . $class_name;
$rc = new ReflectionClass($class);
if (! $rc->isAbstract()) {
$validation_name = strtolower($class_name);
$this->validation_groups[$validation_name] = new $class();
$this->results[$validation_name] = [];
try {
$rc = new ReflectionClass($class);
if (! $rc->isAbstract()) {
$validation_name = strtolower($class_name);
$this->validation_groups[$validation_name] = new $class();
$this->results[$validation_name] = [];
}
} catch (ReflectionException $e) {
}
}
}
@ -66,7 +71,7 @@ class Validator
* @param array $validation_groups selected validation groups to run
* @param bool $print_group_status print out group status
*/
public function validate($validation_groups = [], $print_group_status = false)
public function validate(array $validation_groups = [], bool $print_group_status = false): void
{
foreach ($this->validation_groups as $group_name => $group) {
// only run each group once
@ -103,32 +108,25 @@ class Validator
* @param string $validation_group
* @return int
*/
public function getGroupStatus($validation_group)
public function getGroupStatus(string $validation_group): int
{
$results = $this->getResults($validation_group);
$status = array_reduce($results, function ($compound, $result) {
/** @var ValidationResult $result */
return array_reduce($results, function ($compound, ValidationResult $result) {
return min($compound, $result->getStatus());
}, ValidationResult::SUCCESS);
return $status;
}
/**
* Get the ValidationResults for a specific validation group.
*
* @param string $validation_group
* @param string|null $validation_group
* @return ValidationResult[]
*/
public function getResults($validation_group = null)
public function getResults(string $validation_group = null): array
{
if (isset($validation_group)) {
if (isset($this->results[$validation_group])) {
return $this->results[$validation_group];
} else {
return [];
}
return $this->results[$validation_group] ?? [];
}
return array_reduce($this->results, 'array_merge', []);
@ -138,9 +136,9 @@ class Validator
* Get all of the ValidationResults that have been submitted.
* ValidationResults will be grouped by the validation group.
*
* @return array
* @return ValidationResult[][]
*/
public function getAllResults()
public function getAllResults(): array
{
return $this->results;
}
@ -148,14 +146,13 @@ class Validator
/**
* Print all ValidationResults or a group of them.
*
* @param string $validation_group
* @param string|null $validation_group
*/
public function printResults($validation_group = null)
public function printResults(string $validation_group = null): void
{
$results = $this->getResults($validation_group);
foreach ($results as $result) {
/** @var ValidationResult $result */
$result->consolePrint();
}
}
@ -165,9 +162,9 @@ class Validator
* 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
* @param string|null $group manually specify the group, otherwise this will be inferred from the callers class name
*/
public function result(ValidationResult $result, $group = null)
public function result(ValidationResult $result, string $group = null): void
{
// get the name of the validation that submitted this result
if (empty($group)) {
@ -188,10 +185,10 @@ class Validator
* 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
* @param string|null $fix
* @param string|null $group manually specify the group, otherwise this will be inferred from the callers class name
*/
public function ok($message, $fix = null, $group = null)
public function ok(string $message, string $fix = null, string $group = null): void
{
$this->result(new ValidationResult($message, ValidationResult::SUCCESS, $fix), $group);
}
@ -200,10 +197,10 @@ class Validator
* 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
* @param string|null $fix
* @param string|null $group manually specify the group, otherwise this will be inferred from the callers class name
*/
public function warn($message, $fix = null, $group = null)
public function warn(string $message, string $fix = null, string $group = null): void
{
$this->result(new ValidationResult($message, ValidationResult::WARNING, $fix), $group);
}
@ -212,10 +209,10 @@ class Validator
* 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
* @param string|null $fix
* @param string|null $group manually specify the group, otherwise this will be inferred from the callers class name
*/
public function fail($message, $fix = null, $group = null)
public function fail(string $message, string $fix = null, string $group = null): void
{
$this->result(new ValidationResult($message, ValidationResult::FAILURE, $fix), $group);
}
@ -224,41 +221,22 @@ class Validator
* Submit an informational validation result.
*
* @param string $message
* @param string $group manually specify the group, otherwise this will be inferred from the callers class name
* @param string|null $group manually specify the group, otherwise this will be inferred from the callers class name
*/
public function info($message, $group = null)
public function info(string $message, string $group = null): void
{
$this->result(new ValidationResult($message, ValidationResult::INFO), $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
* @param array|null $output will hold the output of the command
* @param int|null $code will hold the return code from the command
*/
public function execAsUser($command, &$output = null, &$code = null)
public function execAsUser(string $command, array &$output = null, int &$code = null): void
{
if (self::getUsername() === 'root') {
$command = 'su ' . \config('librenms.user') . ' -s /bin/sh -c "' . $command . '"';
@ -271,7 +249,7 @@ class Validator
*
* @return string
*/
public function getUsername()
public function getUsername(): string
{
if (! isset($this->username)) {
if (function_exists('posix_getpwuid')) {
@ -291,15 +269,48 @@ class Validator
*
* @return string the base url without a trailing /
*/
public function getBaseURL()
public function getBaseURL(): string
{
$url = function_exists('get_url') ? get_url() : Config::get('base_url');
return rtrim(str_replace('validate', '', $url), '/'); // get base_url from current url
}
public function getBaseDir()
public function getBaseDir(): string
{
return realpath(__DIR__ . '/..');
}
public function getStatusText(int $status): string
{
switch ($status) {
case ValidationResult::SUCCESS:
return 'Ok';
case ValidationResult::FAILURE:
return 'Failure';
case ValidationResult::WARNING:
return 'Warning';
case ValidationResult::INFO:
return 'Info';
default:
return '';
}
}
public function toArray(): array
{
return array_map(function (array $results, string $group) {
$groupStatus = $this->getGroupStatus($group);
return [
'group' => $group,
'name' => ucfirst($group),
'status' => $groupStatus,
'statusText' => $this->getStatusText($groupStatus),
'results' => array_map(function (ValidationResult $result) {
return $result->toArray();
}, $results),
];
}, $this->getAllResults(), array_keys($this->getAllResults()));
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use LibreNMS\Validator;
class ValidateController extends Controller
{
public function index(): View
{
return view('validate.index');
}
public function runValidation(): JsonResponse
{
$validator = new Validator();
$validator->validate();
return response()->json($validator->toArray());
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,15 +1,15 @@
{
"/js/app.js": "/js/app.js?id=dba3e37f44ce826e96d0",
"/js/app.js": "/js/app.js?id=9a782f01e0fef69d02a2",
"/js/manifest.js": "/js/manifest.js?id=2951ae529be231f05a93",
"/css/vendor.css": "/css/vendor.css?id=2568831af31dbfc3128a",
"/css/app.css": "/css/app.css?id=936fe619dcf1bac0a33f",
"/css/app.css": "/css/app.css?id=113371a4c292b55f1e9e",
"/js/vendor.js": "/js/vendor.js?id=c5fd3d75a63757080dbb",
"/js/lang/de.js": "/js/lang/de.js?id=1aedfce25e3daad3046a",
"/js/lang/en.js": "/js/lang/en.js?id=f16225e77f5dbe2541ac",
"/js/lang/fr.js": "/js/lang/fr.js?id=a20c4c78eb5f9f4a374b",
"/js/lang/it.js": "/js/lang/it.js?id=6b0bdf3be6dc3bf0a167",
"/js/lang/de.js": "/js/lang/de.js?id=e2912d41c392d8bc4e2c",
"/js/lang/en.js": "/js/lang/en.js?id=7aed3226fceb16d522cd",
"/js/lang/fr.js": "/js/lang/fr.js?id=bd58747a5439aafb8330",
"/js/lang/it.js": "/js/lang/it.js?id=5fdcbbb097408f63d589",
"/js/lang/ru.js": "/js/lang/ru.js?id=f6b7c078755312a0907c",
"/js/lang/uk.js": "/js/lang/uk.js?id=1bba323982918f74fa33",
"/js/lang/zh-CN.js": "/js/lang/zh-CN.js?id=b4219bb8e090803ee079",
"/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=7495f99f35742c3e06b5"
"/js/lang/zh-CN.js": "/js/lang/zh-CN.js?id=0edc19cb25bb6d36861b",
"/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=4d13fc5d8fdd20d417d3"
}

View File

@ -20,7 +20,6 @@ use LibreNMS\Config;
use LibreNMS\Enum\Alert;
use LibreNMS\Exceptions\InvalidIpException;
use LibreNMS\Util\Debug;
use LibreNMS\Util\Git;
use LibreNMS\Util\IP;
use LibreNMS\Util\Laravel;
use Symfony\Component\Process\Process;
@ -586,32 +585,20 @@ function parse_location($location)
function version_info($remote = false)
{
$version = \LibreNMS\Util\Version::get();
$local = $version->localCommit();
$output = [
'local_ver' => $version->local(),
'local_sha' => $local['sha'],
'local_date' => $local['date'],
'local_branch' => $local['branch'],
'github' => $remote ? $version->remoteCommit() : null,
'db_schema' => vsprintf('%s (%s)', $version->database()),
'php_ver' => phpversion(),
'python_ver' => $version->python(),
'mysql_ver' => $version->databaseServer(),
'rrdtool_ver' => $version->rrdtool(),
'netsnmp_ver' => $version->netSnmp(),
];
if (Git::repoPresent() && Git::binaryExists()) {
if ($remote === true && Config::get('update_channel') == 'master') {
$api = curl_init();
set_curl_proxy($api);
curl_setopt($api, CURLOPT_USERAGENT, 'LibreNMS');
curl_setopt($api, CURLOPT_URL, Config::get('github_api') . 'commits/master');
curl_setopt($api, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($api, CURLOPT_TIMEOUT, 5);
curl_setopt($api, CURLOPT_TIMEOUT_MS, 5000);
curl_setopt($api, CURLOPT_CONNECTTIMEOUT, 5);
$output['github'] = json_decode(curl_exec($api), true);
}
[$local_sha, $local_date] = explode('|', rtrim(`git show --pretty='%H|%ct' -s HEAD`));
$output['local_sha'] = $local_sha;
$output['local_date'] = $local_date;
$output['local_branch'] = rtrim(`git rev-parse --abbrev-ref HEAD`);
}
$output['db_schema'] = vsprintf('%s (%s)', $version->database());
$output['php_ver'] = phpversion();
$output['python_ver'] = $version->python();
$output['mysql_ver'] = \LibreNMS\DB\Eloquent::isConnected() ? \LibreNMS\DB\Eloquent::version() : '?';
$output['rrdtool_ver'] = $version->rrdtool();
$output['netsnmp_ver'] = $version->netSnmp();
return $output;
}//end version_info()

View File

@ -81,19 +81,6 @@ function toner2colour($descr, $percent)
return $colour;
}//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-z0-9\-]+(/\S*)?#i";
return preg_replace($regex, '<a href="$0">$0</a>', $text);
}
function generate_link($text, $vars, $new_vars = [])
{
return '<a href="' . \LibreNMS\Util\Url::generate($vars, $new_vars) . '">' . $text . '</a>';

View File

@ -1,141 +0,0 @@
<?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 <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
*
* @copyright 2017 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
use LibreNMS\ValidationResult;
use LibreNMS\Validator;
$no_refresh = true;
?>
<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" style="margin-bottom: 5px"><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';
if ($result->getStatus() == ValidationResult::SUCCESS) {
echo ' panel-success"><div class="panel-heading bg-success"> Ok: ';
} elseif ($result->getStatus() == ValidationResult::WARNING) {
echo ' panel-warning"><div class="panel-heading bg-warning"> Warning: ';
} elseif ($result->getStatus() == ValidationResult::FAILURE) {
echo ' panel-danger"><div class="panel-heading bg-danger"> Fail: ';
}
echo $result->getMessage();
echo '</div>';
if ($result->hasFix() || $result->hasList()) {
echo '<div class="panel-body">';
if ($result->hasFix()) {
echo 'Fix: <code>';
foreach ((array) $result->getFix() as $fix) {
echo '<br />' . linkify($fix) . PHP_EOL;
}
echo '</code>';
if ($result->hasList()) {
echo '<br /><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>
</div>
<script>
function expandList($id) {
var item = $("#extraList" + $id);
console.log(item);
$("#extraList" + $id).show();
$("#button" + $id).hide();
}
</script>

View File

@ -6635,86 +6635,6 @@ parameters:
count: 1
path: LibreNMS/Util/Validate.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:consolePrint\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:getFix\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:getList\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:getListDescription\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:getMessage\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:getStatusText\\(\\) has parameter \\$status with no type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:hasFix\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:hasList\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:printList\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:setList\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Method LibreNMS\\\\ValidationResult\\:\\:setList\\(\\) has parameter \\$description with no type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Property LibreNMS\\\\ValidationResult\\:\\:\\$fix has no type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Property LibreNMS\\\\ValidationResult\\:\\:\\$list has no type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Property LibreNMS\\\\ValidationResult\\:\\:\\$list_description has no type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Property LibreNMS\\\\ValidationResult\\:\\:\\$message has no type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Property LibreNMS\\\\ValidationResult\\:\\:\\$status has no type specified\\.$#"
count: 1
path: LibreNMS/ValidationResult.php
-
message: "#^Property LibreNMS\\\\Validations\\\\BaseValidation\\:\\:\\$RUN_BY_DEFAULT has no type specified\\.$#"
count: 1
@ -7125,71 +7045,6 @@ parameters:
count: 1
path: LibreNMS/Validations/User.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:execAsUser\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:fail\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:getBaseDir\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:info\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:ok\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:printResults\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:result\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:validate\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Method LibreNMS\\\\Validator\\:\\:warn\\(\\) has no return type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Property LibreNMS\\\\Validator\\:\\:\\$results has no type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Property LibreNMS\\\\Validator\\:\\:\\$username has no type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Property LibreNMS\\\\Validator\\:\\:\\$validation_groups has no type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Property LibreNMS\\\\Validator\\:\\:\\$versions has no type specified\\.$#"
count: 1
path: LibreNMS/Validator.php
-
message: "#^Property App\\\\Models\\\\Device\\:\\:\\$authlevel \\('authNoPriv'\\|'authPriv'\\|'noAuthNoPriv'\\) does not accept null\\.$#"
count: 1

View File

@ -159,4 +159,12 @@ return [
'attributes' => [],
'results' => [
'fix' => 'Fix',
'fetch_failed' => 'Failed to fetch validation results',
'show_all' => 'Show all',
'show_less' => 'Show less',
'validate' => 'Validate',
'validating' => 'Validating',
],
];

View File

@ -0,0 +1,80 @@
@extends('layouts.librenmsv1')
@section('title', __('validation.results.validate'))
@section('content')
<div x-data="{results: [], listItems: 10, errorMessage: ''}"
x-init="fetch('{{ route('validate.results') }}').then(response => response.json().then(data => results = data).catch(error => errorMessage = error))"
>
<div class="tw-grid tw-place-items-center" style="height: 80vh" x-show="! results.length">
<h3 x-show="! errorMessage"><i class="fa-solid fa-spinner fa-spin"></i> {{ __('validation.results.validating') }}</h3>
<div x-show="errorMessage" class="panel panel-danger">
<div class="panel-heading">
<i class="fa-solid fa-exclamation-triangle"></i> {{ __('validation.results.fetch_failed') }}
</div>
<div class="panel-body" x-text="errorMessage"></div>
</div>
</div>
<div x-show="results.length" class="tw-mx-10">
<template x-for="(group, index) in results">
<div class="panel-group" style="margin-bottom: 5px">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" x-bind:data-target="'#body-' + group.group">
<span x-text="group.name"></span>
<span class="pull-right"
x-bind:class="{'text-success': group.status === 2, 'text-warning': group.status === 1, 'text-danger': group.status === 0}"
x-text="group.statusText"></span>
</a>
</h4>
</div>
<div x-bind:id="'body-' + group.group" class="panel-collapse collapse" x-bind:class="{'in': group.status !== 2}">
<div class="panel-body">
<template x-for="result in group.results">
<div class="panel" x-bind:class="{'panel-success': group.status === 2, 'panel-warning': group.status === 1, 'panel-danger': group.status === 0}">
<div class="panel-heading"
x-bind:class="{'bg-success': result.status === 2, 'bg-warning': result.status === 1, 'bg-danger': result.status === 0}"
x-text="result.statusText + ': ' + result.message"
></div>
<div class="panel-body" x-show="result.fix.length || result.list.length">
<div x-show="result.fix.length">
{{ __('validation.results.fix') }}: <code>
<template x-for="fixText in result.fix">
<span x-text="fixText"></span>
</template>
</code>
</div>
<div x-show="result.list.length" class="tw-mt-5">
<ul class='list-group' style='margin-bottom: -1px'>
<li class="list-group-item active" x-text="result.listDescription"></li>
<template x-for="shortList in result.list.slice(0, listItems)">
<li class="list-group-item" x-text="shortList"></li>
</template>
</ul>
<div x-data="{expanded: false}" x-show="result.list.length > listItems">
<button style="margin-top: 3px" type="button" class="btn btn-default" x-on:click="expanded = ! expanded" x-text="expanded ? '{{ __('validation.results.show_less')}}' : '{{ __('validation.results.show_all')}}'"></button>
<ul x-show="expanded" class='list-group'>
<template x-for="longList in result.list.slice(listItems)">
<li class='list-group-item' x-text="longList"></li>
</template>
</ul>
</div>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</template>
</div>
</div>
@endsection
@push('scripts')
<script>
</script>
@endpush

View File

@ -87,6 +87,8 @@ Route::group(['middleware' => ['auth'], 'guard' => 'auth'], function () {
Route::post('plugin/settings/{plugin:plugin_name}', 'PluginSettingsController@update')->name('plugin.update');
Route::resource('port-groups', 'PortGroupController');
Route::get('validate', [\App\Http\Controllers\ValidateController::class, 'index'])->name('validate');
Route::get('validate/results', [\App\Http\Controllers\ValidateController::class, 'runValidation'])->name('validate.results');
});
Route::get('plugin', 'PluginLegacyController@redirect');

View File

@ -26,6 +26,7 @@
namespace LibreNMS\Tests;
use LibreNMS\Device\YamlDiscovery;
use LibreNMS\Util\Html;
use LibreNMS\Util\Rewrite;
class FunctionsTest extends TestCase
@ -68,7 +69,7 @@ sdfsd <a href="ftp://192.168.1.1/help/me/now.php">ftp://192.168.1.1/help/me/now.
<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));
$this->assertSame($expected, Html::linkify($input));
}
public function testDynamicDiscoveryGetValue()

View File

@ -134,7 +134,7 @@ if (\LibreNMS\DB\Eloquent::isConnected()) {
}
$precheck_complete = true; // disable shutdown function
print_header($validator->getVersions());
print_header(version_info());
if (isset($options['g'])) {
$modules = explode(',', $options['g']);