Skip to content

Commit

Permalink
Merge branch 'librenms:master' into worknoc
Browse files Browse the repository at this point in the history
  • Loading branch information
ottorei authored Sep 19, 2024
2 parents 98761b6 + 2fc59a4 commit 204d6fb
Show file tree
Hide file tree
Showing 744 changed files with 269,987 additions and 35,960 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ jobs:
run: |
php lnms dev:simulate --setup-venv
-
name: Artisan dusk:chrome-driver
name: Start ChromeDriver
if: matrix.skip-web-check != '1'
run: |
php artisan dusk:chrome-driver --detect
$CHROMEWEBDRIVER/chromedriver --port=9515 &
-
name: Copy seeded config
run: cp "${GITHUB_WORKSPACE}/tests/testing_config.yaml" "${GITHUB_WORKSPACE}/database/seeders/config/"
Expand Down
14 changes: 11 additions & 3 deletions LibreNMS/Alert/RunAlerts.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ public function runFollowUp()
$chk[$i]['ip'] = inet6_ntop($chk[$i]['ip']);
}
}
$alert['details']['rule'] ??= []; // if details.rule is missing, set it to an empty array
$o = count($alert['details']['rule']);
$n = count($chk);
$ret = 'Alert #' . $alert['id'];
Expand Down Expand Up @@ -391,6 +392,11 @@ public function runAlerts()
$rextra['recovery'] = true;
}

if (! isset($alert['details']['count'])) {
// make sure count is set for below code, in legacy code null would get type juggled to 0
$alert['details']['count'] = 0;
}

$chk = dbFetchRow('SELECT alerts.alerted,devices.ignore,devices.disabled FROM alerts,devices WHERE alerts.device_id = ? && devices.device_id = alerts.device_id && alerts.rule_id = ?', [$alert['device_id'], $alert['rule_id']]);

if ($chk['alerted'] == $alert['state']) {
Expand All @@ -410,7 +416,8 @@ public function runAlerts()
}

if ($alert['state'] == AlertState::ACTIVE && ! empty($rextra['count']) && ($rextra['count'] == -1 || $alert['details']['count']++ < $rextra['count'])) {
if ($alert['details']['count'] < $rextra['count']) {
// We don't want -1 alert rule count alarms to get muted because of the current alert count
if ($alert['details']['count'] < $rextra['count'] || $rextra['count'] == -1) {
$noacc = true;
}

Expand All @@ -432,8 +439,9 @@ public function runAlerts()
}
}

if (in_array($alert['state'], [AlertState::ACTIVE, AlertState::WORSE, AlertState::BETTER]) && ! empty($rextra['count']) && isset($alert['details']['count']) && ($rextra['count'] == -1 || $alert['details']['count']++ < $rextra['count'])) {
if ($alert['details']['count'] < $rextra['count']) {
if (in_array($alert['state'], [AlertState::ACTIVE, AlertState::WORSE, AlertState::BETTER]) && ! empty($rextra['count']) && ($rextra['count'] == -1 || $alert['details']['count']++ < $rextra['count'])) {
// We don't want -1 alert rule count alarms to get muted because of the current alert count
if ($alert['details']['count'] < $rextra['count'] || $rextra['count'] == -1) {
$noacc = true;
}

Expand Down
2 changes: 1 addition & 1 deletion LibreNMS/Alert/Transport/Matrix.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function deliverAlert(array $alert_data): bool

$message = SimpleTemplate::parse($message, $alert_data);

$body = ['body' => strip_tags($message), 'formatted_body' => "$message", 'msgtype' => 'm.text', 'format' => 'org.matrix.custom.html'];
$body = ['body' => strip_tags($message), 'formatted_body' => "$message", 'msgtype' => 'm.notice', 'format' => 'org.matrix.custom.html'];

$res = Http::client()
->withToken($authtoken)
Expand Down
15 changes: 0 additions & 15 deletions LibreNMS/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -478,9 +478,6 @@ private static function processConfig()
}

self::populateTime();

// populate legacy DB credentials, just in case something external uses them. Maybe remove this later
self::populateLegacyDbCredentials();
}

/**
Expand Down Expand Up @@ -561,18 +558,6 @@ private static function populateTime()
self::set('time.twoyear', $now - 63072000); // time() - (2 * 365 * 24 * 60 * 60);
}

public static function populateLegacyDbCredentials()
{
$db = config('database.default');

self::set('db_host', config("database.connections.$db.host", 'localhost'));
self::set('db_name', config("database.connections.$db.database", 'librenms'));
self::set('db_user', config("database.connections.$db.username", 'librenms'));
self::set('db_pass', config("database.connections.$db.password"));
self::set('db_port', config("database.connections.$db.port", 3306));
self::set('db_socket', config("database.connections.$db.unix_socket"));
}

/**
* Check if the config has been loaded yet
*
Expand Down
32 changes: 26 additions & 6 deletions LibreNMS/DB/SyncsModels.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,26 @@

namespace LibreNMS\DB;

use App\Models\Device;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Support\Collection;
use LibreNMS\Interfaces\Models\Keyable;

trait SyncsModels
{
/**
* Sync several models for a device's relationship
* Model must implement \LibreNMS\Interfaces\Models\Keyable interface
*
* @param \App\Models\Device $device
* @param \Illuminate\Database\Eloquent\Model $parentModel
* @param string $relationship
* @param \Illuminate\Support\Collection $models \LibreNMS\Interfaces\Models\Keyable
* @param \Illuminate\Support\Collection<Keyable> $models \LibreNMS\Interfaces\Models\Keyable
* @return \Illuminate\Support\Collection
*/
protected function syncModels($device, $relationship, $models): Collection
protected function syncModels($parentModel, $relationship, $models, $existing = null): Collection
{
$models = $models->keyBy->getCompositeKey();
$existing = $device->$relationship->groupBy->getCompositeKey();
$existing = ($existing ?? $parentModel->$relationship)->groupBy->getCompositeKey();

foreach ($existing as $exist_key => $existing_rows) {
if ($models->offsetExists($exist_key)) {
Expand All @@ -64,17 +66,35 @@ protected function syncModels($device, $relationship, $models): Collection
}

$new = $models->diffKeys($existing);
if (is_a($device->$relationship(), HasManyThrough::class)) {
if (is_a($parentModel->$relationship(), HasManyThrough::class)) {
// if this is a distant relation, the models need the intermediate relationship set
// just save assuming things are correct
$new->each->save();
} else {
$device->$relationship()->saveMany($new);
$parentModel->$relationship()->saveMany($new);
}

return $existing->map->first()->merge($new);
}

/**
* Sync a sub-group of models to the database
*
* @param Collection<Keyable> $models
*/
public function syncModelsByGroup(Device $device, string $relationship, Collection $models, array $where): Collection
{
$filter = function ($models, $params) {
foreach ($params as $key => $value) {
$models = $models->where($key, '=', $value);
}

return $models;
};

return $this->syncModels($device, $relationship, $models->when($where, $filter), $device->$relationship->when($where, $filter));
}

/**
* Combine a list of existing and potentially new models
* If the model exists fill any new data from the new models
Expand Down
20 changes: 20 additions & 0 deletions LibreNMS/Data/Source/SnmpResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,26 @@ public function values(): array
return $this->values;
}

/**
* Create a key to value pair for an OID
* Only works for single indexed tables
* You may omit $oid if there is only one $oid in the walk
*/
public function pluck(?string $oid = null): array
{
$output = [];
$oid = $oid ?? '[a-zA-Z0-9:.-]+';
$regex = "/^{$oid}[[.](\d+)]?$/";

foreach ($this->values() as $key => $value) {
if (preg_match($regex, $key, $matches)) {
$output[$matches[1]] = $value;
}
}

return $output;
}

public function valuesByIndex(array &$array = []): array
{
foreach ($this->values() as $oid => $value) {
Expand Down
46 changes: 29 additions & 17 deletions LibreNMS/Data/Store/Rrd.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,24 @@ class Rrd extends BaseDatastore
private $sync_process;
/** @var Proc */
private $async_process;
/** @var string */
private $rrd_dir;
/** @var string */
private $version;
/** @var string */
private $rrdcached;
/** @var string */
private $rra;
/** @var int */
private $step;
/** @var string */
private $rrdtool_executable;

public function __construct()
{
parent::__construct();
$this->rrdcached = Config::get('rrdcached', false);

$this->loadConfig();
$this->init();
$this->rrd_dir = Config::get('rrd_dir', Config::get('install_dir') . '/rrd');
$this->step = Config::get('rrd.step', 300);
$this->rra = Config::get(
'rrd_rra',
'RRA:AVERAGE:0.5:1:2016 RRA:AVERAGE:0.5:6:1440 RRA:AVERAGE:0.5:24:1440 RRA:AVERAGE:0.5:288:1440 ' .
' RRA:MIN:0.5:1:2016 RRA:MIN:0.5:6:1440 RRA:MIN:0.5:24:1440 RRA:MIN:0.5:288:1440 ' .
' RRA:MAX:0.5:1:2016 RRA:MAX:0.5:6:1440 RRA:MAX:0.5:24:1440 RRA:MAX:0.5:288:1440 ' .
' RRA:LAST:0.5:1:2016 '
);
$this->version = Config::get('rrdtool_version', '1.4');
}

public function getName()
Expand All @@ -78,23 +74,39 @@ public static function isEnabled()
return Config::get('rrd.enable', true);
}

protected function loadConfig(): void
{
$this->rrdcached = Config::get('rrdcached', false);
$this->rrd_dir = Config::get('rrd_dir', Config::get('install_dir') . '/rrd');
$this->step = Config::get('rrd.step', 300);
$this->rra = Config::get(
'rrd_rra',
'RRA:AVERAGE:0.5:1:2016 RRA:AVERAGE:0.5:6:1440 RRA:AVERAGE:0.5:24:1440 RRA:AVERAGE:0.5:288:1440 ' .
' RRA:MIN:0.5:1:2016 RRA:MIN:0.5:6:1440 RRA:MIN:0.5:24:1440 RRA:MIN:0.5:288:1440 ' .
' RRA:MAX:0.5:1:2016 RRA:MAX:0.5:6:1440 RRA:MAX:0.5:24:1440 RRA:MAX:0.5:288:1440 ' .
' RRA:LAST:0.5:1:2016 '
);
$this->version = Config::get('rrdtool_version', '1.4');
$this->rrdtool_executable = Config::get('rrdtool', 'rrdtool');
}

/**
* Opens up a pipe to RRDTool using handles provided
*
* @param bool $dual_process start an additional process that's output should be read after every command
* @return bool the process(s) have been successfully started
*/
public function init($dual_process = true)
public function init($dual_process = true): bool
{
$command = Config::get('rrdtool', 'rrdtool') . ' -';
$command = $this->rrdtool_executable . ' -';

$descriptor_spec = [
0 => ['pipe', 'r'], // stdin is a pipe that the child will read from
1 => ['pipe', 'w'], // stdout is a pipe that the child will write to
2 => ['pipe', 'w'], // stderr is a pipe that the child will write to
];

$cwd = Config::get('rrd_dir');
$cwd = $this->rrd_dir;

if (! $this->isSyncRunning()) {
$this->sync_process = new Proc($command, $descriptor_spec, $cwd);
Expand Down Expand Up @@ -438,7 +450,7 @@ private function command($command, $filename, $options)
*
* @throws FileExistsException if rrdtool <1.4.3 and the rrd file exists locally
*/
public function buildCommand($command, $filename, $options)
public function buildCommand($command, $filename, $options): string
{
if ($command == 'create') {
// <1.4.3 doesn't support -O, so make sure the file doesn't exist
Expand Down Expand Up @@ -579,7 +591,7 @@ public function purge($hostname, $prefix)
*/
public function graph(string $options, array $env = null): string
{
$process = new Process([Config::get('rrdtool', 'rrdtool'), '-'], $this->rrd_dir, $env);
$process = new Process([$this->rrdtool_executable, '-'], $this->rrd_dir, $env);
$process->setTimeout(300);
$process->setIdleTimeout(300);

Expand Down
15 changes: 13 additions & 2 deletions LibreNMS/Device/Availability.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use App\Models\Device;
use App\Models\DeviceOutage;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use LibreNMS\Util\Number;

class Availability
Expand Down Expand Up @@ -115,7 +116,7 @@ public static function availability(Device $device, int $duration, int $precisio

// no recorded outages found, so use current status
if ($found_outages->isEmpty()) {
return 100 * $device->status;
return $device->status ? 100 : 0;
}

// don't calculate for time when the device didn't exist
Expand All @@ -125,6 +126,16 @@ public static function availability(Device $device, int $duration, int $precisio

$outage_summary = self::outageSummary($found_outages, $duration, $now);

return Number::calculatePercent($duration - $outage_summary, $duration, $precision);
$percent = Number::calculatePercent($duration - $outage_summary, $duration, $precision);
if ($percent < 0) {
Log::debug("Invalid availability calculation ($percent), normalizing to 0");
$percent = 0;
}
if ($percent > 100) {
Log::debug("Invalid availability calculation ($percent), normalizing to 100");
$percent = 100;
}

return $percent;
}
}
39 changes: 39 additions & 0 deletions LibreNMS/Interfaces/Discovery/EntityPhysicalDiscovery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/**
* EntityPhysicalDiscovery.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
*
* @copyright 2024 Tony Murray
* @author Tony Murray <[email protected]>
*/

namespace LibreNMS\Interfaces\Discovery;

use Illuminate\Support\Collection;

interface EntityPhysicalDiscovery
{
/**
* Discover a Collection of IsIsAdjacency models.
* Will be keyed by ifIndex
*
* @return \Illuminate\Support\Collection<\App\Models\EntPhysical>
*/
public function discoverEntityPhysical(): Collection;
}
7 changes: 6 additions & 1 deletion LibreNMS/Interfaces/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,18 @@ public function discover(OS $os): void;
*/
public function poll(OS $os, DataStorageInterface $datastore): void;

/**
* Check if data exists for this module
*/
public function dataExists(Device $device): bool;

/**
* Remove all DB data for this module.
* This will be run when the module is disabled.
*
* @param \App\Models\Device $device
*/
public function cleanup(Device $device): void;
public function cleanup(Device $device): int;

/**
* Dump current module data for the given device for tests.
Expand Down
Loading

0 comments on commit 204d6fb

Please sign in to comment.