mirror of
https://github.com/librenms/librenms.git
synced 2024-09-21 02:18:39 +00:00
Cache version data (#14404)
* Cache version data Calling cli commands can be expensive, cache the results. * style fixes * Fix pre-laravel usage * fix lint
This commit is contained in:
parent
9648edcf1b
commit
06c361c2b5
@ -26,6 +26,7 @@
|
||||
namespace LibreNMS\Util;
|
||||
|
||||
use DB;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
@ -38,19 +39,16 @@ class Version
|
||||
// Update this on release
|
||||
public const VERSION = '22.9.0';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $is_git_install = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->is_git_install = Git::repoPresent() && Git::binaryExists();
|
||||
}
|
||||
/** @var array */
|
||||
protected $cache = [];
|
||||
|
||||
public static function get(): Version
|
||||
{
|
||||
return new static;
|
||||
try {
|
||||
return app()->make('version');
|
||||
} catch (BindingResolutionException $e) {
|
||||
return new static; // no container, just return a fresh instance
|
||||
}
|
||||
}
|
||||
|
||||
public function release(): string
|
||||
@ -60,11 +58,23 @@ class Version
|
||||
|
||||
public function local(): string
|
||||
{
|
||||
if ($this->is_git_install && $version = $this->fromGit()) {
|
||||
return $version;
|
||||
}
|
||||
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 self::VERSION;
|
||||
});
|
||||
}
|
||||
|
||||
public function isGitInstall(): bool
|
||||
{
|
||||
return $this->cacheGet('install_type', function () {
|
||||
return (Git::repoPresent() && Git::binaryExists()) ? 'git' : 'other';
|
||||
}) == 'git';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,31 +84,43 @@ class Version
|
||||
*/
|
||||
public function localCommit(): array
|
||||
{
|
||||
if ($this->is_git_install) {
|
||||
$install_dir = base_path();
|
||||
$version_process = new Process(['git', 'show', '--quiet', '--pretty=%H|%ct'], $install_dir);
|
||||
$version_process->run();
|
||||
return [
|
||||
'sha' => $this->localCommitSha(),
|
||||
'date' => $this->localDate(),
|
||||
'branch' => $this->localBranch(),
|
||||
];
|
||||
}
|
||||
|
||||
// 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();
|
||||
public function localCommitSha(): string
|
||||
{
|
||||
return $this->cacheGet('local_commit_sha', function () {
|
||||
if (! $this->isGitInstall()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
[$local_sha, $local_date] = array_pad(explode('|', rtrim($version_process->getOutput())), 2, '');
|
||||
return $this->localCommitData()[0] ?? '';
|
||||
});
|
||||
}
|
||||
|
||||
$branch_process = new Process(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], $install_dir);
|
||||
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();
|
||||
$branch = rtrim($branch_process->getOutput());
|
||||
|
||||
return [
|
||||
'sha' => $local_sha,
|
||||
'date' => $local_date,
|
||||
'branch' => $branch,
|
||||
];
|
||||
}
|
||||
|
||||
return ['sha' => null, 'date' => null, 'branch' => null];
|
||||
return rtrim($branch_process->getOutput());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,16 +130,16 @@ class Version
|
||||
*/
|
||||
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 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 [];
|
||||
return '[]';
|
||||
}), true);
|
||||
}
|
||||
|
||||
public function databaseServer(): string
|
||||
@ -156,53 +178,50 @@ class Version
|
||||
return ['last' => 'Not Connected', 'total' => 0];
|
||||
}
|
||||
|
||||
private function fromGit(): string
|
||||
{
|
||||
return rtrim(shell_exec('git describe --tags 2>/dev/null'));
|
||||
}
|
||||
|
||||
public function gitChangelog(): string
|
||||
{
|
||||
return $this->is_git_install
|
||||
? rtrim(shell_exec('git log -10'))
|
||||
: '';
|
||||
}
|
||||
|
||||
public function gitDate(): string
|
||||
{
|
||||
return $this->is_git_install
|
||||
? rtrim(shell_exec("git show --pretty='%ct' -s HEAD"))
|
||||
: '';
|
||||
return $this->cacheGet('changelog', function () {
|
||||
return $this->isGitInstall()
|
||||
? rtrim(shell_exec('git log -10'))
|
||||
: '';
|
||||
});
|
||||
}
|
||||
|
||||
public function python(): string
|
||||
{
|
||||
$proc = new Process(['python3', '--version']);
|
||||
$proc->run();
|
||||
return $this->cacheGet('python', function () {
|
||||
$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
|
||||
{
|
||||
$process = new Process([Config::get('rrdtool', 'rrdtool'), '--version']);
|
||||
$process->run();
|
||||
preg_match('/^RRDtool ([\w.]+) /', $process->getOutput(), $matches);
|
||||
return $this->cacheGet('rrdtool', function () {
|
||||
$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
|
||||
{
|
||||
$process = new Process([Config::get('snmpget', 'snmpget'), '-V']);
|
||||
$process->run();
|
||||
preg_match('/[\w.]+$/', $process->getErrorOutput(), $matches);
|
||||
return $this->cacheGet('net-snmp', function () {
|
||||
$process = new Process([Config::get('snmpget', 'snmpget'), '-V']);
|
||||
|
||||
return $matches[0] ?? '';
|
||||
$process->run();
|
||||
preg_match('/[\w.]+$/', $process->getErrorOutput(), $matches);
|
||||
|
||||
return $matches[0] ?? '';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -210,30 +229,61 @@ class Version
|
||||
*/
|
||||
public function os(): string
|
||||
{
|
||||
$info = [];
|
||||
return $this->cacheGet('os', function () {
|
||||
$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]);
|
||||
|
||||
return implode(' ', $only);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* We want these each runtime, so don't use the global cache
|
||||
*/
|
||||
private function cacheGet(string $name, callable $actual): string
|
||||
{
|
||||
if (! array_key_exists($name, $this->cache)) {
|
||||
$this->cache[$name] = $actual($name);
|
||||
}
|
||||
|
||||
$only = array_intersect_key($info, ['NAME' => true, 'VERSION_ID' => true]);
|
||||
return $this->cache[$name];
|
||||
}
|
||||
|
||||
return implode(' ', $only);
|
||||
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());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class AboutController extends Controller
|
||||
|
||||
'db_schema' => vsprintf('%s (%s)', $version->database()),
|
||||
'git_log' => $version->gitChangelog(),
|
||||
'git_date' => $version->gitDate(),
|
||||
'git_date' => $version->localDate(),
|
||||
'project_name' => Config::get('project_name'),
|
||||
|
||||
'version_local' => $version->local(),
|
||||
|
@ -31,6 +31,9 @@ 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->bind(\App\Models\Device::class, function () {
|
||||
/** @var \LibreNMS\Cache\Device $cache */
|
||||
|
@ -541,12 +541,12 @@ function parse_location($location)
|
||||
function version_info($remote = false)
|
||||
{
|
||||
$version = \LibreNMS\Util\Version::get();
|
||||
$local = $version->localCommit();
|
||||
$output = [
|
||||
|
||||
return [
|
||||
'local_ver' => $version->local(),
|
||||
'local_sha' => $local['sha'],
|
||||
'local_date' => $local['date'],
|
||||
'local_branch' => $local['branch'],
|
||||
'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(),
|
||||
@ -555,8 +555,6 @@ function version_info($remote = false)
|
||||
'rrdtool_ver' => $version->rrdtool(),
|
||||
'netsnmp_ver' => $version->netSnmp(),
|
||||
];
|
||||
|
||||
return $output;
|
||||
}//end version_info()
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user