From Crimson Meerkat, 1 Year ago, written in Plain Text.
Embed
  1. commit 81938d2596888f21ebba4eda1e63ee38a43f27ed
  2. Merge: 970abb958 7b868982d
  3. Author: BHk24k33|^f~PG
  4. Date:   Sat Jul 30 00:15:12 2022 +0200
  5.  
  6.     Merge branch 'master' of https://github.com/librenms/librenms
  7.  
  8. commit 7b868982d540d4689bdc6a21e8950961aeb1ba37
  9. Author: Tony Murray <murraytony>
  10. Date:   Fri Jul 29 11:36:49 2022 -0500
  11.  
  12.     New lnms command to enable and disable plugins (#14147)
  13.    
  14.     * New lnms command to enable and disable plugins
  15.     lnms plugin:disable
  16.     lnms plugin:enable
  17.    
  18.     * cleanup
  19.    
  20.     * appease the lint gods
  21.    
  22.     * and style
  23.    
  24.     * Restore accidental file removal
  25.  
  26. diff --git a/app/Console/Commands/PluginDisable.php b/app/Console/Commands/PluginDisable.php
  27. new file mode 100644
  28. index 000000000..094f2f812
  29. --- /dev/null
  30. +++ b/app/Console/Commands/PluginDisable.php
  31. @@ -0,0 +1,49 @@
  32. +&lt;?php
  33. +
  34. +namespace App\Console\Commands;
  35. +
  36. +use App\Console\Commands\Traits\CompletesPluginArgument;
  37. +use App\Console\LnmsCommand;
  38. +use App\Models\Plugin;
  39. +use Symfony\Component\Console\Input\InputArgument;
  40. +
  41. +class PluginDisable extends LnmsCommand
  42. +{
  43. +    use CompletesPluginArgument;
  44. +
  45. +    protected $name = 'plugin:disable';
  46. +
  47. +    public function __construct()
  48. +    {
  49. +        parent::__construct();
  50. +        $this->addArgument('plugin', InputArgument::REQUIRED);
  51. +    }
  52. +
  53. +    public function handle(): int
  54. +    {
  55. +        try {
  56. +            $plugin = $this->argument('plugin');
  57. +            $query = Plugin::query();
  58. +
  59. +            if ($plugin !== 'all') {
  60. +                $query->where('plugin_name', 'like', $plugin);
  61. +            }
  62. +
  63. +            $updated = $query->update(['plugin_active' => 0]);
  64. +
  65. +            if ($updated == 0 && $query->exists()) {
  66. +                $this->info(trans('commands.plugin:enable.already_enabled'));
  67. +
  68. +                return 0;
  69. +            }
  70. +
  71. +            $this->info(trans_choice('commands.plugin:disable.disabled', $updated, ['name' => $updated]));
  72. +
  73. +            return 0;
  74. +        } catch (\Exception $e) {
  75. +            $this->error(trans('commands.plugin:disable.failed'));
  76. +
  77. +            return 1;
  78. +        }
  79. +    }
  80. +}
  81. diff --git a/app/Console/Commands/PluginEnable.php b/app/Console/Commands/PluginEnable.php
  82. new file mode 100644
  83. index 000000000..325855d2f
  84. --- /dev/null
  85. +++ b/app/Console/Commands/PluginEnable.php
  86. @@ -0,0 +1,52 @@
  87. +&lt;?php
  88. +
  89. +namespace App\Console\Commands;
  90. +
  91. +use App\Console\Commands\Traits\CompletesPluginArgument;
  92. +use App\Console\LnmsCommand;
  93. +use App\Models\Plugin;
  94. +use Symfony\Component\Console\Input\InputArgument;
  95. +
  96. +class PluginEnable extends LnmsCommand
  97. +{
  98. +    use CompletesPluginArgument;
  99. +
  100. +    protected $name = 'plugin:enable';
  101. +
  102. +    public function __construct()
  103. +    {
  104. +        parent::__construct();
  105. +        $this->addArgument('plugin', InputArgument::REQUIRED);
  106. +    }
  107. +
  108. +    public function handle(): int
  109. +    {
  110. +        try {
  111. +            $plugin = $this->argument('plugin');
  112. +
  113. +            $query = Plugin::query();
  114. +
  115. +            if ($plugin !== 'all') {
  116. +                $query->where('plugin_name', 'like', $plugin)
  117. +                    ->limit(1)
  118. +                    ->orderBy('version', 'DESC');
  119. +            }
  120. +
  121. +            $updated = $query->update(['plugin_active' => 1]);
  122. +
  123. +            if ($updated == 0 && $query->exists()) {
  124. +                $this->info(trans('commands.plugin:enable.already_enabled'));
  125. +
  126. +                return 0;
  127. +            }
  128. +
  129. +            $this->info(trans_choice('commands.plugin:enable.enabled', $updated, ['count' => $updated]));
  130. +
  131. +            return 0;
  132. +        } catch (\Exception $e) {
  133. +            $this->error(trans('commands.plugin:enable.failed'));
  134. +
  135. +            return 1;
  136. +        }
  137. +    }
  138. +}
  139. diff --git a/app/Console/Commands/Traits/CompletesPluginArgument.php b/app/Console/Commands/Traits/CompletesPluginArgument.php
  140. new file mode 100644
  141. index 000000000..251899680
  142. --- /dev/null
  143. +++ b/app/Console/Commands/Traits/CompletesPluginArgument.php
  144. @@ -0,0 +1,48 @@
  145. +&lt;?php
  146. +/**
  147. + * CompletesPluginArgument.php
  148. + *
  149. + * -Description-
  150. + *
  151. + * This program is free software: you can redistribute it and/or modify
  152. + * it under the terms of the GNU General Public License as published by
  153. + * the Free Software Foundation, either version 3 of the License, or
  154. + * (at your option) any later version.
  155. + *
  156. + * This program is distributed in the hope that it will be useful,
  157. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  158. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
  159. + * GNU General Public License for more details.
  160. + *
  161. + * You should have received a copy of the GNU General Public License
  162. + * along with this program.  If not, see <https>.
  163. + *
  164. + * @link       https://www.librenms.org
  165. + *
  166. + * @copyright  2022 Tony Murray
  167. + * @author     Tony Murray <murraytony>
  168. + */
  169. +
  170. +namespace App\Console\Commands\Traits;
  171. +
  172. +use App\Models\Plugin;
  173. +
  174. +trait CompletesPluginArgument
  175. +{
  176. +    /**
  177. +     * @param  string  $name
  178. +     * @param  string  $value
  179. +     * @param  string  $previous
  180. +     * @return array|false
  181. +     */
  182. +    public function completeArgument($name, $value, $previous)
  183. +    {
  184. +        if ($name == 'plugin') {
  185. +            return Plugin::where('plugin_name', 'like', $value . '%')
  186. +                ->pluck('plugin_name')
  187. +                ->toArray();
  188. +        }
  189. +
  190. +        return false;
  191. +    }
  192. +}
  193. diff --git a/resources/lang/en/commands.php b/resources/lang/en/commands.php
  194. index cab2d4913..0cabc62dc 100644
  195. --- a/resources/lang/en/commands.php
  196. +++ b/resources/lang/en/commands.php
  197. @@ -149,6 +149,24 @@ return [
  198.              'optionValue' => 'Selected :option is invalid. Should be one of: :values',
  199.          ],
  200.      ],
  201. +    'plugin:disable' => [
  202. +        'description' => 'Disable all plugins with the given name',
  203. +        'arguments' => [
  204. +            'plugin' => 'The name of the plugin to disable or "all" to disable all plugins',
  205. +        ],
  206. +        'already_disabled' => 'Plugin already disabled',
  207. +        'disabled' => ':count plugin disabled|:count plugins disabled',
  208. +        'failed' => 'Failed to disable plugin(s)',
  209. +    ],
  210. +    'plugin:enable' => [
  211. +        'description' => 'Enable the newest plugin with the given name',
  212. +        'arguments' => [
  213. +            'plugin' => 'The name of the plugin to enable or "all" to disable all plugins',
  214. +        ],
  215. +        'already_enabled' => 'Plugin already enabled',
  216. +        'enabled' => ':count plugin enabled|:count plugins enabled',
  217. +        'failed' => 'Failed to enable plugin(s)',
  218. +    ],
  219.      'smokeping:generate' => [
  220.          'args-nonsense' => 'Use one of --probes and --targets',
  221.          'config-insufficient' => 'In order to generate a smokeping configuration, you must have set "smokeping.probes", "fping", and "fping6" set in your configuration',
  222.  
  223. commit 670f964e9886591c1727b5e9130a044ad40929d1
  224. Author: Jellyfrog <Jellyfrog>
  225. Date:   Fri Jul 29 18:36:18 2022 +0200
  226.  
  227.     Validate: use "database version" instead of "mysql version" (#14158)
  228.    
  229.     * Validate: use "database version" instead of "mysql version"
  230.    
  231.     * wip
  232.    
  233.     * wip
  234.  
  235. diff --git a/LibreNMS/Poller.php b/LibreNMS/Poller.php
  236. index ef1be0ca9..2efb225d9 100644
  237. --- a/LibreNMS/Poller.php
  238. +++ b/LibreNMS/Poller.php
  239. @@ -43,7 +43,6 @@ use LibreNMS\Util\Debug;
  240.  use LibreNMS\Util\Dns;
  241.  use LibreNMS\Util\Git;
  242.  use LibreNMS\Util\StringHelpers;
  243. -use LibreNMS\Util\Version;
  244.  use Psr\Log\LoggerInterface;
  245.  use Throwable;
  246.  
  247. @@ -371,7 +370,7 @@ Commit SHA: %s
  248.  Commit Date: %s
  249.  DB Schema: %s
  250.  PHP: %s
  251. -MySQL: %s
  252. +Database: %s
  253.  RRDTool: %s
  254.  SNMP: %s
  255.  ==================================
  256. @@ -380,7 +379,7 @@ EOH,
  257.                  Git::localDate(),
  258.                  vsprintf('%s (%s)', $version->database()),
  259.                  phpversion(),
  260. -                Version::get()->databaseServer(),
  261. +                $version->databaseServer(),
  262.                  $version->rrdtool(),
  263.                  $version->netSnmp()
  264.              ));
  265. diff --git a/LibreNMS/Util/Stats.php b/LibreNMS/Util/Stats.php
  266. index a31c833ac..7559b7140 100644
  267. --- a/LibreNMS/Util/Stats.php
  268. +++ b/LibreNMS/Util/Stats.php
  269. @@ -140,7 +140,7 @@ class Stats
  270.              'vminfo'           => $this->selectTotal('vminfo', ['vm_type']),
  271.              'vmware'           => $this->selectTotal('vminfo'),
  272.              'vrfs'             => $this->selectTotal('vrfs'),
  273. -            'mysql_version'    => $this->selectStatic($version->databaseServer()),
  274. +            'database_version' => $this->selectStatic($version->databaseServer()),
  275.              'php_version'      => $this->selectStatic(phpversion()),
  276.              'python_version'   => $this->selectStatic($version->python()),
  277.              'rrdtool_version'  => $this->selectStatic($version->rrdtool()),
  278. diff --git a/LibreNMS/Util/Version.php b/LibreNMS/Util/Version.php
  279. index 2e0fc1ca2..decf6ff82 100644
  280. --- a/LibreNMS/Util/Version.php
  281. +++ b/LibreNMS/Util/Version.php
  282. @@ -122,7 +122,20 @@ class Version
  283.  
  284.      public function databaseServer(): string
  285.      {
  286. -        return Eloquent::isConnected() ? Arr::first(DB::selectOne('select version()')) : 'Not Connected';
  287. +        if (! Eloquent::isConnected()) {
  288. +            return 'Not Connected';
  289. +        }
  290. +
  291. +        switch (Eloquent::getDriver()) {
  292. +            case 'mysql':
  293. +                $ret = Arr::first(DB::selectOne('select version()'));
  294. +
  295. +                return (str_contains($ret, 'MariaDB') ? 'MariaDB ' : 'MySQL ') . $ret;
  296. +            case 'sqlite':
  297. +                return 'SQLite ' . Arr::first(DB::selectOne('select sqlite_version()'));
  298. +            default:
  299. +                return 'Unsupported: ' . Eloquent::getDriver();
  300. +        }
  301.      }
  302.  
  303.      public function database(): array
  304. diff --git a/LibreNMS/Validations/Database/CheckDatabaseServerVersion.php b/LibreNMS/Validations/Database/CheckDatabaseServerVersion.php
  305. index 72d05475e..1eb66af02 100644
  306. --- a/LibreNMS/Validations/Database/CheckDatabaseServerVersion.php
  307. +++ b/LibreNMS/Validations/Database/CheckDatabaseServerVersion.php
  308. @@ -39,22 +39,26 @@ class CheckDatabaseServerVersion implements Validation
  309.      public function validate(): ValidationResult
  310.      {
  311.          $version = Version::get()->databaseServer();
  312. -        $version = explode('-', $version);
  313. +        [$name, $version] = explode(' ', $version, 2);
  314. +        [$version] = explode('-', $version, 2);
  315.  
  316. -        if (isset($version[1]) && $version[1] == 'MariaDB') {
  317. -            if (version_compare($version[0], Database::MARIADB_MIN_VERSION, '&lt;=')) {
  318. -                return ValidationResult::fail(
  319. -                    trans('validation.validations.database.CheckDatabaseServerVersion.fail', ['server' => 'MariaDB', 'min' => Database::MARIADB_MIN_VERSION, 'date' => Database::MARIADB_MIN_VERSION_DATE]),
  320. -                    trans('validation.validations.database.CheckDatabaseServerVersion.fix', ['server' => 'MariaDB', 'suggested' => Database::MARIADB_RECOMMENDED_VERSION]),
  321. -                );
  322. -            }
  323. -        } else {
  324. -            if (version_compare($version[0], Database::MYSQL_MIN_VERSION, '&lt;=')) {
  325. -                return ValidationResult::fail(
  326. -                    trans('validation.validations.database.CheckDatabaseServerVersion.fail', ['server' => 'MySQL', 'min' => Database::MYSQL_MIN_VERSION, 'date' => Database::MYSQL_MIN_VERSION_DATE]),
  327. -                    trans('validation.validations.database.CheckDatabaseServerVersion.fix', ['server' => 'MySQL', 'suggested' => Database::MYSQL_RECOMMENDED_VERSION]),
  328. -                );
  329. -            }
  330. +        switch ($name) {
  331. +            case 'MariaDB':
  332. +                if (version_compare($version, Database::MARIADB_MIN_VERSION, '&lt;=')) {
  333. +                    return ValidationResult::fail(
  334. +                        trans('validation.validations.database.CheckDatabaseServerVersion.fail', ['server' => 'MariaDB', 'min' => Database::MARIADB_MIN_VERSION, 'date' => Database::MARIADB_MIN_VERSION_DATE]),
  335. +                        trans('validation.validations.database.CheckDatabaseServerVersion.fix', ['server' => 'MariaDB', 'suggested' => Database::MARIADB_RECOMMENDED_VERSION]),
  336. +                    );
  337. +                }
  338. +            break;
  339. +            case 'MySQL':
  340. +                if (version_compare($version, Database::MYSQL_MIN_VERSION, '&lt;=')) {
  341. +                    return ValidationResult::fail(
  342. +                        trans('validation.validations.database.CheckDatabaseServerVersion.fail', ['server' => 'MySQL', 'min' => Database::MYSQL_MIN_VERSION, 'date' => Database::MYSQL_MIN_VERSION_DATE]),
  343. +                        trans('validation.validations.database.CheckDatabaseServerVersion.fix', ['server' => 'MySQL', 'suggested' => Database::MYSQL_RECOMMENDED_VERSION]),
  344. +                    );
  345. +                }
  346. +            break;
  347.          }
  348.  
  349.          return ValidationResult::ok(trans('validation.validations.database.CheckDatabaseServerVersion.ok'));
  350. diff --git a/app/Http/Controllers/AboutController.php b/app/Http/Controllers/AboutController.php
  351. index 88a99bc44..9059720aa 100644
  352. --- a/app/Http/Controllers/AboutController.php
  353. +++ b/app/Http/Controllers/AboutController.php
  354. @@ -72,7 +72,7 @@ class AboutController extends Controller
  355.              'project_name' => Config::get('project_name'),
  356.  
  357.              'version_local' => $version->local(),
  358. -            'version_mysql' => $version->databaseServer(),
  359. +            'version_database' => $version->databaseServer(),
  360.              'version_php' => phpversion(),
  361.              'version_laravel' => App::VERSION(),
  362.              'version_python' => $version->python(),
  363. diff --git a/discovery.php b/discovery.php
  364. index 78c049f06..6e1e67dde 100755
  365. --- a/discovery.php
  366. +++ b/discovery.php
  367. @@ -72,7 +72,7 @@ Commit SHA: {$versions['local_sha']}
  368.  Commit Date: {$versions['local_date']}
  369.  DB Schema: {$versions['db_schema']}
  370.  PHP: {$versions['php_ver']}
  371. -MySQL: {$versions['mysql_ver']}
  372. +Database: {$versions['database_ver']}
  373.  RRDTool: {$versions['rrdtool_ver']}
  374.  SNMP: {$versions['netsnmp_ver']}
  375.  ==================================
  376. diff --git a/doc/API/System.md b/doc/API/System.md
  377. index b09bf14cf..786cdbf7a 100644
  378. --- a/doc/API/System.md
  379. +++ b/doc/API/System.md
  380. @@ -27,7 +27,7 @@ Output:
  381.              "local_branch": "master",
  382.              "db_schema": 249,
  383.              "php_ver": "7.2.2",
  384. -            "mysql_ver": "5.5.56-MariaDB",
  385. +            "database_ver": "MariaDB 5.5.56-MariaDB",
  386.              "rrdtool_ver": "1.4.8",
  387.              "netsnmp_ver": "NET-SNMP 5.7.2"
  388.          }
  389. diff --git a/includes/common.php b/includes/common.php
  390. index d2c98aedc..5bb22e1bd 100644
  391. --- a/includes/common.php
  392. +++ b/includes/common.php
  393. @@ -551,7 +551,7 @@ function version_info($remote = false)
  394.          'db_schema' => vsprintf('%s (%s)', $version->database()),
  395.          'php_ver' => phpversion(),
  396.          'python_ver' => $version->python(),
  397. -        'mysql_ver' => $version->databaseServer(),
  398. +        'database_ver' => $version->databaseServer(),
  399.          'rrdtool_ver' => $version->rrdtool(),
  400.          'netsnmp_ver' => $version->netSnmp(),
  401.      ];
  402. diff --git a/poller.php b/poller.php
  403. index 5ffbc6fb4..96a3db616 100755
  404. --- a/poller.php
  405. +++ b/poller.php
  406. @@ -107,7 +107,7 @@ Commit SHA: {$versions['local_sha']}
  407.  Commit Date: {$versions['local_date']}
  408.  DB Schema: {$versions['db_schema']}
  409.  PHP: {$versions['php_ver']}
  410. -MySQL: {$versions['mysql_ver']}
  411. +Database: {$versions['database_ver']}
  412.  RRDTool: {$versions['rrdtool_ver']}
  413.  SNMP: {$versions['netsnmp_ver']}
  414.  ==================================
  415. diff --git a/resources/views/about/index.blade.php b/resources/views/about/index.blade.php
  416. index 64b09e01d..4a7555c15 100644
  417. --- a/resources/views/about/index.blade.php
  418. +++ b/resources/views/about/index.blade.php
  419. @@ -47,8 +47,8 @@
  420.                      <td>{{ $version_python }}</td>
  421.                  </tr>
  422.                  <tr>
  423. -                    <td><b>{{ __('MySQL') }}</b></td>
  424. -                    <td>{{ $version_mysql }}</td>
  425. +                    <td><b>{{ __('Database') }}</b></td>
  426. +                    <td>{{ $version_database }}</td>
  427.                  </tr>
  428.                  <tr>
  429.                      <td><a href="https://laravel.com/"><b>{{ __('Laravel') }}</b></a></td>
  430. diff --git a/validate.php b/validate.php
  431. index 38d15d9a9..ceedc8e5b 100755
  432. --- a/validate.php
  433. +++ b/validate.php
  434. @@ -160,7 +160,7 @@ LibreNMS  | ${versions['local_ver']}
  435.  DB Schema | ${versions['db_schema']}
  436.  PHP       | ${versions['php_ver']}
  437.  Python    | ${versions['python_ver']}
  438. -MySQL     | ${versions['mysql_ver']}
  439. +Database  | ${versions['database_ver']}
  440.  RRDTool   | ${versions['rrdtool_ver']}
  441.  SNMP      | ${versions['netsnmp_ver']}
  442.  ====================================
  443.  
  444. commit 8508710e62ee47fed5d9231e5ef3867a7c624334
  445. Author: Tony Murray <murraytony>
  446. Date:   Fri Jul 29 08:53:41 2022 -0500
  447.  
  448.     Stats: Collect OS distro and LibreNMS version (#14138)
  449.    
  450.     * Stats: Collect OS distro and LibreNMS version
  451.    
  452.     Add os distro/version and LibreNMS version to stats collection.
  453.    
  454.     To view stats: https://stats.librenms.org
  455.    
  456.     * style/lint fixes
  457.    
  458.     * Put debug where it will work
  459.    
  460.     * One call sends int, which is ok
  461.  
  462. diff --git a/LibreNMS/Util/Stats.php b/LibreNMS/Util/Stats.php
  463. new file mode 100644
  464. index 000000000..a31c833ac
  465. --- /dev/null
  466. +++ b/LibreNMS/Util/Stats.php
  467. @@ -0,0 +1,210 @@
  468. +&lt;?php
  469. +/*
  470. + * Stats.php
  471. + *
  472. + * -Description-
  473. + *
  474. + * This program is free software: you can redistribute it and/or modify
  475. + * it under the terms of the GNU General Public License as published by
  476. + * the Free Software Foundation, either version 3 of the License, or
  477. + * (at your option) any later version.
  478. + *
  479. + * This program is distributed in the hope that it will be useful,
  480. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  481. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
  482. + * GNU General Public License for more details.
  483. + *
  484. + * You should have received a copy of the GNU General Public License
  485. + * along with this program.  If not, see <http>.
  486. + *
  487. + * @package    LibreNMS
  488. + * @link       http://librenms.org
  489. + * @copyright  2022 Tony Murray
  490. + * @author     Tony Murray <murraytony>
  491. + */
  492. +
  493. +namespace LibreNMS\Util;
  494. +
  495. +use App\Models\Callback;
  496. +use DB;
  497. +use Illuminate\Database\Query\Builder;
  498. +use Illuminate\Support\Collection;
  499. +use Illuminate\Support\Str;
  500. +
  501. +class Stats
  502. +{
  503. +    public static function submit(): void
  504. +    {
  505. +        $stats = new static;
  506. +
  507. +        if ($stats->isEnabled()) {
  508. +            $response = \Http::withOptions(['proxy' => Proxy::forGuzzle()])
  509. +                ->asForm()
  510. +                ->post(\LibreNMS\Config::get('callback_post'), [
  511. +                    'data' => json_encode($stats->collectData()),
  512. +                ]);
  513. +        }
  514. +    }
  515. +
  516. +    public function isEnabled(): bool
  517. +    {
  518. +        $enabled = Callback::get('enabled');
  519. +
  520. +        if ($enabled == 2) {
  521. +            $this->clearStats();
  522. +
  523. +            return false;
  524. +        }
  525. +
  526. +        return $enabled == 1;
  527. +    }
  528. +
  529. +    public function clearStats(): void
  530. +    {
  531. +        $uuid = Callback::get('uuid');
  532. +
  533. +        $response = \Http::withOptions(['proxy' => Proxy::forGuzzle()])
  534. +            ->asForm()
  535. +            ->post(\LibreNMS\Config::get('callback_clear'), ['uuid' => $uuid]);
  536. +
  537. +        if ($response->successful()) {
  538. +            Callback::where('name', 'uuid')->delete();
  539. +            Callback::set('enabled', 0);
  540. +        }
  541. +    }
  542. +
  543. +    private function collectData(): array
  544. +    {
  545. +        return [
  546. +            'uuid' => $this->getUuid(),
  547. +            'data' => $this->collectStats(),
  548. +            'info' => $this->collectDeviceInfo(),
  549. +        ];
  550. +    }
  551. +
  552. +    private function getUuid(): string
  553. +    {
  554. +        $uuid = Callback::get('uuid');
  555. +
  556. +        if (! $uuid) {
  557. +            $uuid = Str::uuid();
  558. +            Callback::set('uuid', $uuid);
  559. +        }
  560. +
  561. +        return $uuid;
  562. +    }
  563. +
  564. +    private function collectStats(): array
  565. +    {
  566. +        $version = Version::get();
  567. +
  568. +        return [
  569. +            'alert_rules'      => $this->selectTotal(DB::table('alert_rules')->where('disabled', 0), ['severity']),
  570. +            'alert_templates'  => $this->selectTotal('alert_templates'),
  571. +            'api_tokens'       => $this->selectTotal(DB::table('api_tokens')->where('disabled', 0)),
  572. +            'applications'     => $this->selectTotal('applications', ['app_type']),
  573. +            'bgppeer_state'    => $this->selectTotal('bgpPeers', ['bgpPeerState']),
  574. +            'bgppeer_status'   => $this->selectTotal('bgpPeers', ['bgpPeerAdminStatus']),
  575. +            'bills'            => $this->selectTotal('bills', ['bill_type']),
  576. +            'cef'              => $this->selectTotal('cef_switching'),
  577. +            'cisco_asa'        => $this->selectTotal(DB::table('ciscoASA')->where('disabled', 0), ['oid']),
  578. +            'mempool'          => $this->selectTotal('mempools', ['mempool_descr']),
  579. +            'dbschema'         => $this->selectStatic(DB::table('migrations')->count()),
  580. +            'snmp_version'     => $this->selectTotal('devices', ['snmpver']),
  581. +            'os'               => $this->selectTotal('devices', ['os']),
  582. +            'type'             => $this->selectTotal('devices', ['type']),
  583. +            'hardware'         => $this->selectTotal('devices', ['hardware']),
  584. +            'ipsec'            => $this->selectTotal('ipsec_tunnels'),
  585. +            'ipv4_addresses'   => $this->selectTotal('ipv4_addresses'),
  586. +            'ipv4_macaddress'  => $this->selectTotal('ipv4_mac'),
  587. +            'ipv4_networks'    => $this->selectTotal('ipv4_networks'),
  588. +            'ipv6_addresses'   => $this->selectTotal('ipv6_addresses'),
  589. +            'ipv6_networks'    => $this->selectTotal('ipv6_networks'),
  590. +            'xdp'              => $this->selectTotal('links', ['protocol']),
  591. +            'ospf'             => $this->selectTotal('ospf_instances', ['ospfVersionNumber']),
  592. +            'ospf_links'       => $this->selectTotal('ospf_ports', ['ospfIfType']),
  593. +            'arch'             => $this->selectTotal('packages', ['arch']),
  594. +            'pollers'          => $this->selectTotal('pollers'),
  595. +            'port_type'        => $this->selectTotal('ports', ['ifType']),
  596. +            'port_ifspeed'     => DB::table('ports')->select([DB::raw('COUNT(*) AS `total`'), DB::raw('ROUND(`ifSpeed`/1000/1000) as ifSpeed')])->groupBy(['ifSpeed'])->get(),
  597. +            'port_vlans'       => $this->selectTotal('ports_vlans', ['state']),
  598. +            'processes'        => $this->selectTotal('processes'),
  599. +            'processors'       => $this->selectTotal('processors', ['processor_type']),
  600. +            'pseudowires'      => $this->selectTotal('pseudowires'),
  601. +            'sensors'          => $this->selectTotal('sensors', ['sensor_class']),
  602. +            'sla'              => $this->selectTotal('slas', ['rtt_type']),
  603. +            'wireless'         => $this->selectTotal('wireless_sensors', ['sensor_class']),
  604. +            'storage'          => $this->selectTotal('storage', ['storage_type']),
  605. +            'toner'            => $this->selectTotal('printer_supplies', ['supply_type']),
  606. +            'vlans'            => $this->selectTotal('vlans', ['vlan_type']),
  607. +            'vminfo'           => $this->selectTotal('vminfo', ['vm_type']),
  608. +            'vmware'           => $this->selectTotal('vminfo'),
  609. +            'vrfs'             => $this->selectTotal('vrfs'),
  610. +            'mysql_version'    => $this->selectStatic($version->databaseServer()),
  611. +            'php_version'      => $this->selectStatic(phpversion()),
  612. +            'python_version'   => $this->selectStatic($version->python()),
  613. +            'rrdtool_version'  => $this->selectStatic($version->rrdtool()),
  614. +            'netsnmp_version'  => $this->selectStatic($version->netSnmp()),
  615. +            'os_version'       => $this->selectStatic($version->os()),
  616. +            'librenms_release' => $this->selectStatic($version->release(), 'release'),
  617. +        ];
  618. +    }
  619. +
  620. +    private function collectDeviceInfo(): Collection
  621. +    {
  622. +        $device_info = DB::table('devices')
  623. +            ->select([DB::raw('COUNT(*) AS `count`'), 'os', 'sysDescr', 'sysObjectID'])
  624. +            ->whereNotNull(['sysDescr', 'sysObjectID'])
  625. +            ->groupBy(['os', 'sysDescr', 'sysObjectID'])
  626. +            ->get();
  627. +
  628. +        // sanitize sysDescr
  629. +        return $device_info->map(function ($entry) {
  630. +            // remove hostnames from linux, macosx, and SunOS
  631. +            $entry->sysDescr = preg_replace_callback('/^(Linux |Darwin |FreeBSD |SunOS )[A-Za-z0-9._\-]+ ([0-9.]{3,9})/', function ($matches) {
  632. +                return $matches[1] . 'hostname ' . $matches[2];
  633. +            }, $entry->sysDescr);
  634. +
  635. +            // wipe serial numbers, preserve the format
  636. +            $sn_patterns = ['/[A-Z]/', '/[a-z]/', '/[0-9]/'];
  637. +            $sn_replacements = ['A', 'a', '0'];
  638. +            $entry->sysDescr = preg_replace_callback(
  639. +                '/((s\/?n|serial num(ber)?)[:=]? ?)([a-z0-9.\-]{4,16})/i',
  640. +                function ($matches) use ($sn_patterns, $sn_replacements) {
  641. +                    return $matches[1] . preg_replace($sn_patterns, $sn_replacements, $matches[4]);
  642. +                },
  643. +                $entry->sysDescr
  644. +            );
  645. +
  646. +            return $entry;
  647. +        });
  648. +    }
  649. +
  650. +    /**
  651. +     * @param  Builder|string  $table
  652. +     * @param  array  $groups
  653. +     * @return \Illuminate\Support\Collection
  654. +     */
  655. +    private function selectTotal($table, array $groups = []): Collection
  656. +    {
  657. +        $query = $table instanceof Builder ? $table : DB::table($table);
  658. +
  659. +        if (! empty($groups)) {
  660. +            $query->groupBy($groups);
  661. +        }
  662. +
  663. +        return $query
  664. +            ->select(array_merge([DB::raw('COUNT(*) AS `total`')], $groups))
  665. +            ->get();
  666. +    }
  667. +
  668. +    /**
  669. +     * @param  string|int|float  $value
  670. +     * @param  string  $name
  671. +     * @return array[]
  672. +     */
  673. +    private function selectStatic($value, string $name = 'version'): array
  674. +    {
  675. +        return [['total' => 1, $name => $value]];
  676. +    }
  677. +}
  678. diff --git a/LibreNMS/Util/Version.php b/LibreNMS/Util/Version.php
  679. index d71f20228..2e0fc1ca2 100644
  680. --- a/LibreNMS/Util/Version.php
  681. +++ b/LibreNMS/Util/Version.php
  682. @@ -53,6 +53,11 @@ class Version
  683.          return new static;
  684.      }
  685.  
  686. +    public function release(): string
  687. +    {
  688. +        return Config::get('update_channel') == 'master' ? 'master' : self::VERSION;
  689. +    }
  690. +
  691.      public function local(): string
  692.      {
  693.          if ($this->is_git_install && $version = $this->fromGit()) {
  694. @@ -186,4 +191,36 @@ class Version
  695.  
  696.          return $matches[0] ?? '';
  697.      }
  698. +
  699. +    /**
  700. +     * The OS/distribution and version
  701. +     */
  702. +    public function os(): string
  703. +    {
  704. +        $info = [];
  705. +
  706. +        // find release file
  707. +        if (file_exists('/etc/os-release')) {
  708. +            $info = @parse_ini_file&#40;'/etc/os-release'&#41;;
  709. +        } else {
  710. +            foreach (glob('/etc/*-release') as $file) {
  711. +                $content = file_get_contents&#40;$file&#41;;
  712. +                // normal os release style
  713. +                $info = @parse_ini_string($content);
  714. +                if (! empty($info)) {
  715. +                    break;
  716. +                }
  717. +
  718. +                // just a string of text
  719. +                if (substr_count($content, PHP_EOL) &lt;= 1) {
  720. +                    $info = ['NAME' => trim(str_replace('release ', '', $content))];
  721. +                    break;
  722. +                }
  723. +            }
  724. +        }
  725. +
  726. +        $only = array_intersect_key($info, ['NAME' => true, 'VERSION_ID' => true]);
  727. +
  728. +        return implode(' ', $only);
  729. +    }
  730.  }
  731. diff --git a/daily.php b/daily.php
  732. index 98532e5e9..1909876fa 100644
  733. --- a/daily.php
  734. +++ b/daily.php
  735. @@ -16,11 +16,6 @@ use LibreNMS\Validations\Php;
  736.  
  737.  $options = getopt('df:o:t:r:');
  738.  
  739. -if (isset($options['d'])) {
  740. -    echo "DEBUG\n";
  741. -    Debug::set();
  742. -}
  743. -
  744.  /**
  745.   * Scripts without dependencies
  746.   */
  747. @@ -46,6 +41,11 @@ $init_modules = ['alerts'];
  748.  require __DIR__ . '/includes/init.php';
  749.  include_once __DIR__ . '/includes/notifications.php';
  750.  
  751. +if (isset($options['d'])) {
  752. +    echo "DEBUG\n";
  753. +    Debug::set();
  754. +}
  755. +
  756.  if ($options['f'] === 'update') {
  757.      if (! Config::get('update')) {
  758.          exit(0);
  759. @@ -126,7 +126,7 @@ if ($options['f'] === 'authlog') {
  760.  }
  761.  
  762.  if ($options['f'] === 'callback') {
  763. -    include_once 'includes/callback.php';
  764. +    \LibreNMS\Util\Stats::submit();
  765.  }
  766.  
  767.  if ($options['f'] === 'device_perf') {
  768. diff --git a/includes/callback.php b/includes/callback.php
  769. deleted file mode 100644
  770. index 8b9b31799..000000000
  771. --- a/includes/callback.php
  772. +++ /dev/null
  773. @@ -1,138 +0,0 @@
  774. -&lt;?php
  775. -
  776. -/*
  777. - * LibreNMS
  778. - *
  779. - * Copyright (c) 2014 Neil Lathwood <https>
  780. - *
  781. - * This program is free software: you can redistribute it and/or modify it
  782. - * under the terms of the GNU General Public License as published by the
  783. - * Free Software Foundation, either version 3 of the License, or (at your
  784. - * option) any later version.  Please see LICENSE.txt at the top level of
  785. - * the source code distribution for details.
  786. - */
  787. -
  788. -$enabled = dbFetchCell("SELECT `value` FROM `callback` WHERE `name` = 'enabled'");
  789. -if ($enabled == 1) {
  790. -    if (dbFetchCell("SELECT `value` FROM `callback` WHERE `name` = 'uuid'") == '') {
  791. -        dbInsert(['name' => 'uuid', 'value' => guidv4(openssl_random_pseudo_bytes(16))], 'callback');
  792. -    }
  793. -
  794. -    $uuid = dbFetchCell("SELECT `value` FROM `callback` WHERE `name` = 'uuid'");
  795. -
  796. -    $version = version_info();
  797. -    $queries = [
  798. -        'alert_rules'     => 'SELECT COUNT(*) AS `total`,`severity` FROM `alert_rules` WHERE `disabled`=0 GROUP BY `severity`',
  799. -        'alert_templates' => 'SELECT COUNT(*) AS `total` FROM `alert_templates`',
  800. -        'api_tokens'      => 'SELECT COUNT(*) AS `total` FROM `api_tokens` WHERE `disabled`=0',
  801. -        'applications'    => 'SELECT COUNT(*) AS `total`,`app_type` FROM `applications` GROUP BY `app_type`',
  802. -        'bgppeer_state'   => 'SELECT COUNT(*) AS `total`,`bgpPeerState` FROM `bgpPeers` GROUP BY `bgpPeerState`',
  803. -        'bgppeer_status'  => 'SELECT COUNT(*) AS `total`,`bgpPeerAdminStatus` FROM `bgpPeers` GROUP BY `bgpPeerAdminStatus`',
  804. -        'bills'           => 'SELECT COUNT(*) AS `total`,`bill_type` FROM `bills` GROUP BY `bill_type`',
  805. -        'cef'             => 'SELECT COUNT(*) AS `total` FROM `cef_switching`',
  806. -        'cisco_asa'       => 'SELECT COUNT(*) AS `total`,`oid` FROM `ciscoASA` WHERE `disabled` = 0 GROUP BY `oid`',
  807. -        'mempool'         => 'SELECT COUNT(*) AS `total`,`mempool_descr` FROM `mempools` GROUP BY `mempool_descr`',
  808. -        'dbschema'        => 'SELECT COUNT(*) AS `total`, COUNT(*) AS `version` FROM `migrations`',
  809. -        'snmp_version'    => 'SELECT COUNT(*) AS `total`,`snmpver` FROM `devices` GROUP BY `snmpver`',
  810. -        'os'              => 'SELECT COUNT(*) AS `total`,`os` FROM `devices` GROUP BY `os`',
  811. -        'type'            => 'SELECT COUNT(*) AS `total`,`type` FROM `devices` GROUP BY `type`',
  812. -        'hardware'        => 'SELECT COUNT(*) AS `total`, `hardware` FROM `devices` GROUP BY `hardware`',
  813. -        'ipsec'           => 'SELECT COUNT(*) AS `total` FROM `ipsec_tunnels`',
  814. -        'ipv4_addresses'  => 'SELECT COUNT(*) AS `total` FROM `ipv4_addresses`',
  815. -        'ipv4_macaddress' => 'SELECT COUNT(*) AS `total` FROM ipv4_mac',
  816. -        'ipv4_networks'   => 'SELECT COUNT(*) AS `total` FROM ipv4_networks',
  817. -        'ipv6_addresses'  => 'SELECT COUNT(*) AS `total` FROM `ipv6_addresses`',
  818. -        'ipv6_networks'   => 'SELECT COUNT(*) AS `total` FROM `ipv6_networks`',
  819. -        'xdp'             => 'SELECT COUNT(*) AS `total`,`protocol` FROM `links` GROUP BY `protocol`',
  820. -        'ospf'            => 'SELECT COUNT(*) AS `total`,`ospfVersionNumber` FROM `ospf_instances` GROUP BY `ospfVersionNumber`',
  821. -        'ospf_links'      => 'SELECT COUNT(*) AS `total`,`ospfIfType` FROM `ospf_ports` GROUP BY `ospfIfType`',
  822. -        'arch'            => 'SELECT COUNT(*) AS `total`,`arch` FROM `packages` GROUP BY `arch`',
  823. -        'pollers'         => 'SELECT COUNT(*) AS `total` FROM `pollers`',
  824. -        'port_type'       => 'SELECT COUNT(*) AS `total`,`ifType` FROM `ports` GROUP BY `ifType`',
  825. -        'port_ifspeed'    => 'SELECT COUNT(*) AS `total`,ROUND(`ifSpeed`/1000/1000) FROM `ports` GROUP BY `ifSpeed`',
  826. -        'port_vlans'      => 'SELECT COUNT(*) AS `total`,`state` FROM `ports_vlans` GROUP BY `state`',
  827. -        'processes'       => 'SELECT COUNT(*) AS `total` FROM `processes`',
  828. -        'processors'      => 'SELECT COUNT(*) AS `total`,`processor_type` FROM `processors` GROUP BY `processor_type`',
  829. -        'pseudowires'     => 'SELECT COUNT(*) AS `total` FROM `pseudowires`',
  830. -        'sensors'         => 'SELECT COUNT(*) AS `total`,`sensor_class` FROM `sensors` GROUP BY `sensor_class`',
  831. -        'sla'             => 'SELECT COUNT(*) AS `total`,`rtt_type` FROM `slas` GROUP BY `rtt_type`',
  832. -        'wireless'        => 'SELECT COUNT(*) AS `total`,`sensor_class` FROM `wireless_sensors` GROUP BY `sensor_class`',
  833. -        'storage'         => 'SELECT COUNT(*) AS `total`,`storage_type` FROM `storage` GROUP BY `storage_type`',
  834. -        'toner'           => 'SELECT COUNT(*) AS `total`,`supply_type` FROM `printer_supplies` GROUP BY `supply_type`',
  835. -        'vlans'           => 'SELECT COUNT(*) AS `total`,`vlan_type` FROM `vlans` GROUP BY `vlan_type`',
  836. -        'vminfo'          => 'SELECT COUNT(*) AS `total`,`vm_type` FROM `vminfo` GROUP BY `vm_type`',
  837. -        'vmware'          => 'SELECT COUNT(*) AS `total` FROM `vminfo`',
  838. -        'vrfs'            => 'SELECT COUNT(*) AS `total` FROM `vrfs`',
  839. -        'mysql_version'   => 'SELECT 1 AS `total`, @@version AS `version`',
  840. -    ];
  841. -
  842. -    foreach ($queries as $name => $query) {
  843. -        $data = dbFetchRows($query);
  844. -        $response[$name] = $data;
  845. -    }
  846. -    $response['php_version'][] = ['total' => 1, 'version' => $version['php_ver']];
  847. -    $response['python_version'][] = ['total' => 1, 'version' => $version['python_ver']];
  848. -    $response['rrdtool_version'][] = ['total' => 1, 'version' => $version['rrdtool_ver']];
  849. -    $response['netsnmp_version'][] = ['total' => 1, 'version' => $version['netsnmp_ver']];
  850. -
  851. -    // collect sysDescr and sysObjectID for submission
  852. -    $device_info = dbFetchRows('SELECT COUNT(*) AS `count`,`os`, `sysDescr`, `sysObjectID` FROM `devices`
  853. -        WHERE `sysDescr` IS NOT NULL AND `sysObjectID` IS NOT NULL GROUP BY `os`, `sysDescr`, `sysObjectID`');
  854. -
  855. -    // sanitize sysDescr
  856. -    $device_info = array_map(function ($entry) {
  857. -        // remove hostnames from linux, macosx, and SunOS
  858. -        $entry['sysDescr'] = preg_replace_callback('/^(Linux |Darwin |FreeBSD |SunOS )[A-Za-z0-9._\-]+ ([0-9.]{3,9})/', function ($matches) {
  859. -            return $matches[1] . 'hostname ' . $matches[2];
  860. -        }, $entry['sysDescr']);
  861. -
  862. -        // wipe serial numbers, preserve the format
  863. -        $sn_patterns = ['/[A-Z]/', '/[a-z]/', '/[0-9]/'];
  864. -        $sn_replacements = ['A', 'a', '0'];
  865. -        $entry['sysDescr'] = preg_replace_callback(
  866. -            '/((s\/?n|serial num(ber)?)[:=]? ?)([a-z0-9.\-]{4,16})/i',
  867. -            function ($matches) use ($sn_patterns, $sn_replacements) {
  868. -                return $matches[1] . preg_replace($sn_patterns, $sn_replacements, $matches[4]);
  869. -            },
  870. -            $entry['sysDescr']
  871. -        );
  872. -
  873. -        return $entry;
  874. -    }, $device_info);
  875. -
  876. -    $output = [
  877. -        'uuid' => $uuid,
  878. -        'data' => $response,
  879. -        'info' => $device_info,
  880. -    ];
  881. -    $data = json_encode($output);
  882. -    $submit = ['data' => $data];
  883. -
  884. -    $fields = '';
  885. -    foreach ($submit as $key => $value) {
  886. -        $fields .= $key . '=' . $value . '&';
  887. -    }
  888. -
  889. -    rtrim($fields, '&');
  890. -
  891. -    $post = curl_init();
  892. -    set_curl_proxy($post);
  893. -    curl_setopt($post, CURLOPT_URL, \LibreNMS\Config::get('callback_post'));
  894. -    curl_setopt($post, CURLOPT_POST, count($submit));
  895. -    curl_setopt($post, CURLOPT_POSTFIELDS, $fields);
  896. -    curl_setopt($post, CURLOPT_RETURNTRANSFER, 1);
  897. -    $result = curl_exec&#40;$post&#41;;
  898. -} elseif ($enabled == 2) {
  899. -    $uuid = dbFetchCell("SELECT `value` FROM `callback` WHERE `name` = 'uuid'");
  900. -    $fields = "uuid=$uuid";
  901. -
  902. -    $clear = curl_init();
  903. -    set_curl_proxy($clear);
  904. -    curl_setopt($clear, CURLOPT_URL, \LibreNMS\Config::get('callback_clear'));
  905. -    curl_setopt($clear, CURLOPT_POST, count($clear));
  906. -    curl_setopt($clear, CURLOPT_POSTFIELDS, $fields);
  907. -    curl_setopt($clear, CURLOPT_RETURNTRANSFER, 1);
  908. -    $result = curl_exec&#40;$clear&#41;;
  909. -    dbDelete('callback', '`name`="uuid"', []);
  910. -    dbUpdate(['value' => '0'], 'callback', '`name` = "enabled"', []);
  911. -}
  912.  
  913. commit a0e263295d4a88a31941486de1d3f654055cdc10
  914. Author: Félix Bouynot <felixbouynot>
  915. Date:   Fri Jul 29 15:48:49 2022 +0200
  916.  
  917.     Update php installation instruction for CentOS 8 to reflect the minimum php version now being 8.1 (#14159)
  918.  
  919. diff --git a/doc/Installation/Install-LibreNMS.md b/doc/Installation/Install-LibreNMS.md
  920. index a7b9d2d47..005506dec 100644
  921. --- a/doc/Installation/Install-LibreNMS.md
  922. +++ b/doc/Installation/Install-LibreNMS.md
  923. @@ -38,16 +38,18 @@ Connect to the server command line and follow the instructions below.
  924.      === "NGINX"
  925.          ```
  926.          dnf -y install epel-release
  927. +        dnf -y install dnf-utils http://rpms.remirepo.net/enterprise/remi-release-8.rpm
  928.          dnf module reset php
  929. -        dnf module enable php:7.3
  930. +        dnf module enable php:8.1
  931.          dnf install bash-completion cronie fping git ImageMagick mariadb-server mtr net-snmp net-snmp-utils nginx nmap php-fpm php-cli php-common php-curl php-gd php-gmp php-json php-mbstring php-process php-snmp php-xml php-zip php-mysqlnd python3 python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
  932.          ```
  933.  
  934.      === "Apache"
  935.          ```
  936.          dnf -y install epel-release
  937. +        dnf -y install dnf-utils http://rpms.remirepo.net/enterprise/remi-release-8.rpm
  938.          dnf module reset php
  939. -        dnf module enable php:7.3
  940. +        dnf module enable php:8.1
  941.          dnf install bash-completion cronie fping git httpd ImageMagick mariadb-server mtr net-snmp net-snmp-utils nmap php-fpm php-cli php-common php-curl php-gd php-gmp php-json php-mbstring php-process php-snmp php-xml php-zip php-mysqlnd python3 python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
  942.          ```
  943.  
  944.  
  945. commit 6ebcde3c04d2acadfe3f13b645fcd14da1db6898
  946. Author: Jellyfrog <Jellyfrog>
  947. Date:   Fri Jul 29 05:09:09 2022 +0200
  948.  
  949.     Prepare for PHP 8.1 (#14156)
  950.  
  951. diff --git a/LibreNMS/Validations/Php.php b/LibreNMS/Validations/Php.php
  952. index aa2fae775..560cfb605 100644
  953. --- a/LibreNMS/Validations/Php.php
  954. +++ b/LibreNMS/Validations/Php.php
  955. @@ -30,9 +30,9 @@ use LibreNMS\Validator;
  956.  
  957.  class Php extends BaseValidation
  958.  {
  959. -    const PHP_MIN_VERSION = '7.3';
  960. -    const PHP_MIN_VERSION_DATE = 'November, 2020';
  961. -    const PHP_RECOMMENDED_VERSION = '8.0';
  962. +    const PHP_MIN_VERSION = '8.1';
  963. +    const PHP_MIN_VERSION_DATE = 'September, 2022';
  964. +    const PHP_RECOMMENDED_VERSION = '8.1';
  965.  
  966.      /**
  967.       * Validate this module.
  968.  
  969. commit 970abb9589f192f655823ea0407a22ff1062cfeb
  970. Merge: 069741141 d248e6561
  971. Author: Robert373 <R373>
  972. Date:   Fri Jul 29 00:15:06 2022 +0200
  973.  
  974.     Merge branch 'master' of https://github.com/librenms/librenms
  975.  
  976. commit d248e6561fcd8965839c5834d7f440ed0cb2a54b
  977. Author: rhinoau <78184917>
  978. Date:   Fri Jul 29 00:38:46 2022 +0800
  979.  
  980.     Standardize device and device group maintenance API (#14153)
  981.    
  982.     * Standardise device and devicegroup maintenance API
  983.    
  984.     * styleci fixes
  985.  
  986. diff --git a/doc/API/DeviceGroups.md b/doc/API/DeviceGroups.md
  987. index 545950457..95a659378 100644
  988. --- a/doc/API/DeviceGroups.md
  989. +++ b/doc/API/DeviceGroups.md
  990. @@ -150,15 +150,28 @@ Route: `/api/v0/devicesgroups/:name/maintenance`
  991.  
  992.  Input (JSON):
  993.  
  994. -- title: Some title for the Maintenance
  995. -- notes: Some description for the Maintenance
  996. -- start: Start time of Maintenance in format H:m
  997. -- duration: Duration of Maintenance in format H:m
  998. +- `title`: *optional* - Some title for the Maintenance  
  999. +  Will be replaced with device group name if omitted
  1000. +- `notes`: *optional* - Some description for the Maintenance
  1001. +- `start`: *optional* - start time of Maintenance in full format `Y-m-d H:i:00`  
  1002. +  eg: 2022-08-01 22:45:00  
  1003. +  Current system time `now()` will be used if omitted
  1004. +- `duration`: *required* - Duration of Maintenance in format `H:i` / `Hrs:Mins`  
  1005. +  eg: 02:00
  1006.  
  1007. -Example:
  1008. +Example with start time:
  1009.  
  1010.  ```curl
  1011. -curl -X POST -d '{"title":"Device group Maintenance","notes":"A 2 hour Maintenance triggered via API","start":"04:30","duration":"2:00"}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/localhost/maintenance
  1012. +curl -H 'X-Auth-Token: YOURAPITOKENHERE' \
  1013. +  -X POST https://librenms.org/api/v0/devicegroups/Cisco switches/maintenance/ \
  1014. +  --data-raw '
  1015. +{
  1016. + "title":"Device group Maintenance",
  1017. +  "notes":"A 2 hour Maintenance triggered via API with start time",
  1018. +  "start":"2022-08-01 08:00:00",
  1019. +  "duration":"2:00"
  1020. +}
  1021. +'
  1022.  ```
  1023.  
  1024.  Output:
  1025. @@ -166,6 +179,30 @@ Output:
  1026.  ```json
  1027.  {
  1028.      "status": "ok",
  1029. -    "message": "Device group Cisco switches (2) will begin maintenance mode at 5:00 for 2:00 h"
  1030. +    "message": "Device group Cisco switches (2) will begin maintenance mode at 2022-08-01 22:45:00 for 2:00h"
  1031.  }
  1032.  ```
  1033. +
  1034. +Example with no start time:
  1035. +
  1036. +```curl
  1037. +curl -H 'X-Auth-Token: YOURAPITOKENHERE' \
  1038. +  -X POST https://librenms.org/api/v0/devicegroups/Cisco switches/maintenance/ \
  1039. +  --data-raw '
  1040. +{
  1041. + "title":"Device group Maintenance",
  1042. +  "notes":"A 2 hour Maintenance triggered via API with no start time",
  1043. +  "duration":"2:00"
  1044. +}
  1045. +'
  1046. +```
  1047. +
  1048. +Output:
  1049. +
  1050. +```json
  1051. +{
  1052. +    "status": "ok",
  1053. +    "message": "Device group Cisco switches (2) moved into maintenance mode for 2:00h"
  1054. +}
  1055. +```
  1056. +
  1057. diff --git a/doc/API/Devices.md b/doc/API/Devices.md
  1058. index e8cb2cab5..ead46d37f 100644
  1059. --- a/doc/API/Devices.md
  1060. +++ b/doc/API/Devices.md
  1061. @@ -1109,13 +1109,50 @@ Route: `/api/v0/devices/:hostname/maintenance`
  1062.  
  1063.  Input (JSON):
  1064.  
  1065. -- notes: Some description for the Maintenance
  1066. -- duration: Duration of Maintenance in format H:m
  1067. +- `title`: *optional* -  Some title for the Maintenance  
  1068. +  Will be replaced with hostname if omitted
  1069. +- `notes`: *optional* -  Some description for the Maintenance  
  1070. +  Will also be added to device notes if user prefs "Add schedule notes to devices notes" is set
  1071. +- `start`: *optional* - start time of Maintenance in full format `Y-m-d H:i:00`  
  1072. +  eg: 2022-08-01 22:45:00  
  1073. +  Current system time `now()` will be used if omitted
  1074. +- `duration`: *required* - Duration of Maintenance in format `H:i` / `Hrs:Mins`  
  1075. +  eg: 02:00
  1076. +
  1077. +Example with start time:
  1078.  
  1079. -Example:
  1080. +```curl
  1081. +curl -H 'X-Auth-Token: YOURAPITOKENHERE' \
  1082. +  -X POST https://librenms.org/api/v0/devices/localhost/maintenance/ \
  1083. +  --data-raw '
  1084. + "title":"Device Maintenance",
  1085. +  "notes":"A 2 hour Maintenance triggered via API with start time",
  1086. +  "start":"2022-08-01 08:00:00",
  1087. +  "duration":"2:00"
  1088. +}
  1089. +'
  1090. +```
  1091. +
  1092. +Output:
  1093. +
  1094. +```json
  1095. +{
  1096. +    "status": "ok",
  1097. +    "message": "Device localhost (1) will begin maintenance mode at 2022-08-01 22:45:00 for 2:00h"
  1098. +}
  1099. +```
  1100. +
  1101. +Example with no start time:
  1102.  
  1103.  ```curl
  1104. -curl -X POST -d '{"notes":"A 2 hour Maintenance triggered via API","duration":"2:00"}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/localhost/maintenance
  1105. +curl -H 'X-Auth-Token: YOURAPITOKENHERE' \
  1106. +  -X POST https://librenms.org/api/v0/devices/localhost/maintenance/ \
  1107. +  --data-raw '
  1108. + "title":"Device Maintenance",
  1109. +  "notes":"A 2 hour Maintenance triggered via API with no start time",
  1110. +  "duration":"2:00"
  1111. +}
  1112. +'
  1113.  ```
  1114.  
  1115.  Output:
  1116. @@ -1123,10 +1160,11 @@ Output:
  1117.  ```json
  1118.  {
  1119.      "status": "ok",
  1120. -    "message": "Device localhost.localdomain (57) moved into maintenance mode for 2:00 h"
  1121. +    "message": "Device localhost (1) moved into maintenance mode for 2:00h"
  1122.  }
  1123.  ```
  1124.  
  1125. +
  1126.  ### `add_device`
  1127.  
  1128.  Add a new device.  Most fields are optional. You may omit snmp
  1129. diff --git a/includes/html/api_functions.inc.php b/includes/html/api_functions.inc.php
  1130. index 702994370..2e6e78265 100644
  1131. --- a/includes/html/api_functions.inc.php
  1132. +++ b/includes/html/api_functions.inc.php
  1133. @@ -457,28 +457,35 @@ function maintenance_device(Illuminate\Http\Request $request)
  1134.          return api_error(400, 'No information has been provided to set this device into maintenance');
  1135.      }
  1136.  
  1137. -    // This will add a device using the data passed encoded with json
  1138.      $hostname = $request->route('hostname');
  1139.  
  1140.      // use hostname as device_id if it's all digits
  1141. -    $device = ctype_digit($hostname) ? DeviceCache::get($hostname) : DeviceCache::getByHostname($hostname);
  1142. +    $device = ctype_digit($hostname) ? Device::find($hostname) : Device::findByHostname($hostname);
  1143.  
  1144. -    if (! $device) {
  1145. -        return api_error(404, "Device $hostname does not exist");
  1146. +    if (is_null($device)) {
  1147. +        return api_error(404, "Device $hostname not found");
  1148. +    }
  1149. +
  1150. +    if (! $request->json('duration')) {
  1151. +        return api_error(400, 'Duration not provided');
  1152.      }
  1153.  
  1154.      $notes = $request->json('notes');
  1155. +    $title = $request->json('title') ?? $device->displayName();
  1156.      $alert_schedule = new \App\Models\AlertSchedule([
  1157. -        'title' => $device->displayName(),
  1158. +        'title' => $title,
  1159.          'notes' => $notes,
  1160.          'recurring' => 0,
  1161. -        'start' => date('Y-m-d H:i:s'),
  1162.      ]);
  1163.  
  1164. +    $start = $request->json('start') ?? \Carbon\Carbon::now()->format('Y-m-d H:i:00');
  1165. +    $alert_schedule->start = $start;
  1166. +
  1167.      $duration = $request->json('duration');
  1168. +
  1169.      if (Str::contains($duration, ':')) {
  1170.          [$duration_hour, $duration_min] = explode(':', $duration);
  1171. -        $alert_schedule->end = \Carbon\Carbon::now()
  1172. +        $alert_schedule->end = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $start)
  1173.              ->addHours($duration_hour)->addMinutes($duration_min)
  1174.              ->format('Y-m-d H:i:00');
  1175.      }
  1176. @@ -491,7 +498,11 @@ function maintenance_device(Illuminate\Http\Request $request)
  1177.          $device->save();
  1178.      }
  1179.  
  1180. -    return api_success_noresult(201, "Device {$device->hostname} ({$device->device_id}) moved into maintenance mode" . ($duration ? " for {$duration}h" : ''));
  1181. +    if ($request->json('start')) {
  1182. +        return api_success_noresult(201, "Device {$device->hostname} ({$device->device_id}) will begin maintenance mode at $start" . ($duration ? " for {$duration}h" : ''));
  1183. +    } else {
  1184. +        return api_success_noresult(201, "Device {$device->hostname} ({$device->device_id}) moved into maintenance mode" . ($duration ? " for {$duration}h" : ''));
  1185. +    }
  1186.  }
  1187.  
  1188.  function device_availability(Illuminate\Http\Request $request)
  1189. @@ -2143,7 +2154,11 @@ function maintenance_devicegroup(Illuminate\Http\Request $request)
  1190.      $device_group = ctype_digit($name) ? DeviceGroup::find($name) : DeviceGroup::where('name', $name)->first();
  1191.  
  1192.      if (! $device_group) {
  1193. -        return api_error(404, 'Device group not found');
  1194. +        return api_error(404, "Device group $name not found");
  1195. +    }
  1196. +
  1197. +    if (! $request->json('duration')) {
  1198. +        return api_error(400, 'Duration not provided');
  1199.      }
  1200.  
  1201.      $notes = $request->json('notes');
  1202. @@ -2170,7 +2185,11 @@ function maintenance_devicegroup(Illuminate\Http\Request $request)
  1203.      $alert_schedule->save();
  1204.      $alert_schedule->deviceGroups()->attach($device_group);
  1205.  
  1206. -    return api_success_noresult(201, "Device group {$device_group->name} ({$device_group->id}) will begin maintenance mode at $start" . ($duration ? " for {$duration}h" : ''));
  1207. +    if ($request->json('start')) {
  1208. +        return api_success_noresult(201, "Device group {$device_group->name} ({$device_group->id}) will begin maintenance mode at $start" . ($duration ? " for {$duration}h" : ''));
  1209. +    } else {
  1210. +        return api_success_noresult(201, "Device group {$device_group->name} ({$device_group->id}) moved into maintenance mode" . ($duration ? " for {$duration}h" : ''));
  1211. +    }
  1212.  }
  1213.  
  1214.  function get_devices_by_group(Illuminate\Http\Request $request)
  1215.  
  1216. commit 91e7b062c5795a51b025dbd9d6dfbe1b4d47c254
  1217. Author: Félix Bouynot <felixbouynot>
  1218. Date:   Thu Jul 28 15:44:23 2022 +0200
  1219.  
  1220.     Fix typo in Smokeping SELinux documentation (#14155)
  1221.  
  1222. diff --git a/doc/Extensions/Smokeping.md b/doc/Extensions/Smokeping.md
  1223. index 8f802d322..f651ba9f3 100644
  1224. --- a/doc/Extensions/Smokeping.md
  1225. +++ b/doc/Extensions/Smokeping.md
  1226. @@ -314,7 +314,7 @@ If you are using RRDCached with the -B switch and smokeping RRD's inside the Lib
  1227.  
  1228.  ```
  1229.  cat > smokeping_librenms.te &lt;&lt; EOF
  1230. -odule smokeping_librenms 1.0;
  1231. +module smokeping_librenms 1.0;
  1232.  
  1233.  require {
  1234.  type httpd_t;
  1235.