diff --git a/LibreNMS/DB/Schema.php b/LibreNMS/DB/Schema.php index ee936f5c94..8e3220ef4e 100644 --- a/LibreNMS/DB/Schema.php +++ b/LibreNMS/DB/Schema.php @@ -167,7 +167,7 @@ class Schema $update_cache = true; $cache = []; $cache_file = Config::get('install_dir') . "/cache/{$base}_relationships.cache"; - $db_version = Version::get()->database(); + $db_version = Version::get()->databaseMigrationCount(); if (is_file($cache_file)) { $cache = unserialize(file_get_contents($cache_file)); diff --git a/LibreNMS/IRCBot.php b/LibreNMS/IRCBot.php index a5a248138b..53c01542a5 100644 --- a/LibreNMS/IRCBot.php +++ b/LibreNMS/IRCBot.php @@ -25,6 +25,7 @@ use LibreNMS\DB\Eloquent; use LibreNMS\Enum\AlertState; use LibreNMS\Util\Number; use LibreNMS\Util\Time; +use LibreNMS\Util\Version; use Permissions; class IRCBot @@ -781,11 +782,9 @@ class IRCBot private function _version($params) { - $versions = version_info(); - $schema_version = $versions['db_schema']; - $version = $versions['local_ver']; + $version = Version::get(); - $msg = $this->config['project_name'] . ', Version: ' . $version . ', DB schema: ' . $schema_version . ', PHP: ' . PHP_VERSION; + $msg = $this->config['project_name'] . ', Version: ' . $version->name() . ', DB schema: ' . $version->databaseMigrationCount() . ', PHP: ' . PHP_VERSION; return $this->respond($msg); } diff --git a/LibreNMS/Poller.php b/LibreNMS/Poller.php index c123dc01c8..2638564be8 100644 --- a/LibreNMS/Poller.php +++ b/LibreNMS/Poller.php @@ -40,9 +40,9 @@ use LibreNMS\Polling\ConnectivityHelper; use LibreNMS\RRD\RrdDefinition; use LibreNMS\Util\Debug; use LibreNMS\Util\Dns; -use LibreNMS\Util\Git; use LibreNMS\Util\Module; use LibreNMS\Util\StringHelpers; +use LibreNMS\Util\Version; use Psr\Log\LoggerInterface; use Throwable; @@ -362,27 +362,7 @@ EOH, $this->device->hostname, $group ? " ($group)" : '', $this->device->device_i private function printHeader(): void { if (Debug::isEnabled() || Debug::isVerbose()) { - $version = \LibreNMS\Util\Version::get(); - $this->logger->info(sprintf(<<<'EOH' -=================================== -Version info: -Commit SHA: %s -Commit Date: %s -DB Schema: %s -PHP: %s -Database: %s -RRDTool: %s -SNMP: %s -================================== -EOH, - Git::localCommit(), - Git::localDate(), - vsprintf('%s (%s)', $version->database()), - phpversion(), - $version->databaseServer(), - $version->rrdtool(), - $version->netSnmp() - )); + $this->logger->info(Version::get()->header()); } } } diff --git a/LibreNMS/Traits/RuntimeClassCache.php b/LibreNMS/Traits/RuntimeClassCache.php new file mode 100644 index 0000000000..05aa267e6d --- /dev/null +++ b/LibreNMS/Traits/RuntimeClassCache.php @@ -0,0 +1,55 @@ +. + * + * @link https://www.librenms.org + * + * @copyright 2022 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Traits; + +use Illuminate\Support\Facades\Cache; +use LibreNMS\Util\Laravel; + +trait RuntimeClassCache +{ + /** @var array */ + private $runtimeCache = []; + + /** @var int Setting this installs the data in the external cache to be shared across instances */ + protected $runtimeCacheExternalTTL = 0; + + /** + * We want these each runtime, so don't use the global cache + * + * @return mixed + */ + protected function cacheGet(string $name, callable $actual) + { + if (! array_key_exists($name, $this->runtimeCache)) { + $this->runtimeCache[$name] = $this->runtimeCacheExternalTTL && Laravel::isBooted() + ? Cache::remember('runtimeCache' . __CLASS__ . $name, $this->runtimeCacheExternalTTL, $actual) + : $actual(); + } + + return $this->runtimeCache[$name]; + } +} diff --git a/LibreNMS/Util/Git.php b/LibreNMS/Util/Git.php index b150964456..3a0956f200 100644 --- a/LibreNMS/Util/Git.php +++ b/LibreNMS/Util/Git.php @@ -25,74 +25,210 @@ namespace LibreNMS\Util; -use Carbon\Carbon; +use Illuminate\Contracts\Container\BindingResolutionException; +use Illuminate\Http\Client\ConnectionException; +use Illuminate\Support\Str; use LibreNMS\Config; +use LibreNMS\Traits\RuntimeClassCache; use Symfony\Component\Process\Process; class Git { - public static function repoPresent(): bool - { - $install_dir = Config::get('install_dir', realpath(__DIR__ . '/../..')); + use RuntimeClassCache; - return file_exists("$install_dir/.git"); + /** @var string */ + private $install_dir; + + public function __construct(int $cache = 0) + { + $this->runtimeCacheExternalTTL = $cache; + $this->install_dir = Config::get('install_dir', realpath(__DIR__ . '/../..')); } - public static function binaryExists(): bool + public static function make(int $cache = 0): Git { - exec('git > /dev/null 2>&1', $response, $exit_code); + try { + $git = app()->make('git'); // get the singleton + $git->runtimeCacheExternalTTL = $cache; - return $exit_code === 1; + return $git; + } catch (BindingResolutionException $e) { + return new static($cache); // no container, just return a regular instance + } } - public static function localCommit(): string + public function isAvailable(): bool { - return rtrim(exec("git show --pretty='%H' -s HEAD")); + return $this->cacheGet('isAvailable', function () { + return $this->repoPresent() && $this->binaryExists(); + }); } - public static function localDate(): Carbon + public function repoPresent(): bool { - return \Date::createFromTimestamp(exec("git show --pretty='%ct' -s HEAD")); + return $this->cacheGet('repoPresent', function () { + return file_exists("$this->install_dir/.git"); + }); } - public static function unchanged(): bool + public function binaryExists(): bool { - $process = new Process(['git', 'diff-index', '--quiet', 'HEAD']); - $process->disableOutput(); - $process->run(); + return $this->cacheGet('binaryExists', function () { + return $this->run('help', [])->isSuccessful(); + }); + } - return $process->getExitCode() === 0; + public function tag(): string + { + return $this->cacheGet('tag', function () { + return $this->isAvailable() + ? rtrim($this->run('describe', ['--tags'])->getOutput()) + : ''; + }); + } + + public function shortTag(): string + { + return $this->cacheGet('shortTag', function () { + return $this->isAvailable() + ? rtrim($this->run('describe', ['--tags', '--abbrev=0'])->getOutput()) + : ''; + }); + } + + /** + * Returns the commit hash of the local HEAD commit + */ + public function commitHash(): string + { + return $this->headCommit()[0] ?? ''; + } + + /** + * Get the date of the local HEAD commit + */ + public function commitDate(): string + { + return $this->headCommit()[1] ?? ''; + } + + /** + * Get the current branch + */ + public function branch(): string + { + return $this->cacheGet('branch', function () { + return $this->isAvailable() + ? rtrim($this->run('rev-parse', ['--abbrev-ref', 'HEAD'])->getOutput()) + : ''; + }); + } + + /** + * Detect if there are local uncommitted changes. + */ + public function hasChanges(): bool + { + return $this->cacheGet('hasChanges', function () { + return $this->isAvailable() && ! $this->run('diff-index', ['--quiet', 'HEAD'])->isSuccessful(); + }); } /** * Note: It assumes origin/master points to github.com/librenms/librenms for this to work. */ - public static function officalCommit(?string $hash = null, string $remote = 'origin/master'): bool + public function isOfficialCommit(): bool { - if ($hash === null) { - $process = new Process(['git', 'rev-parse', 'HEAD']); - $process->run(); - - $hash = trim($process->getOutput()); - } - - $process = new Process(['git', 'branch', '--remotes', '--contains', $hash, $remote]); - $process->run(); - - if ($process->isSuccessful()) { - if (trim($process->getOutput()) == $remote) { - return true; + return $this->cacheGet('isOfficialCommit', function () { + if (! $this->isAvailable()) { + return false; } - } - return false; + $process = $this->run('branch', ['--remotes', '--contains', $this->commitHash(), 'origin/master']); + + return $process->isSuccessful() && trim($process->getOutput()) == 'origin/master'; + }); } - public static function remoteUrl(string $remote = 'origin'): string + /** + * Get the url of the origin remote + */ + public function remoteUrl(): string { - $process = new Process(['git', 'ls-remote', '--get-url', $remote]); - $process->run(); + return $this->cacheGet('remoteUrl', function () { + return $this->isAvailable() + ? rtrim($this->run('ls-remote', ['--get-url', 'origin'])->getOutput()) + : ''; + }); + } - return trim($process->getOutput()); + public function message(): string + { + return $this->cacheGet('remoteUrl', function () { + return $this->isAvailable() + ? rtrim($this->run('log', ['--pretty=format:%s', '-n', '1'])->getOutput()) + : ''; + }); + } + + public function log(int $lines = 10): string + { + return $this->cacheGet('changelog' . $lines, function () use ($lines) { + return $this->isAvailable() + ? rtrim($this->run('log', ['-' . $lines])->getOutput()) + : ''; + }); + } + + /** + * Fetches the remote commit hash from the github api if on the daily release channel + */ + public function remoteHash(): string + { + return $this->remoteCommit()['sha'] ?? ''; + } + + /** + * Fetches the remote commit from the github api if on the daily release channel + */ + private function remoteCommit(): array + { + return $this->cacheGet('remoteCommit', function () { + if ($this->isAvailable()) { + try { + return (array) \Http::withOptions(['proxy' => Proxy::forGuzzle()])->get(Config::get('github_api') . 'commits/master')->json(); + } catch (ConnectionException $e) { + } + } + + return []; + }); + } + + private function headCommit(): array + { + return $this->cacheGet('headCommit', function () { + if (! $this->isAvailable()) { + return []; + } + + $version_process = $this->run('show', ['--quiet', '--pretty=%H|%ct']); + + // failed due to permissions issue + if ($version_process->getExitCode() == 128 && Str::startsWith($version_process->getErrorOutput(), 'fatal: unsafe repository')) { + $this->run('config', ['--global', '--add', 'safe.directory', $this->install_dir]); // try to fix + $version_process = $this->run('show', ['--quiet', '--pretty=%H|%ct']); // and try again + } + + return explode('|', rtrim($version_process->getOutput())); + }); + } + + private function run(string $command, array $options): Process + { + $version_process = new Process(array_merge(['git', $command], $options), $this->install_dir); + $version_process->run(); + + return $version_process; } } diff --git a/LibreNMS/Util/Version.php b/LibreNMS/Util/Version.php index e2c4e883d8..a764b2ee87 100644 --- a/LibreNMS/Util/Version.php +++ b/LibreNMS/Util/Version.php @@ -26,29 +26,27 @@ namespace LibreNMS\Util; use DB; -use Illuminate\Contracts\Container\BindingResolutionException; -use Illuminate\Http\Client\ConnectionException; use Illuminate\Support\Arr; -use Illuminate\Support\Str; use LibreNMS\Config; use LibreNMS\DB\Eloquent; use Symfony\Component\Process\Process; class Version { - // Update this on release + /** @var string Update this on release */ public const VERSION = '22.9.0'; - /** @var array */ - protected $cache = []; + /** @var Git convenience instance */ + public $git; + + public function __construct() + { + $this->git = Git::make(); + } public static function get(): Version { - try { - return app()->make('version'); - } catch (BindingResolutionException $e) { - return new static; // no container, just return a fresh instance - } + return new static; } public function release(): string @@ -56,90 +54,14 @@ class Version return Config::get('update_channel') == 'master' ? 'master' : self::VERSION; } - public function local(): string + public function date(string $format = 'c'): string { - return $this->cacheGet('local_version', function () { - if ($this->isGitInstall()) { - $version = rtrim(shell_exec('git describe --tags 2>/dev/null')); - if ($version) { - return $version; - } - } - - return self::VERSION; - }); + return date($format, $this->git->commitDate() ?: filemtime(__FILE__)); // approximate date for non-git installs } - public function isGitInstall(): bool + public function name(): string { - return $this->cacheGet('install_type', function () { - return (Git::repoPresent() && Git::binaryExists()) ? 'git' : 'other'; - }) == 'git'; - } - - /** - * Compiles local commit data - * - * @return array with keys sha, date, and branch - */ - public function localCommit(): array - { - return [ - 'sha' => $this->localCommitSha(), - 'date' => $this->localDate(), - 'branch' => $this->localBranch(), - ]; - } - - public function localCommitSha(): string - { - return $this->cacheGet('local_commit_sha', function () { - if (! $this->isGitInstall()) { - return ''; - } - - return $this->localCommitData()[0] ?? ''; - }); - } - - public function localDate(): string - { - return $this->cacheGet('local_commit_date', function () { - return $this->localCommitData()[1] ?? ''; - }); - } - - public function localBranch(): string - { - return $this->cacheGet('local_branch', function () { - if (! $this->isGitInstall()) { - return ''; - } - - $branch_process = new Process(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], Config::get('install_dir')); - $branch_process->run(); - - return rtrim($branch_process->getOutput()); - }); - } - - /** - * Fetches the remote commit from the github api if on the daily release channel - * - * @return array - */ - public function remoteCommit(): array - { - return json_decode($this->cacheGet('remote_commit', function () { - if ($this->isGitInstall()) { - try { - return \Http::withOptions(['proxy' => Proxy::forGuzzle()])->get(Config::get('github_api') . 'commits/master')->body(); - } catch (ConnectionException $e) { - } - } - - return '[]'; - }), true); + return $this->git->tag() ?: self::VERSION; } public function databaseServer(): string @@ -160,68 +82,74 @@ class Version } } - public function database(): array + /** + * Get the database last migration and count as a string + */ + public function database(): string { - if (Eloquent::isConnected()) { - try { - $query = Eloquent::DB()->table('migrations'); - - return [ - 'last' => $query->orderBy('id', 'desc')->value('migration'), - 'total' => $query->count(), - ]; - } catch (\Exception $e) { - return ['last' => 'No Schema', 'total' => 0]; - } - } - - return ['last' => 'Not Connected', 'total' => 0]; + return sprintf('%s (%s)', $this->lastDatabaseMigration(), $this->databaseMigrationCount()); } - public function gitChangelog(): string + /** + * Get the total number of migrations applied to the database + */ + public function databaseMigrationCount(): int { - return $this->cacheGet('changelog', function () { - return $this->isGitInstall() - ? rtrim(shell_exec('git log -10')) - : ''; - }); + try { + if (Eloquent::isConnected()) { + return Eloquent::DB()->table('migrations')->count(); + } + } catch (\Exception $e) { + } + + return 0; + } + + /** + * Get the name of the last migration that was applied to the database + */ + public function lastDatabaseMigration(): string + { + if (! Eloquent::isConnected()) { + return 'Not Connected'; + } + + try { + return Eloquent::DB()->table('migrations')->orderBy('id', 'desc')->value('migration'); + } catch (\Exception $e) { + return 'No Schema'; + } } public function python(): string { - return $this->cacheGet('python', function () { - $proc = new Process(['python3', '--version']); - $proc->run(); + $proc = new Process(['python3', '--version']); + $proc->run(); - if ($proc->getExitCode() !== 0) { - return ''; - } + if ($proc->getExitCode() !== 0) { + return ''; + } - return explode(' ', rtrim($proc->getOutput()), 2)[1] ?? ''; - }); + return explode(' ', rtrim($proc->getOutput()), 2)[1] ?? ''; } public function rrdtool(): string { - return $this->cacheGet('rrdtool', function () { - $process = new Process([Config::get('rrdtool', 'rrdtool'), '--version']); - $process->run(); - preg_match('/^RRDtool ([\w.]+) /', $process->getOutput(), $matches); + $process = new Process([Config::get('rrdtool', 'rrdtool'), '--version']); + $process->run(); + preg_match('/^RRDtool ([\w.]+) /', $process->getOutput(), $matches); - return str_replace('1.7.01.7.0', '1.7.0', $matches[1] ?? ''); - }); + return str_replace('1.7.01.7.0', '1.7.0', $matches[1] ?? ''); } public function netSnmp(): string { - return $this->cacheGet('net-snmp', function () { - $process = new Process([Config::get('snmpget', 'snmpget'), '-V']); + $process = new Process([Config::get('snmpget', 'snmpget'), '-V']); - $process->run(); - preg_match('/[\w.]+$/', $process->getErrorOutput(), $matches); + $process->run(); + preg_match('/[\w.]+$/', $process->getErrorOutput(), $matches); - return $matches[0] ?? ''; - }); + return $matches[0] ?? ''; } /** @@ -229,61 +157,61 @@ class Version */ public function os(): string { - return $this->cacheGet('os', function () { - $info = []; + $info = []; - // find release file - if (file_exists('/etc/os-release')) { - $info = @parse_ini_file('/etc/os-release'); - } else { - foreach (glob('/etc/*-release') as $file) { - $content = file_get_contents($file); - // normal os release style - $info = @parse_ini_string($content); - if (! empty($info)) { - break; - } + // find release file + if (file_exists('/etc/os-release')) { + $info = @parse_ini_file('/etc/os-release'); + } else { + foreach (glob('/etc/*-release') as $file) { + $content = file_get_contents($file); + // normal os release style + $info = @parse_ini_string($content); + if (! empty($info)) { + break; + } - // just a string of text - if (substr_count($content, PHP_EOL) <= 1) { - $info = ['NAME' => trim(str_replace('release ', '', $content))]; - break; - } + // just a string of text + if (substr_count($content, PHP_EOL) <= 1) { + $info = ['NAME' => trim(str_replace('release ', '', $content))]; + break; } } + } - $only = array_intersect_key($info, ['NAME' => true, 'VERSION_ID' => true]); + $only = array_intersect_key($info, ['NAME' => true, 'VERSION_ID' => true]); - return implode(' ', $only); - }); + return implode(' ', $only); } /** - * We want these each runtime, so don't use the global cache + * Get a formatted header to print out to the user. */ - private function cacheGet(string $name, callable $actual): string + public function header(): string { - if (! array_key_exists($name, $this->cache)) { - $this->cache[$name] = $actual($name); - } + return sprintf(<<<'EOH' +=========================================== +Component | Version +--------- | ------- +LibreNMS | %s (%s) +DB Schema | %s (%s) +PHP | %s +Python | %s +Database | %s +RRDTool | %s +SNMP | %s +=========================================== - return $this->cache[$name]; - } - - private function localCommitData(): array - { - return explode('|', $this->cacheGet('local_commit_data', function () { - $install_dir = Config::get('install_dir'); - $version_process = new Process(['git', 'show', '--quiet', '--pretty=%H|%ct'], $install_dir); - $version_process->run(); - - // failed due to permissions issue - if ($version_process->getExitCode() == 128 && Str::startsWith($version_process->getErrorOutput(), 'fatal: unsafe repository')) { - (new Process(['git', 'config', '--global', '--add', 'safe.directory', $install_dir]))->run(); - $version_process->run(); - } - - return rtrim($version_process->getOutput()); - })); +EOH, + $this->name(), + $this->date(), + $this->lastDatabaseMigration(), + $this->databaseMigrationCount(), + phpversion(), + $this->python(), + $this->databaseServer(), + $this->rrdtool(), + $this->netSnmp() + ); } } diff --git a/LibreNMS/Validations/Dependencies.php b/LibreNMS/Validations/Dependencies.php index ff7a3ad7e0..cc1b1f4d5e 100644 --- a/LibreNMS/Validations/Dependencies.php +++ b/LibreNMS/Validations/Dependencies.php @@ -47,7 +47,7 @@ class Dependencies extends BaseValidation } // if git is not installed, do not assume composer is either - if (! Git::repoPresent()) { + if (! Git::make()->repoPresent()) { $validator->ok('Installed from package; no Composer required'); return; diff --git a/LibreNMS/Validations/Updates.php b/LibreNMS/Validations/Updates.php index 5888c379f0..0f4854fd2a 100644 --- a/LibreNMS/Validations/Updates.php +++ b/LibreNMS/Validations/Updates.php @@ -32,7 +32,6 @@ use LibreNMS\ComposerHelper; use LibreNMS\Config; use LibreNMS\Util\EnvHelper; use LibreNMS\Util\Git; -use LibreNMS\Util\Version; use LibreNMS\ValidationResult; use LibreNMS\Validator; use Symfony\Component\Process\Process; @@ -47,14 +46,14 @@ class Updates extends BaseValidation return; } - if (! Git::repoPresent()) { + if (! Git::make()->repoPresent()) { $validator->warn('Non-git install, updates are manual or from package'); return; } // if git is not available, we cannot do the other tests - if (! Git::binaryExists()) { + if (! Git::make()->binaryExists()) { $validator->warn('Unable to locate git. This should probably be installed.'); return; @@ -62,10 +61,9 @@ class Updates extends BaseValidation // check if users on master update channel are up to date if (Config::get('update_channel') == 'master') { - $local_ver = Version::get()->localCommit(); - $remote_ver = Version::get()->remoteCommit(); - if ($local_ver['sha'] != ($remote_ver['sha'] ?? null)) { - if (empty($local_ver['date'])) { + $git = Git::make(); + if ($git->commitHash() != $git->remoteHash()) { + if (! $git->commitDate()) { $process = new Process(['git', 'show', '--quiet', '--pretty=%H|%ct'], base_path()); $process->run(); $error = rtrim($process->getErrorOutput()); @@ -73,7 +71,7 @@ class Updates extends BaseValidation $validator->fail('Failed to fetch version from local git: ' . $error); } else { try { - $commit_date = new DateTime('@' . $local_ver['date'], new DateTimeZone(date_default_timezone_get())); + $commit_date = new DateTime('@' . $git->commitDate(), 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'), @@ -86,13 +84,14 @@ class Updates extends BaseValidation } } - if ($local_ver['branch'] != 'master') { - if ($local_ver['branch'] == 'php53') { + $branch = $git->branch(); + if ($branch != 'master') { + if ($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 ($local_ver['branch'] == 'php56') { + } elseif ($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.' diff --git a/LibreNMS/Validations/User.php b/LibreNMS/Validations/User.php index 4ff388562b..a1910480a2 100644 --- a/LibreNMS/Validations/User.php +++ b/LibreNMS/Validations/User.php @@ -74,7 +74,7 @@ class User extends BaseValidation } // if no git, then we probably have different permissions by design - if (! Git::repoPresent()) { + if (! Git::make()->repoPresent()) { return; } diff --git a/app/Http/Controllers/AboutController.php b/app/Http/Controllers/AboutController.php index f02026873b..9337a4e19d 100644 --- a/app/Http/Controllers/AboutController.php +++ b/app/Http/Controllers/AboutController.php @@ -66,12 +66,12 @@ class AboutController extends Controller 'callback_status' => $callback_status, 'callback_uuid' => $callback_status ? Callback::get('uuid') : null, - 'db_schema' => vsprintf('%s (%s)', $version->database()), - 'git_log' => $version->gitChangelog(), - 'git_date' => $version->localDate(), + 'db_schema' => $version->database(), + 'git_log' => $version->git->log(), + 'git_date' => $version->date(), 'project_name' => Config::get('project_name'), - 'version_local' => $version->local(), + 'version_local' => $version->name(), 'version_database' => $version->databaseServer(), 'version_php' => phpversion(), 'version_laravel' => App::version(), diff --git a/app/Logging/Reporting/Middleware/AddGitInformation.php b/app/Logging/Reporting/Middleware/AddGitInformation.php new file mode 100644 index 0000000000..3802f62fe5 --- /dev/null +++ b/app/Logging/Reporting/Middleware/AddGitInformation.php @@ -0,0 +1,51 @@ +. + * + * @link https://www.librenms.org + * + * @copyright 2022 Tony Murray + * @author Tony Murray + */ + +namespace App\Logging\Reporting\Middleware; + +use Facade\FlareClient\Report; +use LibreNMS\Util\Git; + +class AddGitInformation +{ + /** + * @param \Facade\FlareClient\Report $report + * @param callable $next next in the pipeline + * @return mixed + */ + public function handle(Report $report, $next) + { + $git = Git::make(180); + + $report->group('git', [ + 'hash' => $git->commitHash(), + 'message' => $git->message(), + 'tag' => $git->shortTag(), + 'remote' => $git->remoteUrl(), + ]); + + return $next($report); + } +} diff --git a/app/Logging/Reporting/Middleware/SetGroups.php b/app/Logging/Reporting/Middleware/SetGroups.php index 11e2772d7a..02442e0bd0 100644 --- a/app/Logging/Reporting/Middleware/SetGroups.php +++ b/app/Logging/Reporting/Middleware/SetGroups.php @@ -43,7 +43,7 @@ class SetGroups $version = Version::get(); $report->group('LibreNMS', [ - 'Git version' => $version->local(), + 'Git version' => $version->name(), 'App version' => Version::VERSION, ]); diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 9a792070ef..0d6cfae53f 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -31,8 +31,8 @@ class AppServiceProvider extends ServiceProvider $this->app->singleton('device-cache', function ($app) { return new \LibreNMS\Cache\Device(); }); - $this->app->singleton('version', function ($app) { - return new \LibreNMS\Util\Version(); + $this->app->singleton('git', function ($app) { + return new \LibreNMS\Util\Git(); }); $this->app->bind(\App\Models\Device::class, function () { diff --git a/app/Providers/ErrorReportingProvider.php b/app/Providers/ErrorReportingProvider.php index 10b383c68d..eb44bc8915 100644 --- a/app/Providers/ErrorReportingProvider.php +++ b/app/Providers/ErrorReportingProvider.php @@ -25,6 +25,7 @@ namespace App\Providers; +use App\Logging\Reporting\Middleware\AddGitInformation; use App\Logging\Reporting\Middleware\CleanContext; use App\Logging\Reporting\Middleware\SetGroups; use ErrorException; @@ -69,6 +70,9 @@ class ErrorReportingProvider extends \Facade\Ignition\IgnitionServiceProvider return \LibreNMS\Util\Version::VERSION; }); + // add git information, but cache it unlike the upstream provider + Flare::registerMiddleware(AddGitInformation::class); + // Filter some extra fields for privacy // Move to header middleware when switching to spatie/laravel-ignition Flare::registerMiddleware(CleanContext::class); @@ -114,20 +118,21 @@ class ErrorReportingProvider extends \Facade\Ignition\IgnitionServiceProvider } // Check git - if (Git::repoPresent()) { - if (! Str::contains(Git::remoteUrl(), ['git@github.com:librenms/librenms.git', 'https://github.com/librenms/librenms.git'])) { + $git = Git::make(180); + if ($git->isAvailable()) { + if (! Str::contains($git->remoteUrl(), ['git@github.com:librenms/librenms.git', 'https://github.com/librenms/librenms.git'])) { \Log::debug('Reporting disabled because LibreNMS is not from the official repository'); return false; } - if (! Git::unchanged()) { + if ($git->hasChanges()) { \Log::debug('Reporting disabled because LibreNMS is not from the official repository'); return false; } - if (! Git::officalCommit()) { + if (! $git->isOfficialCommit()) { \Log::debug('Reporting disabled due to local modifications'); return false; diff --git a/config/flare.php b/config/flare.php index aae3c20368..672d3663ba 100644 --- a/config/flare.php +++ b/config/flare.php @@ -34,14 +34,14 @@ return [ 'reporting' => [ 'anonymize_ips' => true, - 'collect_git_information' => true, + 'collect_git_information' => false, 'report_queries' => true, - 'maximum_number_of_collected_queries' => 200, + 'maximum_number_of_collected_queries' => 50, 'report_query_bindings' => true, 'report_view_data' => true, 'grouping_type' => null, 'report_logs' => false, - 'maximum_number_of_collected_logs' => 200, + 'maximum_number_of_collected_logs' => 50, 'censor_request_body_fields' => ['username', 'password', 'sysContact', 'community', 'authname', 'authpass', 'cryptopass'], ], diff --git a/discovery.php b/discovery.php index 6e1e67ddef..3141831abc 100755 --- a/discovery.php +++ b/discovery.php @@ -64,19 +64,7 @@ if (isset($options['i']) && $options['i'] && isset($options['n'])) { } if (Debug::set(isset($options['d']), false) || isset($options['v'])) { - $versions = version_info(); - echo <<header(); echo "DEBUG!\n"; Debug::setVerbose(isset($options['v'])); diff --git a/includes/common.php b/includes/common.php index cb8c326f44..b1af79c039 100644 --- a/includes/common.php +++ b/includes/common.php @@ -532,31 +532,6 @@ function parse_location($location) return false; }//end parse_location() -/** - * Returns version info - * - * @param bool $remote fetch remote version info from github - * @return array - */ -function version_info($remote = false) -{ - $version = \LibreNMS\Util\Version::get(); - - return [ - 'local_ver' => $version->local(), - 'local_sha' => $version->localCommitSha(), - 'local_date' => $version->localDate(), - 'local_branch' => $version->localBranch(), - 'github' => $remote ? $version->remoteCommit() : null, - 'db_schema' => vsprintf('%s (%s)', $version->database()), - 'php_ver' => phpversion(), - 'python_ver' => $version->python(), - 'database_ver' => $version->databaseServer(), - 'rrdtool_ver' => $version->rrdtool(), - 'netsnmp_ver' => $version->netSnmp(), - ]; -}//end version_info() - /** * Convert a MySQL binary v4 (4-byte) or v6 (16-byte) IP address to a printable string. * diff --git a/includes/html/api_functions.inc.php b/includes/html/api_functions.inc.php index 9d633f0a5d..53dc7da092 100644 --- a/includes/html/api_functions.inc.php +++ b/includes/html/api_functions.inc.php @@ -2931,7 +2931,20 @@ function edit_service_for_host(Illuminate\Http\Request $request) */ function server_info() { - $versions = version_info(); + $version = \LibreNMS\Util\Version::get(); + + $versions = [ + 'local_ver' => $version->name(), + 'local_sha' => $version->git->commitHash(), + 'local_date' => $version->date(), + 'local_branch' => $version->git->branch(), + 'db_schema' => $version->database(), + 'php_ver' => phpversion(), + 'python_ver' => $version->python(), + 'database_ver' => $version->databaseServer(), + 'rrdtool_ver' => $version->rrdtool(), + 'netsnmp_ver' => $version->netSnmp(), + ]; return api_success([ $versions, diff --git a/poller.php b/poller.php index 96a3db6169..f62d318a8f 100755 --- a/poller.php +++ b/poller.php @@ -99,19 +99,7 @@ if (empty($where)) { } if (Debug::set(isset($options['d']), false) || isset($options['v'])) { - $versions = version_info(); - echo <<header(); echo "DEBUG!\n"; if (isset($options['v'])) { diff --git a/validate.php b/validate.php index ceedc8e5b7..1a176c4b34 100755 --- a/validate.php +++ b/validate.php @@ -80,7 +80,7 @@ register_shutdown_function(function () { spl_autoload_register(function ($class) { @include str_replace('\\', '/', $class) . '.php'; }); - print_header(version_info()); + print_header(); } }); @@ -134,7 +134,7 @@ if (\LibreNMS\DB\Eloquent::isConnected()) { } $precheck_complete = true; // disable shutdown function -print_header(version_info()); +print_header(); if (isset($options['g'])) { $modules = explode(',', $options['g']); @@ -147,26 +147,13 @@ if (isset($options['g'])) { // run checks $validator->validate($modules, isset($options['s']) || ! empty($modules)); -function print_header($versions) +function print_header() { $output = ob_get_clean(); @ob_end_clean(); - echo <<< EOF -==================================== -Component | Version ---------- | ------- -LibreNMS | ${versions['local_ver']} -DB Schema | ${versions['db_schema']} -PHP | ${versions['php_ver']} -Python | ${versions['python_ver']} -Database | ${versions['database_ver']} -RRDTool | ${versions['rrdtool_ver']} -SNMP | ${versions['netsnmp_ver']} -==================================== - -$output -EOF; + echo \LibreNMS\Util\Version::get()->header() . PHP_EOL; + echo $output; } // output matches that of ValidationResult