Files
librenms-librenms/app/Models/Port.php
Tony Murray e08571c38c Transceiver Support (#16165)
* Add transceivers module

Move os specific code to OS

Fix errors and updated connector names

Add RouterOS, a lot less data there.

Add Comware

Add Exa, required a transformer function (mw to dBm)

Add Junos, revision was too short

Just starting on ui

Graphs, and more ui
some polling fixes

collapse header for small screens

refactor a bit

Missed graphs

Transceivers icon inline

Use @once on popup javascript

update db_schema.yaml

Don't show transceivers in basic view
basic view could use a review

Apply fixes from StyleCI

API functions

Comware don't fail if port is missing

Apply fixes from StyleCI

Add alert rules to collection

Device Overview

Attempt to fix bad alert rule, probably needs more

Fix up Comware and remove old sensors

Mark transceiver metrics without thresholds as Unknown

Routeros cleanup

Exa cleanup

Handle missing port

Graph allow filter by channel

More translations

Add transceiver graphs to port graphs

Add Cisco support, use entPhyscial module data if available

Fix OcNos divisors

Labels on transceiver page

Show encoding if available

Hacky OcNos port mapping

Fix up Junos optics and remove old sensors

FS switch support
Metric casts to prevent thrashing
Extra transform_function support

Add link to transceivers page from overview

Change default sort to group by type, then channel
move some code out of overview blade template
Fix bad type ocnos

Apply fixes from StyleCI

Add scales to graphs

Add some test data

Default sort order for metrcis in SQL applied by default

Transceiver metrics threshold manual settings via WebUI and API

Fixes to channels verbiage

Fix severity calculations

Add cable field for SM/MM/Copper

Apply fixes from StyleCI

update test data

Show DDM

Update DB schema file

Extend serial field to 32, even though devices shouldn't be able to have one longer than 16

Missing import

Add status field to database, that way we can support snmp implementations that only return an enum

Add missing files

Fix db_schema

Fix style

Fixes

Style fix

Work around phpstan issue

Update transceivers.blade.php

Missed getStatus() call

Prevent extra dots when channels are not changed

Update module to match upstream

Save ocnos metrics as sensors

Move to regular sensors

add entity physical index

Update UI to sensors WIP

Apply fixes from StyleCI

Forgot one change

Update ui to use sensors

Remove transceiver metrics

Remove metric os discover code
fs-switch pending

Remove transceiver metrics for fs-centec

Exa link up

Revert all test data

Fix up transceiver module interface

Remove unused Convert class

comware cache and transceiver type

Fix some transceiver metrics filtering and formatting issues

Consolidate display formatting

Coalesce commare hh3cTransceiverTable walks to prevent double walk

Use group to identify transceiver sensors

Fixup routeros

Fix up cisco

update db_schema

Small addition to docs

Improve overview layout and add graph popup

Update Junos

update css files

ddm should be nullable

Increase the field length for type and model

Cisco Improve detection when there is an intermediary container

Add transceiver test data

Apply fixes from StyleCI

Fix incorrect test data

Improve display formatting

Fix test data

Apply fixes from StyleCI

Fix up more data

Fix up more data

Fix incorrect return type in routeros

Update ocnos data

* Remove some remaining references to transceiver_metrics table
2024-09-29 11:05:44 -05:00

417 lines
11 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use LibreNMS\Util\Rewrite;
use Permissions;
class Port extends DeviceRelatedModel
{
use HasFactory;
public $timestamps = false;
protected $primaryKey = 'port_id';
/**
* Initialize this class
*/
public static function boot()
{
parent::boot();
static::deleting(function (Port $port) {
// delete related data
$port->adsl()->delete();
$port->vdsl()->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();
$port->links()->delete();
$port->remoteLinks()->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('ports_stack')->where('low_port_id', $port->port_id)->orWhere('high_port_id', $port->port_id)->delete();
\Rrd::purge($port->device?->hostname, \Rrd::portName($port->port_id)); // purge all port rrd files
});
}
// ---- Helper Functions ----
/**
* Returns a human readable label for this port
*
* @return string
*/
public function getLabel()
{
$os = $this->device?->os;
if (\LibreNMS\Config::getOsSetting($os, 'ifname')) {
$label = $this->ifName;
} elseif (\LibreNMS\Config::getOsSetting($os, 'ifalias')) {
$label = $this->ifAlias;
}
if (empty($label)) {
$label = $this->ifDescr;
if (\LibreNMS\Config::getOsSetting($os, 'ifindex')) {
$label .= " $this->ifIndex";
}
}
foreach ((array) \LibreNMS\Config::get('rewrite_if', []) as $src => $val) {
if (Str::contains(strtolower($label), strtolower($src))) {
$label = $val;
}
}
foreach ((array) \LibreNMS\Config::get('rewrite_if_regexp', []) as $reg => $val) {
$label = preg_replace($reg . 'i', $val, $label);
}
return $label;
}
/**
* Get the shortened label for this device. Replaces things like GigabitEthernet with GE.
*
* @return string
*/
public function getShortLabel()
{
return Rewrite::shortenIfName(Rewrite::normalizeIfName($this->ifName ?: $this->ifDescr));
}
/**
* Get the description of this port
*/
public function getDescription(): string
{
return (string) $this->ifAlias;
}
/**
* Check if user can access this port.
*
* @param User|int $user
* @return bool
*/
public function canAccess($user)
{
if (! $user) {
return false;
}
if ($user->hasGlobalRead()) {
return true;
}
return Permissions::canAccessDevice($this->device_id, $user) || Permissions::canAccessPort($this->port_id, $user);
}
// ---- Accessors/Mutators ----
public function getIfPhysAddressAttribute($mac)
{
if (! empty($mac)) {
return preg_replace('/(..)(..)(..)(..)(..)(..)/', '\\1:\\2:\\3:\\4:\\5:\\6', $mac);
}
return null;
}
// ---- Query scopes ----
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsDeleted($query)
{
return $query->where([
['deleted', 1],
]);
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsNotDeleted($query)
{
return $query->where([
['deleted', 0],
]);
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsUp($query)
{
return $query->where([
['deleted', '=', 0],
['ignore', '=', 0],
['disabled', '=', 0],
['ifOperStatus', '=', 'up'],
]);
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsDown($query)
{
return $query->where([
['deleted', '=', 0],
['ignore', '=', 0],
['disabled', '=', 0],
['ifOperStatus', '!=', 'up'],
['ifAdminStatus', '=', 'up'],
]);
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsShutdown($query)
{
return $query->where([
['deleted', '=', 0],
['ignore', '=', 0],
['disabled', '=', 0],
['ifAdminStatus', '=', 'down'],
]);
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsIgnored($query)
{
return $query->where([
['deleted', '=', 0],
['ignore', '=', 1],
]);
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsDisabled($query)
{
return $query->where([
['deleted', '=', 0],
['disabled', '=', 1],
]);
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeHasErrors($query)
{
return $query->where([
['deleted', '=', 0],
['ignore', '=', 0],
['disabled', '=', 0],
])->where(function ($query) {
/** @var Builder $query */
$query->where('ifInErrors_delta', '>', 0)
->orWhere('ifOutErrors_delta', '>', 0);
});
}
/**
* @param Builder $query
* @return Builder
*/
public function scopeIsValid($query)
{
return $query->where([
['deleted', '=', 0],
['disabled', '=', 0],
]);
}
public function scopeHasAccess($query, User $user)
{
return $this->hasPortAccess($query, $user);
}
public function scopeInPortGroup($query, $portGroup)
{
return $query->whereIn($query->qualifyColumn('port_id'), function ($query) use ($portGroup) {
$query->select('port_id')
->from('port_group_port')
->where('port_group_id', $portGroup);
});
}
// ---- Define Relationships ----
public function adsl(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(PortAdsl::class, 'port_id');
}
public function vdsl(): \Illuminate\Database\Eloquent\Relations\HasOne
{
return $this->hasOne(PortVdsl::class, 'port_id');
}
public function events(): MorphMany
{
return $this->morphMany(Eventlog::class, 'events', 'type', 'reference');
}
public function fdbEntries(): HasMany
{
return $this->hasMany(\App\Models\PortsFdb::class, 'port_id', 'port_id');
}
public function groups(): BelongsToMany
{
return $this->belongsToMany(\App\Models\PortGroup::class, 'port_group_port', 'port_id', 'port_group_id');
}
public function ipv4(): HasMany
{
return $this->hasMany(Ipv4Address::class, 'port_id');
}
public function ipv4Networks(): HasManyThrough
{
return $this->hasManyThrough(Ipv4Network::class, Ipv4Address::class, 'port_id', 'ipv4_network_id', 'port_id', 'ipv4_network_id');
}
public function ipv6(): HasMany
{
return $this->hasMany(Ipv6Address::class, 'port_id');
}
public function ipv6Networks(): HasManyThrough
{
return $this->hasManyThrough(Ipv6Network::class, Ipv6Address::class, 'port_id', 'ipv6_network_id', 'port_id', 'ipv6_network_id');
}
public function links(): HasMany
{
return $this->hasMany(\App\Models\Link::class, 'local_port_id');
}
public function remoteLinks(): HasMany
{
return $this->hasMany(\App\Models\Link::class, 'remote_port_id');
}
public function allLinks(): \Illuminate\Support\Collection
{
return $this->links->merge($this->remoteLinks);
}
public function macAccounting(): HasMany
{
return $this->hasMany(MacAccounting::class, 'port_id');
}
public function macs(): HasMany
{
return $this->hasMany(Ipv4Mac::class, 'port_id');
}
public function nac(): HasMany
{
return $this->hasMany(PortsNac::class, 'port_id');
}
public function ospfNeighbors(): HasMany
{
return $this->hasMany(OspfNbr::class, 'port_id');
}
public function ospfPorts(): HasMany
{
return $this->hasMany(OspfPort::class, 'port_id');
}
public function pagpParent(): BelongsTo
{
return $this->belongsTo(Port::class, 'pagpGroupIfIndex', 'ifIndex');
}
public function pseudowires(): HasMany
{
return $this->hasMany(Pseudowire::class, 'port_id');
}
public function stackChildren(): HasManyThrough
{
return $this->hasManyThrough(Port::class, PortStack::class, 'low_port_id', 'port_id', 'port_id', 'high_port_id');
}
public function stackParent(): HasManyThrough
{
return $this->hasManyThrough(Port::class, PortStack::class, 'high_port_id', 'port_id', 'port_id', 'low_port_id');
}
public function statistics(): HasMany
{
return $this->hasMany(PortStatistic::class, 'port_id');
}
public function stp(): HasMany
{
return $this->hasMany(PortStp::class, 'port_id');
}
public function transceivers(): HasMany
{
return $this->hasMany(Transceiver::class, 'port_id');
}
public function users(): BelongsToMany
{
// FIXME does not include global read
return $this->belongsToMany(\App\Models\User::class, 'ports_perms', 'port_id', 'user_id');
}
public function vlans(): HasMany
{
return $this->hasMany(PortVlan::class, 'port_id');
}
public function vrf()
{
return $this->hasOne(Vrf::class, 'vrf_id', 'ifVrf');
}
}