mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Delete ports via eloquent event (#11354)
* Delete ports via eloquent event Chunk delete during purge all operations so we don't use too much memory. * protect against missing device * fix whitespace * fetch less from the database when deleting a device's ports fix output
This commit is contained in:
@@ -269,6 +269,18 @@ class Rrd extends BaseDatastore
|
||||
return join('/', [$pmxcdir, self::safeName($vmid . '_netif_' . $vmport . '.rrd')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the port rrd file. For alternate rrd, specify the suffix.
|
||||
*
|
||||
* @param int $port_id
|
||||
* @param string $suffix
|
||||
* @return string
|
||||
*/
|
||||
public function portName($port_id, $suffix = null)
|
||||
{
|
||||
return "port-id$port_id" . (empty($suffix) ? '' : '-' . $suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* rename an rrdfile, can only be done on the LibreNMS server hosting the rrd files
|
||||
*
|
||||
@@ -433,6 +445,23 @@ class Rrd extends BaseDatastore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove RRD file(s). Use with care as this permanently deletes rrd data.
|
||||
* @param string $hostname rrd subfolder (hostname)
|
||||
* @param string $prefix start of rrd file name all files matching will be deleted
|
||||
*/
|
||||
public function purge($hostname, $prefix)
|
||||
{
|
||||
if (empty($hostname)) {
|
||||
Log::error("Could not purge rrd $prefix, empty hostname");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (glob($this->name($hostname, $prefix, '*.rrd')) as $rrd) {
|
||||
unlink($rrd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a graph file at $graph_file using $options
|
||||
* Opens its own rrdtool pipe.
|
||||
|
10
app/Models/MacAccounting.php
Normal file
10
app/Models/MacAccounting.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class MacAccounting extends PortRelatedModel
|
||||
{
|
||||
protected $table = 'mac_accounting';
|
||||
protected $primaryKey = 'ma_id';
|
||||
public $timestamps = false;
|
||||
}
|
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use DB;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use LibreNMS\Data\Store\Rrd;
|
||||
use LibreNMS\Util\Rewrite;
|
||||
use Permissions;
|
||||
|
||||
@@ -12,7 +13,40 @@ class Port extends DeviceRelatedModel
|
||||
public $timestamps = false;
|
||||
protected $primaryKey = 'port_id';
|
||||
|
||||
// ---- Helper Functions ----
|
||||
/**
|
||||
* Initialize this class
|
||||
*/
|
||||
public static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::deleting(function (Port $port) {
|
||||
// delete related data
|
||||
$port->adsl()->delete();
|
||||
$port->fdbEntries()->delete();
|
||||
$port->ipv4()->delete();
|
||||
$port->ipv6()->delete();
|
||||
$port->macAccounting()->delete();
|
||||
$port->macs()->delete();
|
||||
$port->nac()->delete();
|
||||
$port->ospfNeighbors()->delete();
|
||||
$port->ospfPorts()->delete();
|
||||
$port->pseudowires()->delete();
|
||||
$port->statistics()->delete();
|
||||
$port->stp()->delete();
|
||||
$port->vlans()->delete();
|
||||
|
||||
// dont have relationships yet
|
||||
DB::table('juniAtmVp')->where('port_id', $port->port_id)->delete();
|
||||
DB::table('ports_perms')->where('port_id', $port->port_id)->delete();
|
||||
DB::table('links')->where('local_port_id', $port->port_id)->orWhere('remote_port_id', $port->port_id)->delete();
|
||||
DB::table('ports_stack')->where('port_id_low', $port->port_id)->orWhere('port_id_high', $port->port_id)->delete();
|
||||
|
||||
\Rrd::purge(optional($port->device)->hostname, \Rrd::portName($port->port_id)); // purge all port rrd files
|
||||
});
|
||||
}
|
||||
|
||||
// ---- Helper Functions ----
|
||||
|
||||
/**
|
||||
* Returns a human readable label for this port
|
||||
@@ -216,6 +250,11 @@ class Port extends DeviceRelatedModel
|
||||
|
||||
// ---- Define Relationships ----
|
||||
|
||||
public function adsl()
|
||||
{
|
||||
return $this->hasMany(PortAdsl::class, 'port_id');
|
||||
}
|
||||
|
||||
public function events()
|
||||
{
|
||||
return $this->morphMany(Eventlog::class, 'events', 'type', 'reference');
|
||||
@@ -226,12 +265,6 @@ class Port extends DeviceRelatedModel
|
||||
return $this->hasMany('App\Models\PortsFdb', 'port_id', 'port_id');
|
||||
}
|
||||
|
||||
public function users()
|
||||
{
|
||||
// FIXME does not include global read
|
||||
return $this->belongsToMany('App\Models\User', 'ports_perms', 'port_id', 'user_id');
|
||||
}
|
||||
|
||||
public function ipv4()
|
||||
{
|
||||
return $this->hasMany('App\Models\Ipv4Address', 'port_id');
|
||||
@@ -241,4 +274,55 @@ class Port extends DeviceRelatedModel
|
||||
{
|
||||
return $this->hasMany('App\Models\Ipv6Address', 'port_id');
|
||||
}
|
||||
|
||||
public function macAccounting()
|
||||
{
|
||||
return $this->hasMany(MacAccounting::class, 'port_id');
|
||||
}
|
||||
|
||||
public function macs()
|
||||
{
|
||||
return $this->hasMany(Ipv4Mac::class, 'port_id');
|
||||
}
|
||||
|
||||
public function nac()
|
||||
{
|
||||
return $this->hasMany(PortsNac::class, 'port_id');
|
||||
}
|
||||
|
||||
public function ospfNeighbors()
|
||||
{
|
||||
return $this->hasMany(OspfNbr::class, 'port_id');
|
||||
}
|
||||
|
||||
public function ospfPorts()
|
||||
{
|
||||
return $this->hasMany(OspfPort::class, 'port_id');
|
||||
}
|
||||
|
||||
public function pseudowires()
|
||||
{
|
||||
return $this->hasMany(Pseudowire::class, 'port_id');
|
||||
}
|
||||
|
||||
public function statistics()
|
||||
{
|
||||
return $this->hasMany(PortStatistic::class, 'port_id');
|
||||
}
|
||||
|
||||
public function stp()
|
||||
{
|
||||
return $this->hasMany(PortStp::class, 'port_id');
|
||||
}
|
||||
|
||||
public function users()
|
||||
{
|
||||
// FIXME does not include global read
|
||||
return $this->belongsToMany('App\Models\User', 'ports_perms', 'port_id', 'user_id');
|
||||
}
|
||||
|
||||
public function vlans()
|
||||
{
|
||||
return $this->hasMany(PortVlan::class, 'port_id');
|
||||
}
|
||||
}
|
||||
|
10
app/Models/PortAdsl.php
Normal file
10
app/Models/PortAdsl.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class PortAdsl extends PortRelatedModel
|
||||
{
|
||||
protected $table = 'ports_adsl';
|
||||
protected $primaryKey = 'port_id';
|
||||
public $timestamps = false;
|
||||
}
|
10
app/Models/PortStatistic.php
Normal file
10
app/Models/PortStatistic.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class PortStatistic extends PortRelatedModel
|
||||
{
|
||||
protected $table = 'ports_statistics';
|
||||
protected $primaryKey = 'port_id';
|
||||
public $timestamps = false;
|
||||
}
|
10
app/Models/PortStp.php
Normal file
10
app/Models/PortStp.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class PortStp extends PortRelatedModel
|
||||
{
|
||||
protected $table = 'ports_stp';
|
||||
protected $primaryKey = 'port_stp_id';
|
||||
public $timestamps = false;
|
||||
}
|
10
app/Models/PortVlan.php
Normal file
10
app/Models/PortVlan.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class PortVlan extends PortRelatedModel
|
||||
{
|
||||
protected $table = 'ports_vlans';
|
||||
protected $primaryKey = 'port_vlan_id';
|
||||
public $timestamps = false;
|
||||
}
|
11
daily.php
11
daily.php
@@ -135,10 +135,13 @@ if ($options['f'] === 'ports_purge') {
|
||||
$ports_purge = Config::get('ports_purge');
|
||||
|
||||
if ($ports_purge) {
|
||||
$interfaces = dbFetchRows('SELECT * from `ports` AS P, `devices` AS D WHERE `deleted` = 1 AND D.device_id = P.device_id');
|
||||
foreach ($interfaces as $interface) {
|
||||
delete_port($interface['port_id']);
|
||||
}
|
||||
\App\Models\Port::query()->with(['device' => function ($query) {
|
||||
$query->select('device_id', 'hostname');
|
||||
}])->isDeleted()->chunk(100, function ($ports) {
|
||||
foreach ($ports as $port) {
|
||||
$port->delete();
|
||||
}
|
||||
});
|
||||
echo "All deleted ports now purged\n";
|
||||
}
|
||||
} catch (LockException $e) {
|
||||
|
@@ -176,22 +176,6 @@ function print_message($text)
|
||||
}
|
||||
}
|
||||
|
||||
function delete_port($int_id)
|
||||
{
|
||||
$interface = dbFetchRow("SELECT * FROM `ports` AS P, `devices` AS D WHERE P.port_id = ? AND D.device_id = P.device_id", array($int_id));
|
||||
|
||||
$interface_tables = array('ipv4_addresses', 'ipv4_mac', 'ipv6_addresses', 'juniAtmVp', 'mac_accounting', 'ospf_nbrs', 'ospf_ports', 'ports', 'ports_adsl', 'ports_perms', 'ports_statistics', 'ports_stp', 'ports_vlans', 'pseudowires');
|
||||
|
||||
foreach ($interface_tables as $table) {
|
||||
dbDelete($table, "`port_id` = ?", array($int_id));
|
||||
}
|
||||
|
||||
dbDelete('links', "`local_port_id` = ? OR `remote_port_id` = ?", array($int_id, $int_id));
|
||||
dbDelete('ports_stack', "`port_id_low` = ? OR `port_id_high` = ?", array($int_id, $int_id));
|
||||
|
||||
unlink(get_port_rrdfile_path($interface['hostname'], $interface['port_id']));
|
||||
}
|
||||
|
||||
function get_sensor_rrd($device, $sensor)
|
||||
{
|
||||
return rrd_name($device['hostname'], get_sensor_rrd_name($device, $sensor));
|
||||
@@ -209,11 +193,7 @@ function get_sensor_rrd_name($device, $sensor)
|
||||
|
||||
function getPortRrdName($port_id, $suffix = '')
|
||||
{
|
||||
if (!empty($suffix)) {
|
||||
$suffix = '-' . $suffix;
|
||||
}
|
||||
|
||||
return "port-id$port_id$suffix";
|
||||
return Rrd::portName($port_id, $suffix);
|
||||
}
|
||||
|
||||
function get_port_rrdfile_path($hostname, $port_id, $suffix = '')
|
||||
|
@@ -453,12 +453,16 @@ function delete_device($id)
|
||||
dbQuery("DELETE `ipv4_addresses` FROM `ipv4_addresses` INNER JOIN `ports` ON `ports`.`port_id`=`ipv4_addresses`.`port_id` WHERE `device_id`=?", array($id));
|
||||
dbQuery("DELETE `ipv6_addresses` FROM `ipv6_addresses` INNER JOIN `ports` ON `ports`.`port_id`=`ipv6_addresses`.`port_id` WHERE `device_id`=?", array($id));
|
||||
|
||||
foreach (dbFetch("SELECT * FROM `ports` WHERE `device_id` = ?", array($id)) as $int_data) {
|
||||
$int_if = $int_data['ifDescr'];
|
||||
$int_id = $int_data['port_id'];
|
||||
delete_port($int_id);
|
||||
$ret .= "Removed interface $int_id ($int_if)\n";
|
||||
}
|
||||
|
||||
\App\Models\Port::where('device_id', $id)
|
||||
->with('device')
|
||||
->select(['port_id', 'device_id', 'ifIndex', 'ifName', 'ifAlias', 'ifDescr'])
|
||||
->chunk(100, function ($ports) use (&$ret) {
|
||||
foreach ($ports as $port) {
|
||||
$port->delete();
|
||||
$ret .= "Removed interface $port->port_id (" . $port->getLabel() . ")\n";
|
||||
}
|
||||
});
|
||||
|
||||
// Remove sensors manually due to constraints
|
||||
foreach (dbFetchRows("SELECT * FROM `sensors` WHERE `device_id` = ?", array($id)) as $sensor) {
|
||||
|
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
use App\Models\Port;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
$pagetitle[] = "Ports";
|
||||
|
||||
@@ -388,18 +389,18 @@ foreach ($vars as $var => $value) {
|
||||
break;
|
||||
case 'purge':
|
||||
if ($vars['purge'] === 'all') {
|
||||
$interfaces = dbFetchRows('SELECT * from `ports` AS P, `devices` AS D WHERE `deleted` = 1 AND D.device_id = P.device_id');
|
||||
foreach ($interfaces as $interface) {
|
||||
$interface = cleanPort($interface);
|
||||
if (port_permitted($interface['port_id'], $interface['device_id'])) {
|
||||
delete_port($interface['port_id']);
|
||||
Port::hasAccess(Auth::user())->with(['device' => function ($query) {
|
||||
$query->select('device_id', 'hostname');
|
||||
}])->isDeleted()->chunk(100, function ($ports) {
|
||||
foreach ($ports as $port) {
|
||||
$port->delete();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$interface = dbFetchRow('SELECT * from `ports` AS P, `devices` AS D WHERE `port_id` = ? AND D.device_id = P.device_id', array($vars['purge']));
|
||||
$interface = cleanPort($interface);
|
||||
if (port_permitted($interface['port_id'], $interface['device_id'])) {
|
||||
delete_port($interface['port_id']);
|
||||
try {
|
||||
Port::hasAccess(Auth::user())->where('port_id', $vars['purge'])->firstOrFail()->delete();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
echo "<div class='alert alert-danger'>Port ID {$vars['purge']} not found! Could not purge port.</div>";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
foreach (dbFetchRows("SELECT * FROM `ports` WHERE `deleted` = '1'") as $port) {
|
||||
echo "<div style='font-weight: bold;'>Deleting port ".$port['port_id'].' - '.$port['ifDescr'];
|
||||
delete_port($port['port_id']);
|
||||
echo '</div>';
|
||||
}
|
@@ -26,6 +26,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
use App\Models\Port;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
chdir(dirname($argv[0]));
|
||||
|
||||
$init_modules = array();
|
||||
@@ -55,7 +58,11 @@ if (! $port_id && ! $port_id_file || ($port_id && $port_id_file)) {
|
||||
|
||||
// Purge single port
|
||||
if ($port_id) {
|
||||
delete_port($port_id);
|
||||
try {
|
||||
Port::findOrFail($port_id)->delete();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
echo "Port ID $port_id not found!\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Delete multiple ports
|
||||
@@ -72,7 +79,11 @@ if ($port_id_file) {
|
||||
}
|
||||
|
||||
while ($port_id = trim(fgets($fh))) {
|
||||
delete_port($port_id);
|
||||
try {
|
||||
Port::findOrFail($port_id)->delete();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
echo "Port ID $port_id not found!\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($fh != STDIN) {
|
||||
|
Reference in New Issue
Block a user