2018-05-09 08:05:17 -05:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Models;
|
|
|
|
|
2021-11-18 15:46:22 -06:00
|
|
|
use App\View\SimpleTemplate;
|
2018-07-30 16:58:38 -05:00
|
|
|
use Fico7489\Laravel\Pivot\Traits\PivotEventTrait;
|
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
2020-11-03 17:18:31 +01:00
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
2018-09-21 10:08:17 -05:00
|
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
2021-03-30 11:14:34 +02:00
|
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
|
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
2021-10-03 01:03:24 +02:00
|
|
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
2021-03-30 11:14:34 +02:00
|
|
|
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
2018-07-30 16:58:38 -05:00
|
|
|
use Illuminate\Database\Query\JoinClause;
|
2023-04-10 15:26:26 -03:00
|
|
|
use Illuminate\Support\Arr;
|
2019-03-01 23:06:01 -06:00
|
|
|
use Illuminate\Support\Str;
|
2018-08-11 23:37:45 +02:00
|
|
|
use LibreNMS\Exceptions\InvalidIpException;
|
2018-08-14 01:56:16 -05:00
|
|
|
use LibreNMS\Util\IP;
|
2018-08-11 23:37:45 +02:00
|
|
|
use LibreNMS\Util\IPv4;
|
|
|
|
use LibreNMS\Util\IPv6;
|
Implement OS specific information discovery (#11446)
* Implement OS specific information discovery
That way it doesn't have to be fetched during polling
Also improve discovery process, os is only detected once, in the core module.
EXA is the test os, a couple improvements there.
* Use local variable, then unset it so we don't pollute.
* fix style issues
* test and other fixes
* attribute update fixes
* Update exa data, need new source data
* null missing "os" values
* fix ftos odd character
* fix ftos odd character
* only null for new style or we will reset to null every discovery
* Move device observer to own class
* Handle location, relocate event logging
* update exa e7-2 data
* update ird test data, apparently unicode is now working.
* update Linux ntc, now uses correct icon
* Only load all os on the web, also, we can't load existing the the database isn't connected.
* only for devices that have a location
* revert ftos test data apparently
* revert ird
2020-05-14 11:27:59 -05:00
|
|
|
use LibreNMS\Util\Rewrite;
|
2019-03-18 03:09:58 +01:00
|
|
|
use LibreNMS\Util\Time;
|
Implement OS specific information discovery (#11446)
* Implement OS specific information discovery
That way it doesn't have to be fetched during polling
Also improve discovery process, os is only detected once, in the core module.
EXA is the test os, a couple improvements there.
* Use local variable, then unset it so we don't pollute.
* fix style issues
* test and other fixes
* attribute update fixes
* Update exa data, need new source data
* null missing "os" values
* fix ftos odd character
* fix ftos odd character
* only null for new style or we will reset to null every discovery
* Move device observer to own class
* Handle location, relocate event logging
* update exa e7-2 data
* update ird test data, apparently unicode is now working.
* update Linux ntc, now uses correct icon
* Only load all os on the web, also, we can't load existing the the database isn't connected.
* only for devices that have a location
* revert ftos test data apparently
* revert ird
2020-05-14 11:27:59 -05:00
|
|
|
use LibreNMS\Util\Url;
|
2019-12-30 12:11:26 +01:00
|
|
|
use Permissions;
|
2018-07-30 16:58:38 -05:00
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
/**
|
|
|
|
* @property-read int|null $ports_count
|
|
|
|
* @property-read int|null $sensors_count
|
|
|
|
* @property-read int|null $wirelessSensors_count
|
2021-09-10 20:09:53 +02:00
|
|
|
*
|
2021-04-01 00:35:19 +02:00
|
|
|
* @method static \Database\Factories\DeviceFactory factory(...$parameters)
|
2021-03-30 11:14:34 +02:00
|
|
|
*/
|
2018-05-09 08:05:17 -05:00
|
|
|
class Device extends BaseModel
|
|
|
|
{
|
2020-11-03 17:18:31 +01:00
|
|
|
use PivotEventTrait, HasFactory;
|
2018-07-30 16:58:38 -05:00
|
|
|
|
2018-05-09 08:05:17 -05:00
|
|
|
public $timestamps = false;
|
|
|
|
protected $primaryKey = 'device_id';
|
2021-10-01 20:04:42 +01:00
|
|
|
protected $fillable = [
|
2021-10-19 15:43:43 -05:00
|
|
|
'authalgo',
|
|
|
|
'authlevel',
|
|
|
|
'authname',
|
|
|
|
'authpass',
|
|
|
|
'community',
|
|
|
|
'cryptoalgo',
|
|
|
|
'cryptopass',
|
2022-11-16 15:12:37 +01:00
|
|
|
'disable_notify',
|
2023-04-19 16:50:42 +02:00
|
|
|
'disabled',
|
2021-10-19 15:43:43 -05:00
|
|
|
'features',
|
|
|
|
'hardware',
|
2021-10-01 20:04:42 +01:00
|
|
|
'hostname',
|
2021-11-18 15:46:22 -06:00
|
|
|
'display',
|
2021-10-19 15:43:43 -05:00
|
|
|
'icon',
|
2023-04-21 15:38:58 -05:00
|
|
|
'ignore',
|
2021-10-01 20:04:42 +01:00
|
|
|
'ip',
|
2022-11-16 15:12:37 +01:00
|
|
|
'location_id',
|
2022-10-23 04:45:47 +08:00
|
|
|
'notes',
|
2021-10-19 15:43:43 -05:00
|
|
|
'os',
|
2022-11-08 11:22:37 -06:00
|
|
|
'override_sysLocation',
|
2021-10-19 15:43:43 -05:00
|
|
|
'overwrite_ip',
|
|
|
|
'poller_group',
|
|
|
|
'port',
|
|
|
|
'port_association_mode',
|
2022-11-08 11:22:37 -06:00
|
|
|
'purpose',
|
2021-10-19 15:43:43 -05:00
|
|
|
'retries',
|
|
|
|
'serial',
|
|
|
|
'snmp_disable',
|
|
|
|
'snmp_max_repeaters',
|
|
|
|
'snmpver',
|
2021-10-01 20:04:42 +01:00
|
|
|
'status',
|
|
|
|
'status_reason',
|
|
|
|
'sysDescr',
|
2021-10-19 15:43:43 -05:00
|
|
|
'sysName',
|
2021-10-01 20:04:42 +01:00
|
|
|
'sysObjectID',
|
2021-10-19 15:43:43 -05:00
|
|
|
'timeout',
|
2021-10-01 20:04:42 +01:00
|
|
|
'transport',
|
2021-10-19 15:43:43 -05:00
|
|
|
'version',
|
2021-10-20 02:08:10 +02:00
|
|
|
'uptime',
|
2021-10-01 20:04:42 +01:00
|
|
|
];
|
|
|
|
|
2019-03-18 03:09:58 +01:00
|
|
|
protected $casts = [
|
|
|
|
'last_polled' => 'datetime',
|
|
|
|
'status' => 'boolean',
|
|
|
|
];
|
2018-05-09 08:05:17 -05:00
|
|
|
|
|
|
|
// ---- Helper Functions ----
|
|
|
|
|
2022-03-12 16:14:32 -06:00
|
|
|
public static function findByHostname(string $hostname): ?Device
|
2018-08-11 23:37:45 +02:00
|
|
|
{
|
|
|
|
return static::where('hostname', $hostname)->first();
|
|
|
|
}
|
|
|
|
|
2020-01-30 13:20:30 +01:00
|
|
|
/**
|
|
|
|
* Returns IP/Hostname where polling will be targeted to
|
|
|
|
*
|
2021-09-08 23:35:56 +02:00
|
|
|
* @param string|array $device hostname which will be triggered
|
|
|
|
* array $device associative array with device data
|
2020-01-30 13:20:30 +01:00
|
|
|
* @return string IP/Hostname to which Device polling is targeted
|
|
|
|
*/
|
2020-02-18 13:26:41 +01:00
|
|
|
public static function pollerTarget($device)
|
2020-01-30 13:20:30 +01:00
|
|
|
{
|
2020-05-21 15:15:39 -05:00
|
|
|
if (! is_array($device)) {
|
2020-02-18 13:26:41 +01:00
|
|
|
$ret = static::where('hostname', $device)->first(['hostname', 'overwrite_ip']);
|
|
|
|
if (empty($ret)) {
|
|
|
|
return $device;
|
|
|
|
}
|
|
|
|
$overwrite_ip = $ret->overwrite_ip;
|
|
|
|
$hostname = $ret->hostname;
|
|
|
|
} elseif (array_key_exists('overwrite_ip', $device)) {
|
|
|
|
$overwrite_ip = $device['overwrite_ip'];
|
|
|
|
$hostname = $device['hostname'];
|
|
|
|
} else {
|
|
|
|
return $device['hostname'];
|
2020-01-30 13:20:30 +01:00
|
|
|
}
|
2020-09-21 14:54:51 +02:00
|
|
|
|
2020-02-18 13:26:41 +01:00
|
|
|
return $overwrite_ip ?: $hostname;
|
2020-01-30 13:20:30 +01:00
|
|
|
}
|
|
|
|
|
2022-03-12 16:14:32 -06:00
|
|
|
public static function findByIp(?string $ip): ?Device
|
2018-08-11 23:37:45 +02:00
|
|
|
{
|
2018-08-14 01:56:16 -05:00
|
|
|
if (! IP::isValid($ip)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2018-08-11 23:37:45 +02:00
|
|
|
$device = static::where('hostname', $ip)->orWhere('ip', inet_pton($ip))->first();
|
|
|
|
|
|
|
|
if ($device) {
|
|
|
|
return $device;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
$ipv4 = new IPv4($ip);
|
2018-08-14 01:56:16 -05:00
|
|
|
$port = Ipv4Address::where('ipv4_address', (string) $ipv4)
|
2018-08-11 23:37:45 +02:00
|
|
|
->with('port', 'port.device')
|
2018-08-14 01:56:16 -05:00
|
|
|
->firstOrFail()->port;
|
|
|
|
if ($port) {
|
|
|
|
return $port->device;
|
|
|
|
}
|
2018-08-11 23:37:45 +02:00
|
|
|
} catch (InvalidIpException $e) {
|
|
|
|
//
|
|
|
|
} catch (ModelNotFoundException $e) {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
$ipv6 = new IPv6($ip);
|
2018-08-14 01:56:16 -05:00
|
|
|
$port = Ipv6Address::where('ipv6_address', $ipv6->uncompressed())
|
2018-08-11 23:37:45 +02:00
|
|
|
->with(['port', 'port.device'])
|
2018-08-14 01:56:16 -05:00
|
|
|
->firstOrFail()->port;
|
|
|
|
if ($port) {
|
|
|
|
return $port->device;
|
|
|
|
}
|
2018-08-11 23:37:45 +02:00
|
|
|
} catch (InvalidIpException $e) {
|
|
|
|
//
|
|
|
|
} catch (ModelNotFoundException $e) {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-08-23 01:22:28 -05:00
|
|
|
/**
|
|
|
|
* Get VRF contexts to poll.
|
|
|
|
* If no contexts are found, return the default context ''
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getVrfContexts(): array
|
|
|
|
{
|
|
|
|
return $this->vrfLites->isEmpty() ? [''] : $this->vrfLites->pluck('context_name')->all();
|
|
|
|
}
|
|
|
|
|
2018-09-11 07:51:35 -05:00
|
|
|
/**
|
2021-11-18 15:46:22 -06:00
|
|
|
* Get the display name of this device based on the display format string
|
|
|
|
* The default is {{ $hostname }} controlled by the device_display_default setting
|
2018-09-11 07:51:35 -05:00
|
|
|
*/
|
2021-11-18 15:46:22 -06:00
|
|
|
public function displayName(): string
|
2018-09-11 07:51:35 -05:00
|
|
|
{
|
2021-11-18 15:46:22 -06:00
|
|
|
$hostname_is_ip = IP::isValid($this->hostname);
|
|
|
|
|
|
|
|
return SimpleTemplate::parse($this->display ?: \LibreNMS\Config::get('device_display_default', '{{ $hostname }}'), [
|
|
|
|
'hostname' => $this->hostname,
|
|
|
|
'sysName' => $this->sysName ?: $this->hostname,
|
|
|
|
'sysName_fallback' => $hostname_is_ip ? $this->sysName : $this->hostname,
|
|
|
|
'ip' => $this->overwrite_ip ?: ($hostname_is_ip ? $this->hostname : $this->ip),
|
|
|
|
]);
|
2018-09-11 07:51:35 -05:00
|
|
|
}
|
|
|
|
|
2021-11-18 15:46:22 -06:00
|
|
|
/**
|
|
|
|
* Returns the device name if not already displayed
|
|
|
|
*/
|
|
|
|
public function name(): string
|
2019-01-25 15:31:33 -06:00
|
|
|
{
|
2021-11-18 15:46:22 -06:00
|
|
|
$display = $this->displayName();
|
|
|
|
|
|
|
|
if (! Str::contains($display, $this->hostname)) {
|
2021-11-19 12:21:56 -06:00
|
|
|
return (string) $this->hostname;
|
2021-11-18 15:46:22 -06:00
|
|
|
} elseif (! Str::contains($display, $this->sysName)) {
|
2021-11-19 12:21:56 -06:00
|
|
|
return (string) $this->sysName;
|
2019-01-25 15:31:33 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
2019-01-03 16:42:12 -06:00
|
|
|
public function isUnderMaintenance()
|
|
|
|
{
|
2020-06-14 12:39:10 -05:00
|
|
|
if (! $this->device_id) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-03 16:42:12 -06:00
|
|
|
$query = AlertSchedule::isActive()
|
2020-06-14 12:39:10 -05:00
|
|
|
->where(function (Builder $query) {
|
|
|
|
$query->whereHas('devices', function (Builder $query) {
|
|
|
|
$query->where('alert_schedulables.alert_schedulable_id', $this->device_id);
|
2019-01-03 16:42:12 -06:00
|
|
|
});
|
|
|
|
|
2021-04-20 12:47:22 +02:00
|
|
|
if ($this->groups->isNotEmpty()) {
|
2020-06-14 12:39:10 -05:00
|
|
|
$query->orWhereHas('deviceGroups', function (Builder $query) {
|
2022-05-16 02:57:58 -05:00
|
|
|
$query->whereIntegerInRaw('alert_schedulables.alert_schedulable_id', $this->groups->pluck('id'));
|
2019-01-03 16:42:12 -06:00
|
|
|
});
|
|
|
|
}
|
2020-02-03 18:26:08 +01:00
|
|
|
|
|
|
|
if ($this->location) {
|
2020-06-14 12:39:10 -05:00
|
|
|
$query->orWhereHas('locations', function (Builder $query) {
|
|
|
|
$query->where('alert_schedulables.alert_schedulable_id', $this->location->id);
|
2020-02-03 18:26:08 +01:00
|
|
|
});
|
|
|
|
}
|
2019-01-03 16:42:12 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
return $query->exists();
|
|
|
|
}
|
|
|
|
|
2018-09-20 15:33:03 -05:00
|
|
|
/**
|
|
|
|
* Get the shortened display name of this device.
|
|
|
|
* Length is always overridden by shorthost_target_length.
|
|
|
|
*
|
2021-09-08 23:35:56 +02:00
|
|
|
* @param int $length length to shorten to, will not break up words so may be longer
|
2018-09-20 15:33:03 -05:00
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function shortDisplayName($length = 12)
|
|
|
|
{
|
|
|
|
$name = $this->displayName();
|
|
|
|
|
|
|
|
// IP addresses should not be shortened
|
|
|
|
if (IP::isValid($name)) {
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
|
2018-09-21 10:08:17 -05:00
|
|
|
$length = \LibreNMS\Config::get('shorthost_target_length', $length);
|
2018-09-20 15:33:03 -05:00
|
|
|
if ($length < strlen($name)) {
|
2022-03-12 16:14:09 -06:00
|
|
|
$take = max(substr_count($name, '.', 0, $length), 1);
|
2020-09-21 14:54:51 +02:00
|
|
|
|
2018-09-20 15:33:03 -05:00
|
|
|
return implode('.', array_slice(explode('.', $name), 0, $take));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
|
2018-09-24 02:07:00 -05:00
|
|
|
/**
|
|
|
|
* Check if user can access this device.
|
|
|
|
*
|
2021-09-08 23:35:56 +02:00
|
|
|
* @param User $user
|
2018-09-24 02:07:00 -05:00
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function canAccess($user)
|
|
|
|
{
|
|
|
|
if (! $user) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($user->hasGlobalRead()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-30 12:11:26 +01:00
|
|
|
return Permissions::canAccessDevice($this->device_id, $user->user_id);
|
2018-09-24 02:07:00 -05:00
|
|
|
}
|
|
|
|
|
2020-06-15 23:53:48 +02:00
|
|
|
public function formatDownUptime($short = false)
|
2018-09-11 07:51:35 -05:00
|
|
|
{
|
2020-06-15 23:53:48 +02:00
|
|
|
$time = ($this->status == 1) ? $this->uptime : time() - strtotime($this->last_polled);
|
2020-09-21 14:54:51 +02:00
|
|
|
|
2020-06-15 23:53:48 +02:00
|
|
|
return Time::formatInterval($time, $short);
|
2018-09-11 07:51:35 -05:00
|
|
|
}
|
|
|
|
|
2018-05-09 08:05:17 -05:00
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function logo()
|
|
|
|
{
|
|
|
|
$base_name = pathinfo($this->icon, PATHINFO_FILENAME);
|
|
|
|
$options = [
|
|
|
|
"images/logos/$base_name.svg",
|
|
|
|
"images/logos/$base_name.png",
|
|
|
|
"images/os/$base_name.svg",
|
|
|
|
"images/os/$base_name.png",
|
|
|
|
];
|
|
|
|
|
|
|
|
foreach ($options as $file) {
|
2020-05-21 15:15:39 -05:00
|
|
|
if (is_file(public_path() . "/$file")) {
|
2018-05-09 08:05:17 -05:00
|
|
|
return asset($file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return asset('images/os/generic.svg');
|
|
|
|
}
|
|
|
|
|
2018-07-30 16:58:38 -05:00
|
|
|
/**
|
|
|
|
* Update the max_depth field based on parents
|
|
|
|
* Performs SQL query, so make sure all parents are saved first
|
|
|
|
*
|
2021-09-08 23:35:56 +02:00
|
|
|
* @param int $exclude exclude a device_id from being considered (used for deleting)
|
2018-07-30 16:58:38 -05:00
|
|
|
*/
|
|
|
|
public function updateMaxDepth($exclude = null)
|
|
|
|
{
|
|
|
|
// optimize for memory instead of time
|
|
|
|
$query = $this->parents()->getQuery();
|
|
|
|
if (! is_null($exclude)) {
|
|
|
|
$query->where('device_id', '!=', $exclude);
|
|
|
|
}
|
|
|
|
|
|
|
|
$count = $query->count();
|
|
|
|
if ($count === 0) {
|
|
|
|
if ($this->children()->count() === 0) {
|
|
|
|
$this->max_depth = 0; // no children or parents
|
|
|
|
} else {
|
|
|
|
$this->max_depth = 1; // has children
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$parents_max_depth = $query->max('max_depth');
|
|
|
|
$this->max_depth = $parents_max_depth + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->save();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Device dependency check to see if this node is standalone or not.
|
|
|
|
* Standalone is a special case where the device has no parents or children and is denoted by a max_depth of 0
|
|
|
|
*
|
|
|
|
* Only checks on root nodes (where max_depth is 1 or 0)
|
|
|
|
*/
|
|
|
|
public function validateStandalone()
|
|
|
|
{
|
|
|
|
if ($this->max_depth === 0 && $this->children()->count() > 0) {
|
2020-05-21 15:15:39 -05:00
|
|
|
$this->max_depth = 1; // has children
|
2018-07-30 16:58:38 -05:00
|
|
|
} elseif ($this->max_depth === 1 && $this->parents()->count() === 0) {
|
2020-05-21 15:15:39 -05:00
|
|
|
$this->max_depth = 0; // no children or parents
|
2018-07-30 16:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
$this->save();
|
|
|
|
}
|
|
|
|
|
2019-11-14 21:56:06 +00:00
|
|
|
public function getAttrib($name)
|
|
|
|
{
|
|
|
|
return $this->attribs->pluck('attrib_value', 'attrib_type')->get($name);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setAttrib($name, $value)
|
|
|
|
{
|
|
|
|
$attrib = $this->attribs->first(function ($item) use ($name) {
|
|
|
|
return $item->attrib_type === $name;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (! $attrib) {
|
|
|
|
$attrib = new DeviceAttrib(['attrib_type' => $name]);
|
|
|
|
$this->attribs->push($attrib);
|
|
|
|
}
|
|
|
|
|
|
|
|
$attrib->attrib_value = $value;
|
2020-09-21 14:54:51 +02:00
|
|
|
|
2020-05-21 15:15:39 -05:00
|
|
|
return (bool) $this->attribs()->save($attrib);
|
2019-11-14 21:56:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function forgetAttrib($name)
|
|
|
|
{
|
|
|
|
$attrib_index = $this->attribs->search(function ($attrib) use ($name) {
|
|
|
|
return $attrib->attrib_type === $name;
|
|
|
|
});
|
|
|
|
|
|
|
|
if ($attrib_index !== false) {
|
2020-05-21 15:15:39 -05:00
|
|
|
$deleted = (bool) $this->attribs->get($attrib_index)->delete();
|
2020-01-23 16:48:14 -05:00
|
|
|
// only forget the attrib_index after delete, otherwise delete() will fail fatally with:
|
|
|
|
// Symfony\\Component\\Debug\Exception\\FatalThrowableError(code: 0): Call to a member function delete() on null
|
2021-04-20 12:47:22 +02:00
|
|
|
$this->attribs->forget((string) $attrib_index);
|
2020-09-21 14:54:51 +02:00
|
|
|
|
2020-01-23 16:48:14 -05:00
|
|
|
return $deleted;
|
2019-11-14 21:56:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getAttribs()
|
|
|
|
{
|
|
|
|
return $this->attribs->pluck('attrib_value', 'attrib_type')->toArray();
|
|
|
|
}
|
|
|
|
|
2021-02-14 20:36:55 -06:00
|
|
|
/**
|
|
|
|
* Update the location to the correct location and update GPS if needed
|
|
|
|
*
|
2021-02-22 11:17:40 +01:00
|
|
|
* @param \App\Models\Location|string $new_location location data
|
2021-09-08 23:35:56 +02:00
|
|
|
* @param bool $doLookup try to lookup the GPS coordinates
|
2021-02-14 20:36:55 -06:00
|
|
|
*/
|
2021-03-24 15:13:43 +01:00
|
|
|
public function setLocation($new_location, bool $doLookup = false)
|
Implement OS specific information discovery (#11446)
* Implement OS specific information discovery
That way it doesn't have to be fetched during polling
Also improve discovery process, os is only detected once, in the core module.
EXA is the test os, a couple improvements there.
* Use local variable, then unset it so we don't pollute.
* fix style issues
* test and other fixes
* attribute update fixes
* Update exa data, need new source data
* null missing "os" values
* fix ftos odd character
* fix ftos odd character
* only null for new style or we will reset to null every discovery
* Move device observer to own class
* Handle location, relocate event logging
* update exa e7-2 data
* update ird test data, apparently unicode is now working.
* update Linux ntc, now uses correct icon
* Only load all os on the web, also, we can't load existing the the database isn't connected.
* only for devices that have a location
* revert ftos test data apparently
* revert ird
2020-05-14 11:27:59 -05:00
|
|
|
{
|
2021-02-22 11:17:40 +01:00
|
|
|
$new_location = $new_location instanceof Location ? $new_location : new Location(['location' => $new_location]);
|
|
|
|
$new_location->location = $new_location->location ? Rewrite::location($new_location->location) : null;
|
|
|
|
$coord = array_filter($new_location->only(['lat', 'lng']));
|
Implement OS specific information discovery (#11446)
* Implement OS specific information discovery
That way it doesn't have to be fetched during polling
Also improve discovery process, os is only detected once, in the core module.
EXA is the test os, a couple improvements there.
* Use local variable, then unset it so we don't pollute.
* fix style issues
* test and other fixes
* attribute update fixes
* Update exa data, need new source data
* null missing "os" values
* fix ftos odd character
* fix ftos odd character
* only null for new style or we will reset to null every discovery
* Move device observer to own class
* Handle location, relocate event logging
* update exa e7-2 data
* update ird test data, apparently unicode is now working.
* update Linux ntc, now uses correct icon
* Only load all os on the web, also, we can't load existing the the database isn't connected.
* only for devices that have a location
* revert ftos test data apparently
* revert ird
2020-05-14 11:27:59 -05:00
|
|
|
|
2021-02-22 11:17:40 +01:00
|
|
|
if (! $this->override_sysLocation) {
|
|
|
|
if (! $new_location->location) { // disassociate if the location name is empty
|
|
|
|
$this->location()->dissociate();
|
2021-02-14 20:36:55 -06:00
|
|
|
|
2021-02-22 11:17:40 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-02-14 20:36:55 -06:00
|
|
|
|
2023-04-17 13:51:35 +02:00
|
|
|
if (! $this->relationLoaded('location') || $this->location?->location !== $new_location->location) {
|
2021-02-22 11:17:40 +01:00
|
|
|
if (! $new_location->exists) { // don't fetch if new location persisted to the DB, just use it
|
|
|
|
$new_location = Location::firstOrCreate(['location' => $new_location->location], $coord);
|
|
|
|
}
|
|
|
|
$this->location()->associate($new_location);
|
2021-02-14 20:36:55 -06:00
|
|
|
}
|
Implement OS specific information discovery (#11446)
* Implement OS specific information discovery
That way it doesn't have to be fetched during polling
Also improve discovery process, os is only detected once, in the core module.
EXA is the test os, a couple improvements there.
* Use local variable, then unset it so we don't pollute.
* fix style issues
* test and other fixes
* attribute update fixes
* Update exa data, need new source data
* null missing "os" values
* fix ftos odd character
* fix ftos odd character
* only null for new style or we will reset to null every discovery
* Move device observer to own class
* Handle location, relocate event logging
* update exa e7-2 data
* update ird test data, apparently unicode is now working.
* update Linux ntc, now uses correct icon
* Only load all os on the web, also, we can't load existing the the database isn't connected.
* only for devices that have a location
* revert ftos test data apparently
* revert ird
2020-05-14 11:27:59 -05:00
|
|
|
}
|
2021-02-14 20:36:55 -06:00
|
|
|
|
2021-02-22 11:17:40 +01:00
|
|
|
// set coordinates
|
|
|
|
if ($this->location && ! $this->location->fixed_coordinates) {
|
|
|
|
$this->location->fill($coord);
|
|
|
|
if ($doLookup && empty($coord)) { // only if requested and coordinates not passed explicitly
|
|
|
|
$this->location->lookupCoordinates($this->hostname);
|
|
|
|
}
|
2021-02-14 20:36:55 -06:00
|
|
|
}
|
Implement OS specific information discovery (#11446)
* Implement OS specific information discovery
That way it doesn't have to be fetched during polling
Also improve discovery process, os is only detected once, in the core module.
EXA is the test os, a couple improvements there.
* Use local variable, then unset it so we don't pollute.
* fix style issues
* test and other fixes
* attribute update fixes
* Update exa data, need new source data
* null missing "os" values
* fix ftos odd character
* fix ftos odd character
* only null for new style or we will reset to null every discovery
* Move device observer to own class
* Handle location, relocate event logging
* update exa e7-2 data
* update ird test data, apparently unicode is now working.
* update Linux ntc, now uses correct icon
* Only load all os on the web, also, we can't load existing the the database isn't connected.
* only for devices that have a location
* revert ftos test data apparently
* revert ird
2020-05-14 11:27:59 -05:00
|
|
|
}
|
|
|
|
|
2018-05-09 08:05:17 -05:00
|
|
|
// ---- Accessors/Mutators ----
|
2018-09-11 07:51:35 -05:00
|
|
|
|
2021-11-10 20:48:22 -06:00
|
|
|
public function getIconAttribute($icon): string
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2019-03-01 23:06:01 -06:00
|
|
|
return Str::start(Url::findOsImage($this->os, $this->features, $icon), 'images/os/');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
2019-03-01 23:06:01 -06:00
|
|
|
|
2021-11-10 20:48:22 -06:00
|
|
|
public function getIpAttribute($ip): ?string
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
|
|
|
if (empty($ip)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
// @ suppresses warning, inet_ntop() returns false if it fails
|
|
|
|
return @inet_ntop($ip) ?: null;
|
|
|
|
}
|
|
|
|
|
2021-11-10 20:48:22 -06:00
|
|
|
public function setIpAttribute($ip): void
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
|
|
|
$this->attributes['ip'] = inet_pton($ip);
|
|
|
|
}
|
|
|
|
|
2021-11-10 20:48:22 -06:00
|
|
|
public function setStatusAttribute($status): void
|
2018-07-30 16:58:38 -05:00
|
|
|
{
|
2020-05-21 15:15:39 -05:00
|
|
|
$this->attributes['status'] = (int) $status;
|
2018-07-30 16:58:38 -05:00
|
|
|
}
|
|
|
|
|
2021-11-10 20:48:22 -06:00
|
|
|
public function setSysDescrAttribute(?string $sysDescr): void
|
|
|
|
{
|
|
|
|
$this->attributes['sysDescr'] = $sysDescr === null ? null : trim(str_replace(chr(218), "\n", $sysDescr), "\\\" \r\n\t\0");
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setSysNameAttribute(?string $sysName): void
|
|
|
|
{
|
|
|
|
$this->attributes['sysName'] = $sysName === null ? null : str_replace("\n", '', strtolower(trim($sysName)));
|
|
|
|
}
|
|
|
|
|
2018-05-09 08:05:17 -05:00
|
|
|
// ---- Query scopes ----
|
|
|
|
|
|
|
|
public function scopeIsUp($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
|
|
|
['status', '=', 1],
|
|
|
|
['ignore', '=', 0],
|
2020-01-15 18:32:29 +01:00
|
|
|
['disable_notify', '=', 0],
|
2020-05-21 15:15:39 -05:00
|
|
|
['disabled', '=', 0],
|
2018-05-09 08:05:17 -05:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeIsActive($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
|
|
|
['ignore', '=', 0],
|
2020-05-21 15:15:39 -05:00
|
|
|
['disabled', '=', 0],
|
2018-05-09 08:05:17 -05:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeIsDown($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
|
|
|
['status', '=', 0],
|
2020-01-15 18:32:29 +01:00
|
|
|
['disable_notify', '=', 0],
|
2018-05-09 08:05:17 -05:00
|
|
|
['ignore', '=', 0],
|
2020-05-21 15:15:39 -05:00
|
|
|
['disabled', '=', 0],
|
2018-05-09 08:05:17 -05:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeIsIgnored($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
|
|
|
['ignore', '=', 1],
|
2020-05-21 15:15:39 -05:00
|
|
|
['disabled', '=', 0],
|
2018-05-09 08:05:17 -05:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeNotIgnored($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
2020-05-21 15:15:39 -05:00
|
|
|
['ignore', '=', 0],
|
2018-05-09 08:05:17 -05:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeIsDisabled($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
2020-05-21 15:15:39 -05:00
|
|
|
['disabled', '=', 1],
|
2018-05-09 08:05:17 -05:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2020-01-15 18:32:29 +01:00
|
|
|
public function scopeIsDisableNotify($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
2020-05-21 15:15:39 -05:00
|
|
|
['disable_notify', '=', 1],
|
2020-01-15 18:32:29 +01:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeIsNotDisabled($query)
|
|
|
|
{
|
|
|
|
return $query->where([
|
|
|
|
['disable_notify', '=', 0],
|
2020-05-21 15:15:39 -05:00
|
|
|
['disabled', '=', 0],
|
2020-01-15 18:32:29 +01:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2021-05-11 08:08:59 -05:00
|
|
|
public function scopeWhereAttributeDisabled(Builder $query, string $attribute): Builder
|
|
|
|
{
|
|
|
|
return $query->leftJoin('devices_attribs', function (JoinClause $query) use ($attribute) {
|
|
|
|
$query->on('devices.device_id', 'devices_attribs.device_id')
|
|
|
|
->where('devices_attribs.attrib_type', $attribute);
|
|
|
|
})->where(function (Builder $query) {
|
|
|
|
$query->whereNull('devices_attribs.attrib_value')
|
|
|
|
->orWhere('devices_attribs.attrib_value', '!=', 'true');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-04-01 06:03:02 +02:00
|
|
|
public function scopeWhereUptime($query, $uptime, $modifier = '<')
|
|
|
|
{
|
|
|
|
return $query->where([
|
|
|
|
['uptime', '>', 0],
|
2020-05-21 15:15:39 -05:00
|
|
|
['uptime', $modifier, $uptime],
|
2020-04-01 06:03:02 +02:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2021-05-11 08:08:59 -05:00
|
|
|
public function scopeCanPing(Builder $query): Builder
|
2018-07-30 16:58:38 -05:00
|
|
|
{
|
2021-05-11 08:08:59 -05:00
|
|
|
return $this->scopeWhereAttributeDisabled($query->where('disabled', 0), 'override_icmp_disable');
|
2018-07-30 16:58:38 -05:00
|
|
|
}
|
|
|
|
|
2018-05-09 08:05:17 -05:00
|
|
|
public function scopeHasAccess($query, User $user)
|
|
|
|
{
|
|
|
|
return $this->hasDeviceAccess($query, $user);
|
|
|
|
}
|
|
|
|
|
2019-08-08 02:59:14 +02:00
|
|
|
public function scopeInDeviceGroup($query, $deviceGroup)
|
|
|
|
{
|
2021-02-02 06:40:11 +00:00
|
|
|
return $query->whereIn(
|
|
|
|
$query->qualifyColumn('device_id'), function ($query) use ($deviceGroup) {
|
|
|
|
$query->select('device_id')
|
2022-03-12 16:14:32 -06:00
|
|
|
->from('device_group_device')
|
2023-04-10 15:26:26 -03:00
|
|
|
->whereIn('device_group_id', Arr::wrap($deviceGroup));
|
2021-02-02 06:40:11 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeNotInDeviceGroup($query, $deviceGroup)
|
|
|
|
{
|
|
|
|
return $query->whereNotIn(
|
|
|
|
$query->qualifyColumn('device_id'), function ($query) use ($deviceGroup) {
|
|
|
|
$query->select('device_id')
|
2022-03-12 16:14:32 -06:00
|
|
|
->from('device_group_device')
|
2023-04-10 15:26:26 -03:00
|
|
|
->whereIn('device_group_id', Arr::wrap($deviceGroup));
|
2021-02-02 06:40:11 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeInServiceTemplate($query, $serviceTemplate)
|
|
|
|
{
|
|
|
|
return $query->whereIn(
|
|
|
|
$query->qualifyColumn('device_id'), function ($query) use ($serviceTemplate) {
|
|
|
|
$query->select('device_id')
|
2022-03-12 16:14:32 -06:00
|
|
|
->from('service_templates_device')
|
|
|
|
->where('service_template_id', $serviceTemplate);
|
2021-02-02 06:40:11 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scopeNotInServiceTemplate($query, $serviceTemplate)
|
|
|
|
{
|
|
|
|
return $query->whereNotIn(
|
|
|
|
$query->qualifyColumn('device_id'), function ($query) use ($serviceTemplate) {
|
|
|
|
$query->select('device_id')
|
2022-03-12 16:14:32 -06:00
|
|
|
->from('service_templates_device')
|
|
|
|
->where('service_template_id', $serviceTemplate);
|
2021-02-02 06:40:11 +00:00
|
|
|
}
|
|
|
|
);
|
2019-08-08 02:59:14 +02:00
|
|
|
}
|
|
|
|
|
2018-05-09 08:05:17 -05:00
|
|
|
// ---- Define Relationships ----
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function accessPoints(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(AccessPoint::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function alerts(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Alert::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function alertLogs(): HasMany
|
2019-11-14 21:56:06 +00:00
|
|
|
{
|
2022-01-29 21:09:05 -06:00
|
|
|
return $this->hasMany(\App\Models\AlertLog::class, 'device_id');
|
2019-11-14 21:56:06 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function alertSchedules(): MorphToMany
|
2019-01-03 16:42:12 -06:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->morphToMany(\App\Models\AlertSchedule::class, 'alert_schedulable', 'alert_schedulables', 'schedule_id', 'schedule_id');
|
2019-01-03 16:42:12 -06:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function applications(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Application::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function attribs(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\DeviceAttrib::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function availability(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\Availability::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function bgppeers(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\BgpPeer::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function cefSwitching(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\CefSwitching::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function children(): BelongsToMany
|
2018-07-30 16:58:38 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->belongsToMany(self::class, 'device_relationships', 'parent_device_id', 'child_device_id');
|
2018-07-30 16:58:38 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function components(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Component::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function diskIo(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\DiskIo::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function hostResources(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(HrDevice::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-10-03 01:03:24 +02:00
|
|
|
public function hostResourceValues(): HasOne
|
2021-10-02 01:58:26 +02:00
|
|
|
{
|
2021-10-03 01:03:24 +02:00
|
|
|
return $this->hasOne(HrSystem::class, 'device_id');
|
2021-10-02 01:58:26 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function entityPhysical(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(EntPhysical::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function entityState(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(EntityState::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function eventlogs(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Eventlog::class, 'device_id', 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function graphs(): HasMany
|
2020-05-30 17:42:50 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\DeviceGraph::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function groups(): BelongsToMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->belongsToMany(\App\Models\DeviceGroup::class, 'device_group_device', 'device_id', 'device_group_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function ipsecTunnels(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(IpsecTunnel::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function ipv4(): HasManyThrough
|
2019-07-26 22:13:35 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasManyThrough(\App\Models\Ipv4Address::class, \App\Models\Port::class, 'device_id', 'port_id', 'device_id', 'port_id');
|
2019-07-26 22:13:35 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function ipv6(): HasManyThrough
|
2019-07-26 22:13:35 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasManyThrough(\App\Models\Ipv6Address::class, \App\Models\Port::class, 'device_id', 'port_id', 'device_id', 'port_id');
|
2019-07-26 22:13:35 +02:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function isisAdjacencies(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\IsisAdjacency::class, 'device_id', 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function location(): BelongsTo
|
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls)
- Parse coordinates from the location more consistently
- Add settings to webui
- ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~
- Google Maps, Bing, Mapquest, and OpenStreetMap supported initially.
- Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though.
- All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate)
- Update all (I think) sql queries to handle the new structure
- Remove final vestiges of override_sysLocation as a device attribute
- Update existing device groups and rules in DB
- Tested all APIs with good/bad location, no/bad/good key, and no connection.
- Cannot fix advanced queries that use location
This blocks #8868
DO NOT DELETE THIS TEXT
#### Please note
> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.
- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)
#### Testers
If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
2018-11-28 16:49:18 -06:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->belongsTo(\App\Models\Location::class, 'location_id', 'id');
|
Refactored and update Location Geocoding (#9359)
- Fix location so it is a regular database relation (this allows multiple devices to be accurately linked to one location and saves api calls)
- Parse coordinates from the location more consistently
- Add settings to webui
- ~~Used [PHP Geocoder](http://geocoder-php.org/), which has lots of backends and is well tested. (also includes reverse and geoip)~~
- Google Maps, Bing, Mapquest, and OpenStreetMap supported initially.
- Default to OpenStreetMap, which doesn't require a key. They will liberally hand out bans if you exceed 1 query per second though.
- All other Geocoding APIs require an API key. (Google requires a credit card on file, but seems to be the most accurate)
- Update all (I think) sql queries to handle the new structure
- Remove final vestiges of override_sysLocation as a device attribute
- Update existing device groups and rules in DB
- Tested all APIs with good/bad location, no/bad/good key, and no connection.
- Cannot fix advanced queries that use location
This blocks #8868
DO NOT DELETE THIS TEXT
#### Please note
> Please read this information carefully. You can run `./scripts/pre-commit.php` to check your code before submitting.
- [x] Have you followed our [code guidelines?](http://docs.librenms.org/Developing/Code-Guidelines/)
#### Testers
If you would like to test this pull request then please run: `./scripts/github-apply <pr_id>`, i.e `./scripts/github-apply 5926`
After you are done testing, you can remove the changes with `./scripts/github-remove`. If there are schema changes, you can ask on discord how to revert.
2018-11-28 16:49:18 -06:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function macs(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(Ipv4Mac::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mefInfo(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(MefInfo::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function muninPlugins(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
2020-07-09 15:22:50 +02:00
|
|
|
return $this->hasMany(\App\Models\MuninPlugin::class, 'device_id');
|
2020-04-29 07:25:13 -05:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function netscalerVservers(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(NetscalerVserver::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-11-12 13:49:09 -06:00
|
|
|
public function ospfAreas(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\OspfArea::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function ospfInstances(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\OspfInstance::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
2020-09-21 14:54:51 +02:00
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function ospfNbrs(): HasMany
|
2020-05-21 15:15:39 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\OspfNbr::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function ospfPorts(): HasMany
|
2020-05-21 15:15:39 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\OspfPort::class, 'device_id');
|
|
|
|
}
|
2018-05-09 08:05:17 -05:00
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function packages(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Package::class, 'device_id', 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function parents(): BelongsToMany
|
2018-07-30 16:58:38 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->belongsToMany(self::class, 'device_relationships', 'child_device_id', 'parent_device_id');
|
2018-07-30 16:58:38 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function perf(): HasMany
|
2018-07-30 16:58:38 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\DevicePerf::class, 'device_id');
|
2018-07-30 16:58:38 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function ports(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Port::class, 'device_id', 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2022-09-08 02:29:17 +02:00
|
|
|
public function portsAdsl(): HasManyThrough
|
|
|
|
{
|
|
|
|
return $this->hasManyThrough(\App\Models\PortAdsl::class, \App\Models\Port::class, 'device_id', 'port_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function portsFdb(): HasMany
|
2019-05-13 08:35:24 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\PortsFdb::class, 'device_id', 'device_id');
|
2019-05-13 08:35:24 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function portsNac(): HasMany
|
2018-12-20 19:50:12 -06:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\PortsNac::class, 'device_id', 'device_id');
|
2018-12-20 19:50:12 -06:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function portsStp(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\PortStp::class, 'device_id', 'device_id');
|
|
|
|
}
|
|
|
|
|
2022-09-08 02:29:17 +02:00
|
|
|
public function portsVdsl(): HasManyThrough
|
|
|
|
{
|
|
|
|
return $this->hasManyThrough(\App\Models\PortVdsl::class, \App\Models\Port::class, 'device_id', 'port_id');
|
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function portsVlan(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\PortVlan::class, 'device_id', 'device_id');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function processes(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\Process::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function processors(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Processor::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function routes(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(Route::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function rules(): BelongsToMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->belongsToMany(\App\Models\AlertRule::class, 'alert_device_map', 'device_id', 'rule_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function sensors(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Sensor::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function serviceTemplates(): BelongsToMany
|
2021-02-02 06:40:11 +00:00
|
|
|
{
|
|
|
|
return $this->belongsToMany(\App\Models\ServiceTemplate::class, 'service_templates_device', 'device_id', 'service_template_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function services(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Service::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function storage(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Storage::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function stpInstances(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(Stp::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2022-01-30 16:28:18 -06:00
|
|
|
public function stpPorts(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\PortStp::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mempools(): HasMany
|
2018-05-19 00:36:06 -04:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Mempool::class, 'device_id');
|
2018-05-19 00:36:06 -04:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsLsps(): HasMany
|
2019-06-06 23:12:13 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsLsp::class, 'device_id');
|
2019-06-06 23:12:13 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsLspPaths(): HasMany
|
2019-06-06 23:12:13 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsLspPath::class, 'device_id');
|
2019-06-06 23:12:13 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsSdps(): HasMany
|
2019-07-28 06:11:04 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsSdp::class, 'device_id');
|
2019-07-28 06:11:04 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsServices(): HasMany
|
2019-07-28 06:11:04 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsService::class, 'device_id');
|
2019-07-28 06:11:04 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsSaps(): HasMany
|
2019-07-28 06:11:04 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsSap::class, 'device_id');
|
2019-07-28 06:11:04 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsSdpBinds(): HasMany
|
2019-07-28 06:11:04 +02:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsSdpBind::class, 'device_id');
|
2019-07-28 06:11:04 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsTunnelArHops(): HasMany
|
2020-01-01 23:45:06 +01:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsTunnelArHop::class, 'device_id');
|
2020-01-01 23:45:06 +01:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function mplsTunnelCHops(): HasMany
|
2020-01-01 23:45:06 +01:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\MplsTunnelCHop::class, 'device_id');
|
2020-01-01 23:45:06 +01:00
|
|
|
}
|
|
|
|
|
2021-10-03 22:45:10 -05:00
|
|
|
public function outages(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(DeviceOutage::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function printerSupplies(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
2021-03-27 16:09:14 +01:00
|
|
|
return $this->hasMany(PrinterSupply::class, 'device_id');
|
2020-04-29 07:25:13 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function pseudowires(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(Pseudowire::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function rServers(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(LoadbalancerRserver::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function slas(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(Sla::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function syslogs(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Syslog::class, 'device_id', 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2022-01-29 21:09:05 -06:00
|
|
|
public function tnmsNeInfo(): HasMany
|
|
|
|
{
|
|
|
|
return $this->hasMany(TnmsneInfo::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function users(): BelongsToMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
|
|
|
// FIXME does not include global read
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->belongsToMany(\App\Models\User::class, 'devices_perms', 'device_id', 'user_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function vminfo(): HasMany
|
2020-01-17 11:16:14 -06:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Vminfo::class, 'device_id');
|
2020-01-17 11:16:14 -06:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function vlans(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(\App\Models\Vlan::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function vrfLites(): HasMany
|
2019-11-14 21:56:06 +00:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\VrfLite::class, 'device_id');
|
2019-11-14 21:56:06 +00:00
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function vrfs(): HasMany
|
2018-05-09 08:05:17 -05:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\Vrf::class, 'device_id');
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|
2019-01-25 15:31:33 -06:00
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function vServers(): HasMany
|
2020-04-29 07:25:13 -05:00
|
|
|
{
|
|
|
|
return $this->hasMany(LoadbalancerVserver::class, 'device_id');
|
|
|
|
}
|
|
|
|
|
2021-03-30 11:14:34 +02:00
|
|
|
public function wirelessSensors(): HasMany
|
2019-01-25 15:31:33 -06:00
|
|
|
{
|
2020-04-21 14:28:48 +02:00
|
|
|
return $this->hasMany(\App\Models\WirelessSensor::class, 'device_id');
|
2019-01-25 15:31:33 -06:00
|
|
|
}
|
2018-05-09 08:05:17 -05:00
|
|
|
}
|