Skip to content

Commit

Permalink
Application Soft Delete (librenms#15270)
Browse files Browse the repository at this point in the history
* add the softdeletes migrations for applications

* add working migration file

* add deleted_at to db schema.yaml for applications

* update includes/html/forms/application-update.inc.php to work with softdeletes

* update includes/html/pages/device/edit/apps.inc.php for softdelete

* update includes/discovery/applications.inc.php to work with softdelete

* minor updates to application-update.inc.php for disabling

* style cleanup

* set discovered when running discovery

* update application tests to include deleted_at

* add deleted_at to a missed test

* a few more tweaks for opensips

* add a missing deleted_at for linux_suricata_extract-v1

* fix fillable for Application model

* massive cleanup of the application update widget thingy

* improve the code for discovery and using Laravel

* add a missing line to app/Models/Application

* add a missing include to app/Models/Application.php

* record includes for Application model

* remove apps from the applications table when a device is deleted

* revert to using upcert and where for discovery to fix CI

* make discovered fillable and set it when running discovery... convert back to firstOrNew

* clean up application discovery a bit and use observer

* style fix

* spelling fix... disablaed -> disabled

* rever removal to just use where

* cleanup app removal on delete

* add restored to ModuleModelObserver

* delete -> forcedelete fix

* apply the suggested changes

* use murrants other suggestion

* style fix
  • Loading branch information
VVelox authored Sep 6, 2023
1 parent 013096c commit 2618a99
Show file tree
Hide file tree
Showing 55 changed files with 269 additions and 134 deletions.
4 changes: 3 additions & 1 deletion app/Models/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@

namespace App\Models;

use Illuminate\Database\Eloquent\SoftDeletes;
use LibreNMS\Util\StringHelpers;

class Application extends DeviceRelatedModel
{
use SoftDeletes;
public $timestamps = false;
protected $primaryKey = 'app_id';
protected $fillable = ['data'];
protected $fillable = ['device_id', 'app_type', 'app_instance', 'app_status', 'app_state', 'data', 'deleted_at', 'discovered'];
protected $casts = [
'data' => 'array',
];
Expand Down
2 changes: 1 addition & 1 deletion app/Observers/DeviceObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function deleting(Device $device): void
$device->alerts()->delete();
\DB::table('alert_device_map')->where('device_id', $device->device_id)->delete();
$device->alertLogs()->delete();
$device->applications()->delete();
$device->applications()->forceDelete();
$device->attribs()->delete();
$device->availability()->delete();
$device->bgppeers()->delete();
Expand Down
9 changes: 9 additions & 0 deletions app/Observers/ModuleModelObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ public function updated($model): void
d_echo($model->getDirty());
}

/**
* @param Eloquent $model
*/
public function restored($model)
{
d_echo('Restored data:', 'R');
d_echo($model->getDirty());
}

/**
* @param Eloquent $model
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddApplicationsSoftDeleted extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('applications', function (Blueprint $table) {
$table->softDeletes();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('applications', function (Blueprint $table) {
$table->dropColumn('deleted_at');
});
}
}
44 changes: 17 additions & 27 deletions includes/discovery/applications.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
* @author Tony Murray <[email protected]>
*/

use App\Models\Application;
use App\Observers\ModuleModelObserver;
use LibreNMS\Config;

echo "\nApplications: ";
Expand Down Expand Up @@ -56,7 +58,7 @@

// Generate a list of enabled apps and a list of all discovered apps from the db
[$enabled_apps, $discovered_apps] = array_reduce(dbFetchRows(
'SELECT `app_type`,`discovered` FROM `applications` WHERE `device_id`=? ORDER BY `app_type`',
'SELECT `app_type`,`discovered` FROM `applications` WHERE `device_id`=? AND deleted_at IS NULL ORDER BY `app_type`',
[$device['device_id']]
), function ($result, $app) {
$result[0][] = $app['app_type'];
Expand All @@ -67,46 +69,34 @@
return $result;
}, [[], []]);

// enable observer for printing changes
ModuleModelObserver::observe(\App\Models\Application::class);

// Enable applications
$current_apps = [];
foreach ($results as $extend => $result) {
if (isset($applications[$extend])) {
$app = $applications[$extend];
$current_apps[] = $app;

if (in_array($app, $enabled_apps)) {
echo '.';
} else {
dbInsert([
'device_id' => $device['device_id'],
'app_type' => $app,
'discovered' => 1,
'app_status' => '',
'app_instance' => '',
], 'applications');

echo '+';
if (! in_array($app, $enabled_apps)) {
$app_obj = Application::withTrashed()->firstOrNew(['device_id' => $device['device_id'], 'app_type' => $app]);
if ($app_obj->trashed()) {
$app_obj->restore();
}
$app_obj->discovered = 1;
$app_obj->save();
log_event("Application enabled by discovery: $app", $device, 'application', 1);
}
}
}

// remove non-existing apps
$apps_to_remove = array_diff($discovered_apps, $current_apps);
$num = count($apps_to_remove);
if ($num > 0) {
echo str_repeat('-', $num);
$vars = $apps_to_remove;
array_unshift($vars, $device['device_id']);
dbDelete(
'applications',
'`device_id`=? AND `app_type` IN ' . dbGenPlaceholders($num),
$vars
);
foreach ($apps_to_remove as $app) {
log_event("Application disabled by discovery: $app", $device, 'application', 3);
}
}
DeviceCache::getPrimary()->applications()->whereIn('app_type', $apps_to_remove)->get()->each(function (Application $app) {
$app->delete();
\App\Models\Eventlog::log("Application disabled by discovery: $app->app_type", DeviceCache::getPrimary(), 'application', \LibreNMS\Enum\Severity::Notice);
});

// clean application_metrics
dbDeleteOrphans('application_metrics', ['applications.app_id']);
Expand Down
21 changes: 13 additions & 8 deletions includes/html/forms/application-update.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
* @copyright 2017 Tony Murray
* @author Tony Murray <[email protected]>
*/
use App\Models\Application;

if (! Auth::user()->hasGlobalAdmin()) {
$status = ['status' => 1, 'message' => 'You need to be admin'];
} else {
Expand All @@ -32,21 +34,24 @@
$status = ['status' => 1, 'message' => 'Error with data'];
} else {
$status = ['status' => 1, 'message' => 'Database update failed'];
$app = Application::withTrashed()->firstOrNew(['device_id' => $device_id, 'app_type' => $app]);
if ($_POST['state'] == 'true') {
$update = [
'device_id' => $device_id,
'app_type' => $app,
'app_status' => '',
'app_instance' => '',
];
if (dbInsert($update, 'applications')) {
if ($app->trashed()) {
$app->restore();
}
if ($app->save()) {
log_event("Application enabled by user: $app", $device_id, 'application', 1);
$status = ['status' => 0, 'message' => 'Application enabled'];
} else {
$status = ['status' => 1, 'message' => 'Database update for enabling the application failed'];
}
} else {
if (dbDelete('applications', '`device_id`=? AND `app_type`=?', [$device_id, $app])) {
$app->delete();
if ($app->save()) {
log_event("Application disabled by user: $app", $device_id, 'application', 3);
$status = ['status' => 0, 'message' => 'Application disabled'];
} else {
$status = ['status' => 1, 'message' => 'Database update for disabling the application failed'];
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion includes/html/pages/device/edit/apps.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

// Generate a list of enabled apps with a value of whether they are discovered or not
$enabled_apps = array_reduce(dbFetchRows(
'SELECT `app_type`,`discovered` FROM `applications` WHERE `device_id`=? ORDER BY `app_type`',
'SELECT `app_type`,`discovered` FROM `applications` WHERE `device_id`=? AND deleted_at IS NULL ORDER BY `app_type`',
[$device['device_id']]
), function ($result, $app) {
$result[$app['app_type']] = $app['discovered'];
Expand Down
1 change: 1 addition & 0 deletions misc/db_schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ applications:
- { Field: timestamp, Type: timestamp, 'Null': false, Extra: 'on update CURRENT_TIMESTAMP', Default: CURRENT_TIMESTAMP }
- { Field: app_instance, Type: varchar(255), 'Null': false, Extra: '', Default: '' }
- { Field: data, Type: longtext, 'Null': true, Extra: '' }
- { Field: deleted_at, Type: timestamp, 'Null': true, Extra: '' }
Indexes:
PRIMARY: { Name: PRIMARY, Columns: [app_id], Unique: true, Type: BTREE }
applications_device_id_app_type_unique: { Name: applications_device_id_app_type_unique, Columns: [device_id, app_type], Unique: true, Type: BTREE }
Expand Down
6 changes: 4 additions & 2 deletions tests/data/beagleboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -1674,7 +1674,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -1687,7 +1688,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "18",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_asterisk-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -22,7 +23,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_cape-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -22,7 +23,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_certificate-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -43,7 +44,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_chronyd.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -22,7 +23,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "",
"app_instance": "",
"data": "{\"sources\":[\"PPS\",\"GPS\"]}"
"data": "{\"sources\":[\"PPS\",\"GPS\"]}",
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_docker-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -22,7 +23,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "LEGACY",
"app_instance": "",
"data": "{\"containers\":[\"foobar_laravel.test_1\",\"foobar_dashboard_1\",\"foobar_meilisearch_1\",\"foobar_mysql_1\",\"foobar_redis_1\"]}"
"data": "{\"containers\":[\"foobar_laravel.test_1\",\"foobar_dashboard_1\",\"foobar_meilisearch_1\",\"foobar_mysql_1\",\"foobar_redis_1\"]}",
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_docker-v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -22,7 +23,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "",
"app_instance": "",
"data": "{\"containers\":[\"foobar_laravel.test_1\",\"foobar_dashboard_1\",\"foobar_meilisearch_1\",\"foobar_mysql_1\",\"foobar_redis_1\"]}"
"data": "{\"containers\":[\"foobar_laravel.test_1\",\"foobar_dashboard_1\",\"foobar_meilisearch_1\",\"foobar_mysql_1\",\"foobar_redis_1\"]}",
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_fail2ban-legacy.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -22,7 +23,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "",
"app_instance": "",
"data": "{\"jails\":[\"dovecot\",\"sshd\"]}"
"data": "{\"jails\":[\"dovecot\",\"sshd\"]}",
"deleted_at": null
}
],
"application_metrics": [
Expand Down
6 changes: 4 additions & 2 deletions tests/data/linux_fail2ban-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"app_state_prev": null,
"app_status": "",
"app_instance": "",
"data": null
"data": null,
"deleted_at": null
}
]
},
Expand All @@ -22,7 +23,8 @@
"app_state_prev": "UNKNOWN",
"app_status": "",
"app_instance": "",
"data": "{\"jails\":[\"sshd\",\"dovecot\"]}"
"data": "{\"jails\":[\"sshd\",\"dovecot\"]}",
"deleted_at": null
}
],
"application_metrics": [
Expand Down
Loading

0 comments on commit 2618a99

Please sign in to comment.