Skip to content

Commit f4b7027

Browse files
mwobstlaf
andauthored
Add Scheduled Maintenance behaviour to control alerts (librenms#17929)
* Fix typo * Apply code cleanup * Add behaviors to scheduled maintenance A scheduled maintenance means that no alert rule checks are run for affected devices. Therefore any new issue would go by unnoticed. This behavior will be called "Skip alert rule checks". Two more behaviors are introduced: - "No alert transporting": Alert rule checks are run as usual, but no alert transport (e. g. e-mail) happens - "Information only": Choose this if you want to see the screwdriver right of the device name at the detail page. Alerting and alert transport will continue to work as before. * Add documentation for scheduled maintenances * Ensure that device type icon is displayed below device state Otherwise the icon "overshadows" the text if the latter one is to long. * Improve warning in config definition file * Update Scheduled-Maintenances.md * Update api_functions.inc.php * Update schedule-maintenance.inc.php * Update config_definitions.json * Update alert_schedule.inc.php * Update device_maintenance.inc.php * Update settings.php * Update settings.php * Update settings.php * Update settings.php --------- Co-authored-by: Neil Lathwood <[email protected]>
1 parent ec89714 commit f4b7027

26 files changed

+408
-19
lines changed

LibreNMS/Alert/AlertRules.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use Illuminate\Support\Facades\Log;
3939
use LibreNMS\Alerting\QueryBuilderParser;
4040
use LibreNMS\Enum\AlertState;
41+
use LibreNMS\Enum\MaintenanceAlertBehavior;
4142
use LibreNMS\Enum\Severity;
4243
use PDO;
4344
use PDOException;
@@ -47,7 +48,7 @@ class AlertRules
4748
public function runRules($device_id)
4849
{
4950
//Check to see if under maintenance
50-
if (AlertUtil::isMaintenance($device_id) > 0) {
51+
if (AlertUtil::isMaintenance($device_id, MaintenanceAlertBehavior::SKIP->value) > 0) {
5152
echo "Under Maintenance, skipping alert rules check.\r\n";
5253

5354
return false;

LibreNMS/Alert/AlertUtil.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,9 @@ public static function getRules($device_id)
207207
* @param int $device_id Device-ID
208208
* @return bool
209209
*/
210-
public static function isMaintenance($device_id)
210+
public static function isMaintenance($device_id, $behavior)
211211
{
212-
return DeviceCache::get($device_id)->isUnderMaintenance();
212+
return DeviceCache::get($device_id)->isUnderMaintenance($behavior);
213213
}
214214

215215
/**

LibreNMS/Alert/RunAlerts.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use App\Models\Eventlog;
3939
use LibreNMS\Alerting\QueryBuilderParser;
4040
use LibreNMS\Enum\AlertState;
41+
use LibreNMS\Enum\MaintenanceAlertBehavior;
4142
use LibreNMS\Enum\Severity;
4243
use LibreNMS\Exceptions\AlertTransportDeliveryException;
4344
use LibreNMS\Polling\ConnectivityHelper;
@@ -548,8 +549,23 @@ public function runAlerts()
548549
$noacc = false;
549550
}
550551

551-
if (AlertUtil::isMaintenance($alert['device_id'])) {
552+
$disable_alert_transport = AlertUtil::isMaintenance(
553+
$alert['device_id'],
554+
MaintenanceAlertBehavior::MUTE->value
555+
);
556+
$skip_alert_rule_checks = AlertUtil::isMaintenance(
557+
$alert['device_id'],
558+
MaintenanceAlertBehavior::SKIP->value
559+
);
560+
561+
// Do not send alert notifications for these types of scheduled maintenance
562+
if ($disable_alert_transport || $skip_alert_rule_checks) {
552563
$noiss = true;
564+
}
565+
566+
// If alert rule checks are to be skipped, ensure that this alert is
567+
// not to be handled again by this method again (by changing open to 0 later)
568+
if ($skip_alert_rule_checks) {
553569
$noacc = true;
554570
}
555571

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/*
4+
* MaintenanceAlertBehavior.php
5+
*
6+
* -Description-
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License as published by
10+
* the Free Software Foundation, either version 3 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
*
21+
* @package LibreNMS
22+
* @link https://www.librenms.org
23+
*/
24+
25+
namespace LibreNMS\Enum;
26+
27+
enum MaintenanceAlertBehavior: int
28+
{
29+
case ANY = 0;
30+
case SKIP = 1;
31+
case MUTE = 2;
32+
case RUN = 3;
33+
34+
public static function is_valid_option($value)
35+
{
36+
$valid_options = [
37+
self::SKIP->value,
38+
self::MUTE->value,
39+
self::RUN->value,
40+
];
41+
42+
return in_array((int) $value, $valid_options);
43+
}
44+
45+
public static function get_value_or_fallback($value, $fallback)
46+
{
47+
// the fallback value needs to be validated first to avoid config nonsense
48+
$valid_fallback = self::is_valid_option($fallback)
49+
? $fallback
50+
: self::SKIP->value;
51+
52+
return self::is_valid_option($value)
53+
? (int) $value
54+
: (int) $valid_fallback;
55+
}
56+
}

LibreNMS/Polling/ConnectivityHelper.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use App\Models\Eventlog;
3333
use LibreNMS\Data\Source\Fping;
3434
use LibreNMS\Data\Source\FpingResponse;
35+
use LibreNMS\Enum\MaintenanceAlertBehavior;
3536
use LibreNMS\Enum\Severity;
3637
use SnmpQuery;
3738
use Symfony\Component\Process\Process;
@@ -171,7 +172,10 @@ public function ipFamily(): string
171172

172173
private function updateAvailability(bool $previous, bool $status): void
173174
{
174-
if (LibrenmsConfig::get('graphing.availability_consider_maintenance') && $this->device->isUnderMaintenance()) {
175+
if (
176+
LibrenmsConfig::get('graphing.availability_consider_maintenance')
177+
&& $this->device->isUnderMaintenance(MaintenanceAlertBehavior::SKIP->value)
178+
) {
175179
return;
176180
}
177181

app/Http/Controllers/DeviceController.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Illuminate\Support\Arr;
1313
use Illuminate\Support\Facades\Auth;
1414
use Illuminate\Support\Facades\Blade;
15+
use LibreNMS\Enum\MaintenanceAlertBehavior;
1516
use LibreNMS\Interfaces\UI\DeviceTab;
1617
use LibreNMS\Util\Debug;
1718
use LibreNMS\Util\Graph;
@@ -94,6 +95,9 @@ public function index(Request $request, $device, $current_tab = 'overview', $var
9495
$data = $tab_controller->data($device, $request);
9596
$page_links = $data['page_links'] ?? [];
9697

98+
// Pass 'any' behaviour for scheduled behaviors
99+
$maintenance_any_behaviour = MaintenanceAlertBehavior::ANY->value;
100+
97101
// Device Link Menu, select the primary link
98102
$device_links = $this->deviceLinkMenu($device, $current_tab);
99103
$primary_device_link_name = LibrenmsConfig::get('html.device.primary_link', 'edit');

app/Http/Controllers/Table/AlertScheduleController.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use App\Models\AlertSchedule;
3030
use Carbon\Carbon;
3131
use Illuminate\Support\Facades\DB;
32+
use LibreNMS\Enum\MaintenanceAlertBehavior;
3233

3334
class AlertScheduleController extends TableController
3435
{
@@ -56,6 +57,7 @@ protected function sortFields($request)
5657
'start' => 'start',
5758
'end' => 'end',
5859
'status' => DB::raw("end < '" . Carbon::now('UTC') . "'"), // only partition lapsed
60+
'behavior' => 'behavior',
5961
];
6062
}
6163

@@ -65,9 +67,26 @@ protected function sortFields($request)
6567
*/
6668
public function formatItem($schedule)
6769
{
70+
$behavior_lang_keypart = '';
71+
72+
if ($schedule->behavior == MaintenanceAlertBehavior::SKIP->value) {
73+
$behavior_lang_keypart = 'skip_alerts';
74+
} elseif ($schedule->behavior == MaintenanceAlertBehavior::MUTE->value) {
75+
$behavior_lang_keypart = 'mute_alerts';
76+
} elseif ($schedule->behavior == MaintenanceAlertBehavior::RUN->value) {
77+
$behavior_lang_keypart = 'run_alerts';
78+
}
79+
80+
if (! empty($behavior_lang_keypart)) {
81+
$behavior_str = __('maintenance.behavior.options.' . $behavior_lang_keypart);
82+
} else {
83+
$behavior_str = '';
84+
}
85+
6886
return [
6987
'title' => htmlentities($schedule->title),
7088
'notes' => htmlentities($schedule->notes),
89+
'behavior' => $behavior_str,
7190
'id' => $schedule->schedule_id,
7291
'start' => $schedule->recurring ? '' : $schedule->start->toDateTimeString('minutes'),
7392
'end' => $schedule->recurring ? '' : $schedule->end->toDateTimeString('minutes'),

app/Http/Controllers/Table/DeviceController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Illuminate\Support\Arr;
3434
use Illuminate\Support\Facades\Auth;
3535
use Illuminate\Support\Facades\Blade;
36+
use LibreNMS\Enum\MaintenanceAlertBehavior;
3637
use LibreNMS\Util\Rewrite;
3738
use LibreNMS\Util\Time;
3839
use LibreNMS\Util\Url;
@@ -154,7 +155,7 @@ public function formatItem($device)
154155
return [
155156
'extra' => $this->getLabel($device),
156157
'status' => $status,
157-
'maintenance' => $device->isUnderMaintenance(),
158+
'maintenance' => $device->isUnderMaintenance(MaintenanceAlertBehavior::ANY->value),
158159
'icon' => '<img src="' . asset($device->icon) . '" title="' . pathinfo($device->icon, PATHINFO_FILENAME) . '">',
159160
'hostname' => $this->getHostname($device, $status),
160161
'metrics' => $this->getMetrics($device),

app/Models/Device.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Illuminate\Database\Query\JoinClause;
1818
use Illuminate\Support\Arr;
1919
use Illuminate\Support\Str;
20+
use LibreNMS\Enum\MaintenanceAlertBehavior;
2021
use LibreNMS\Exceptions\InvalidIpException;
2122
use LibreNMS\Util\IP;
2223
use LibreNMS\Util\IPv4;
@@ -240,7 +241,7 @@ public function name(): string
240241
return '';
241242
}
242243

243-
public function isUnderMaintenance()
244+
public function isUnderMaintenance($behavior = MaintenanceAlertBehavior::SKIP->value)
244245
{
245246
if (! $this->device_id) {
246247
return false;
@@ -265,6 +266,10 @@ public function isUnderMaintenance()
265266
}
266267
});
267268

269+
if ($behavior != MaintenanceAlertBehavior::ANY->value) {
270+
$query = $query->where('behavior', $behavior);
271+
}
272+
268273
return $query->exists();
269274
}
270275

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
use LibreNMS\Enum\MaintenanceAlertBehavior;
7+
8+
return new class extends Migration
9+
{
10+
/**
11+
* Run the migrations.
12+
*/
13+
public function up(): void
14+
{
15+
Schema::table('alert_schedule', function (Blueprint $table) {
16+
$table->integer('behavior')->default(
17+
MaintenanceAlertBehavior::SKIP->value
18+
);
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*/
25+
public function down(): void
26+
{
27+
Schema::table('alert_schedule', function (Blueprint $table) {
28+
$table->dropColumn('behavior');
29+
});
30+
}
31+
};

0 commit comments

Comments
 (0)