1 | <?php |
||
2 | |||
3 | namespace App\Models; |
||
4 | |||
5 | use Fico7489\Laravel\Pivot\Traits\PivotEventTrait; |
||
6 | use Illuminate\Database\Eloquent\Builder; |
||
7 | use Illuminate\Database\Eloquent\Factories\HasFactory; |
||
8 | use Illuminate\Database\Eloquent\ModelNotFoundException; |
||
9 | use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||
10 | use Illuminate\Database\Eloquent\Relations\BelongsToMany; |
||
11 | use Illuminate\Database\Eloquent\Relations\HasMany; |
||
12 | use Illuminate\Database\Eloquent\Relations\HasManyThrough; |
||
13 | use Illuminate\Database\Eloquent\Relations\MorphToMany; |
||
14 | use Illuminate\Database\Query\JoinClause; |
||
15 | use Illuminate\Support\Str; |
||
16 | use LibreNMS\Exceptions\InvalidIpException; |
||
17 | use LibreNMS\Util\IP; |
||
18 | use LibreNMS\Util\IPv4; |
||
19 | use LibreNMS\Util\IPv6; |
||
20 | use LibreNMS\Util\Rewrite; |
||
21 | use LibreNMS\Util\Time; |
||
22 | use LibreNMS\Util\Url; |
||
23 | use Permissions; |
||
24 | |||
25 | /** |
||
26 | * @property-read int|null $ports_count |
||
27 | * @property-read int|null $sensors_count |
||
28 | * @property-read int|null $wirelessSensors_count |
||
29 | * |
||
30 | * @method static \Database\Factories\DeviceFactory factory(...$parameters) |
||
31 | */ |
||
32 | class Device extends BaseModel |
||
33 | { |
||
34 | use PivotEventTrait, HasFactory; |
||
35 | |||
36 | public $timestamps = false; |
||
37 | protected $primaryKey = 'device_id'; |
||
38 | protected $fillable = ['hostname', 'ip', 'status', 'status_reason', 'sysName', 'sysDescr', 'sysObjectID', 'hardware', 'version', 'features', 'serial', 'icon']; |
||
39 | protected $casts = [ |
||
40 | 'last_polled' => 'datetime', |
||
41 | 'status' => 'boolean', |
||
42 | ]; |
||
43 | |||
44 | // ---- Helper Functions ---- |
||
45 | |||
46 | public static function findByHostname($hostname) |
||
47 | { |
||
48 | return static::where('hostname', $hostname)->first(); |
||
49 | } |
||
50 | |||
51 | /** |
||
52 | * Returns IP/Hostname where polling will be targeted to |
||
53 | * |
||
54 | * @param string|array $device hostname which will be triggered |
||
55 | * array $device associative array with device data |
||
56 | * @return string IP/Hostname to which Device polling is targeted |
||
57 | */ |
||
58 | public static function pollerTarget($device) |
||
59 | { |
||
60 | if (! is_array($device)) { |
||
61 | $ret = static::where('hostname', $device)->first(['hostname', 'overwrite_ip']); |
||
62 | if (empty($ret)) { |
||
63 | return $device; |
||
64 | } |
||
65 | $overwrite_ip = $ret->overwrite_ip; |
||
66 | $hostname = $ret->hostname; |
||
67 | } elseif (array_key_exists('overwrite_ip', $device)) { |
||
68 | $overwrite_ip = $device['overwrite_ip']; |
||
69 | $hostname = $device['hostname']; |
||
70 | } else { |
||
71 | return $device['hostname']; |
||
72 | } |
||
73 | |||
74 | return $overwrite_ip ?: $hostname; |
||
75 | } |
||
76 | |||
77 | public static function findByIp($ip) |
||
78 | { |
||
79 | if (! IP::isValid($ip)) { |
||
80 | return null; |
||
81 | } |
||
82 | |||
83 | $device = static::where('hostname', $ip)->orWhere('ip', inet_pton($ip))->first(); |
||
84 | |||
85 | if ($device) { |
||
86 | return $device; |
||
87 | } |
||
88 | |||
89 | try { |
||
90 | $ipv4 = new IPv4($ip); |
||
91 | $port = Ipv4Address::where('ipv4_address', (string) $ipv4) |
||
92 | ->with('port', 'port.device') |
||
93 | ->firstOrFail()->port; |
||
94 | if ($port) { |
||
95 | return $port->device; |
||
96 | } |
||
97 | } catch (InvalidIpException $e) { |
||
98 | // |
||
99 | } catch (ModelNotFoundException $e) { |
||
100 | // |
||
101 | } |
||
102 | |||
103 | try { |
||
104 | $ipv6 = new IPv6($ip); |
||
105 | $port = Ipv6Address::where('ipv6_address', $ipv6->uncompressed()) |
||
106 | ->with(['port', 'port.device']) |
||
107 | ->firstOrFail()->port; |
||
108 | if ($port) { |
||
109 | return $port->device; |
||
110 | } |
||
111 | } catch (InvalidIpException $e) { |
||
112 | // |
||
113 | } catch (ModelNotFoundException $e) { |
||
114 | // |
||
115 | } |
||
116 | |||
117 | return null; |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Get VRF contexts to poll. |
||
122 | * If no contexts are found, return the default context '' |
||
123 | * |
||
124 | * @return array |
||
125 | */ |
||
126 | public function getVrfContexts(): array |
||
127 | { |
||
128 | return $this->vrfLites->isEmpty() ? [''] : $this->vrfLites->pluck('context_name')->all(); |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * Get the display name of this device (hostname) unless force_ip_to_sysname is set |
||
133 | * and hostname is an IP and sysName is set |
||
134 | * |
||
135 | * @return string |
||
136 | */ |
||
137 | public function displayName() |
||
138 | { |
||
139 | if (\LibreNMS\Config::get('force_ip_to_sysname') && $this->sysName && IP::isValid($this->hostname)) { |
||
140 | return $this->sysName; |
||
141 | } |
||
142 | |||
143 | return $this->hostname; |
||
144 | } |
||
145 | |||
146 | public function name() |
||
147 | { |
||
148 | $displayName = $this->displayName(); |
||
149 | if ($this->sysName !== $displayName) { |
||
150 | return $this->sysName; |
||
151 | } elseif ($this->hostname !== $displayName && $this->hostname !== $this->ip) { |
||
152 | return $this->hostname; |
||
153 | } |
||
154 | |||
155 | return ''; |
||
156 | } |
||
157 | |||
158 | public function isUnderMaintenance() |
||
159 | { |
||
160 | if (! $this->device_id) { |
||
161 | return false; |
||
162 | } |
||
163 | |||
164 | $query = AlertSchedule::isActive() |
||
165 | ->where(function (Builder $query) { |
||
166 | $query->whereHas('devices', function (Builder $query) { |
||
167 | $query->where('alert_schedulables.alert_schedulable_id', $this->device_id); |
||
168 | }); |
||
169 | |||
170 | if ($this->groups->isNotEmpty()) { |
||
171 | $query->orWhereHas('deviceGroups', function (Builder $query) { |
||
172 | $query->whereIn('alert_schedulables.alert_schedulable_id', $this->groups->pluck('id')); |
||
173 | }); |
||
174 | } |
||
175 | |||
176 | if ($this->location) { |
||
177 | $query->orWhereHas('locations', function (Builder $query) { |
||
178 | $query->where('alert_schedulables.alert_schedulable_id', $this->location->id); |
||
179 | }); |
||
180 | } |
||
181 | }); |
||
182 | |||
183 | return $query->exists(); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Get the shortened display name of this device. |
||
188 | * Length is always overridden by shorthost_target_length. |
||
189 | * |
||
190 | * @param int $length length to shorten to, will not break up words so may be longer |
||
191 | * @return string |
||
192 | */ |
||
193 | public function shortDisplayName($length = 12) |
||
194 | { |
||
195 | $name = $this->displayName(); |
||
196 | |||
197 | // IP addresses should not be shortened |
||
198 | if (IP::isValid($name)) { |
||
199 | return $name; |
||
200 | } |
||
201 | |||
202 | $length = \LibreNMS\Config::get('shorthost_target_length', $length); |
||
203 | if ($length < strlen($name)) { |
||
204 | $take = substr_count($name, '.', 0, $length) + 1; |
||
205 | |||
206 | return implode('.', array_slice(explode('.', $name), 0, $take)); |
||
207 | } |
||
208 | |||
209 | return $name; |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * Check if user can access this device. |
||
214 | * |
||
215 | * @param User $user |
||
216 | * @return bool |
||
217 | */ |
||
218 | public function canAccess($user) |
||
219 | { |
||
220 | if (! $user) { |
||
221 | return false; |
||
222 | } |
||
223 | |||
224 | if ($user->hasGlobalRead()) { |
||
225 | return true; |
||
226 | } |
||
227 | |||
228 | return Permissions::canAccessDevice($this->device_id, $user->user_id); |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
229 | } |
||
230 | |||
231 | public function formatDownUptime($short = false) |
||
232 | { |
||
233 | $time = ($this->status == 1) ? $this->uptime : time() - strtotime($this->last_polled); |
||
234 | |||
235 | return Time::formatInterval($time, $short); |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * @return string |
||
240 | */ |
||
241 | public function logo() |
||
242 | { |
||
243 | $base_name = pathinfo($this->icon, PATHINFO_FILENAME); |
||
244 | $options = [ |
||
245 | "images/logos/$base_name.svg", |
||
246 | "images/logos/$base_name.png", |
||
247 | "images/os/$base_name.svg", |
||
248 | "images/os/$base_name.png", |
||
249 | ]; |
||
250 | |||
251 | foreach ($options as $file) { |
||
252 | if (is_file(public_path() . "/$file")) { |
||
253 | return asset($file); |
||
254 | } |
||
255 | } |
||
256 | |||
257 | return asset('images/os/generic.svg'); |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Update the max_depth field based on parents |
||
262 | * Performs SQL query, so make sure all parents are saved first |
||
263 | * |
||
264 | * @param int $exclude exclude a device_id from being considered (used for deleting) |
||
265 | */ |
||
266 | public function updateMaxDepth($exclude = null) |
||
267 | { |
||
268 | // optimize for memory instead of time |
||
269 | $query = $this->parents()->getQuery(); |
||
270 | if (! is_null($exclude)) { |
||
271 | $query->where('device_id', '!=', $exclude); |
||
272 | } |
||
273 | |||
274 | $count = $query->count(); |
||
275 | if ($count === 0) { |
||
276 | if ($this->children()->count() === 0) { |
||
277 | $this->max_depth = 0; // no children or parents |
||
278 | } else { |
||
279 | $this->max_depth = 1; // has children |
||
280 | } |
||
281 | } else { |
||
282 | $parents_max_depth = $query->max('max_depth'); |
||
283 | $this->max_depth = $parents_max_depth + 1; |
||
284 | } |
||
285 | |||
286 | $this->save(); |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * Device dependency check to see if this node is standalone or not. |
||
291 | * Standalone is a special case where the device has no parents or children and is denoted by a max_depth of 0 |
||
292 | * |
||
293 | * Only checks on root nodes (where max_depth is 1 or 0) |
||
294 | */ |
||
295 | public function validateStandalone() |
||
296 | { |
||
297 | if ($this->max_depth === 0 && $this->children()->count() > 0) { |
||
298 | $this->max_depth = 1; // has children |
||
299 | } elseif ($this->max_depth === 1 && $this->parents()->count() === 0) { |
||
300 | $this->max_depth = 0; // no children or parents |
||
301 | } |
||
302 | |||
303 | $this->save(); |
||
304 | } |
||
305 | |||
306 | public function getAttrib($name) |
||
307 | { |
||
308 | return $this->attribs->pluck('attrib_value', 'attrib_type')->get($name); |
||
309 | } |
||
310 | |||
311 | public function setAttrib($name, $value) |
||
312 | { |
||
313 | $attrib = $this->attribs->first(function ($item) use ($name) { |
||
314 | return $item->attrib_type === $name; |
||
315 | }); |
||
316 | |||
317 | if (! $attrib) { |
||
318 | $attrib = new DeviceAttrib(['attrib_type' => $name]); |
||
319 | $this->attribs->push($attrib); |
||
320 | } |
||
321 | |||
322 | $attrib->attrib_value = $value; |
||
323 | |||
324 | return (bool) $this->attribs()->save($attrib); |
||
325 | } |
||
326 | |||
327 | public function forgetAttrib($name) |
||
328 | { |
||
329 | $attrib_index = $this->attribs->search(function ($attrib) use ($name) { |
||
330 | return $attrib->attrib_type === $name; |
||
331 | }); |
||
332 | |||
333 | if ($attrib_index !== false) { |
||
334 | $deleted = (bool) $this->attribs->get($attrib_index)->delete(); |
||
335 | // only forget the attrib_index after delete, otherwise delete() will fail fatally with: |
||
336 | // Symfony\\Component\\Debug\Exception\\FatalThrowableError(code: 0): Call to a member function delete() on null |
||
337 | $this->attribs->forget((string) $attrib_index); |
||
338 | |||
339 | return $deleted; |
||
340 | } |
||
341 | |||
342 | return false; |
||
343 | } |
||
344 | |||
345 | public function getAttribs() |
||
346 | { |
||
347 | return $this->attribs->pluck('attrib_value', 'attrib_type')->toArray(); |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * Update the location to the correct location and update GPS if needed |
||
352 | * |
||
353 | * @param \App\Models\Location|string $new_location location data |
||
354 | * @param bool $doLookup try to lookup the GPS coordinates |
||
355 | */ |
||
356 | public function setLocation($new_location, bool $doLookup = false) |
||
357 | { |
||
358 | $new_location = $new_location instanceof Location ? $new_location : new Location(['location' => $new_location]); |
||
359 | $new_location->location = $new_location->location ? Rewrite::location($new_location->location) : null; |
||
360 | $coord = array_filter($new_location->only(['lat', 'lng'])); |
||
361 | |||
362 | if (! $this->override_sysLocation) { |
||
363 | if (! $new_location->location) { // disassociate if the location name is empty |
||
364 | $this->location()->dissociate(); |
||
365 | |||
366 | return; |
||
367 | } |
||
368 | |||
369 | if (! $this->relationLoaded('location') || optional($this->location)->location !== $new_location->location) { |
||
370 | if (! $new_location->exists) { // don't fetch if new location persisted to the DB, just use it |
||
371 | $new_location = Location::firstOrCreate(['location' => $new_location->location], $coord); |
||
372 | } |
||
373 | $this->location()->associate($new_location); |
||
374 | } |
||
375 | } |
||
376 | |||
377 | // set coordinates |
||
378 | if ($this->location && ! $this->location->fixed_coordinates) { |
||
379 | $this->location->fill($coord); |
||
380 | if ($doLookup && empty($coord)) { // only if requested and coordinates not passed explicitly |
||
381 | $this->location->lookupCoordinates($this->hostname); |
||
382 | } |
||
383 | } |
||
384 | } |
||
385 | |||
386 | // ---- Accessors/Mutators ---- |
||
387 | |||
388 | public function getIconAttribute($icon) |
||
389 | { |
||
390 | return Str::start(Url::findOsImage($this->os, $this->features, $icon), 'images/os/'); |
||
391 | } |
||
392 | |||
393 | public function getIpAttribute($ip) |
||
394 | { |
||
395 | if (empty($ip)) { |
||
396 | return null; |
||
397 | } |
||
398 | // @ suppresses warning, inet_ntop() returns false if it fails |
||
399 | return @inet_ntop($ip) ?: null; |
||
400 | } |
||
401 | |||
402 | public function setIpAttribute($ip) |
||
403 | { |
||
404 | $this->attributes['ip'] = inet_pton($ip); |
||
405 | } |
||
406 | |||
407 | public function setStatusAttribute($status) |
||
408 | { |
||
409 | $this->attributes['status'] = (int) $status; |
||
410 | } |
||
411 | |||
412 | // ---- Query scopes ---- |
||
413 | |||
414 | public function scopeIsUp($query) |
||
415 | { |
||
416 | return $query->where([ |
||
417 | ['status', '=', 1], |
||
418 | ['ignore', '=', 0], |
||
419 | ['disable_notify', '=', 0], |
||
420 | ['disabled', '=', 0], |
||
421 | ]); |
||
422 | } |
||
423 | |||
424 | public function scopeIsActive($query) |
||
425 | { |
||
426 | return $query->where([ |
||
427 | ['ignore', '=', 0], |
||
428 | ['disabled', '=', 0], |
||
429 | ]); |
||
430 | } |
||
431 | |||
432 | public function scopeIsDown($query) |
||
433 | { |
||
434 | return $query->where([ |
||
435 | ['status', '=', 0], |
||
436 | ['disable_notify', '=', 0], |
||
437 | ['ignore', '=', 0], |
||
438 | ['disabled', '=', 0], |
||
439 | ]); |
||
440 | } |
||
441 | |||
442 | public function scopeIsIgnored($query) |
||
443 | { |
||
444 | return $query->where([ |
||
445 | ['ignore', '=', 1], |
||
446 | ['disabled', '=', 0], |
||
447 | ]); |
||
448 | } |
||
449 | |||
450 | public function scopeNotIgnored($query) |
||
451 | { |
||
452 | return $query->where([ |
||
453 | ['ignore', '=', 0], |
||
454 | ]); |
||
455 | } |
||
456 | |||
457 | public function scopeIsDisabled($query) |
||
458 | { |
||
459 | return $query->where([ |
||
460 | ['disabled', '=', 1], |
||
461 | ]); |
||
462 | } |
||
463 | |||
464 | public function scopeIsDisableNotify($query) |
||
465 | { |
||
466 | return $query->where([ |
||
467 | ['disable_notify', '=', 1], |
||
468 | ]); |
||
469 | } |
||
470 | |||
471 | public function scopeIsNotDisabled($query) |
||
472 | { |
||
473 | return $query->where([ |
||
474 | ['disable_notify', '=', 0], |
||
475 | ['disabled', '=', 0], |
||
476 | ]); |
||
477 | } |
||
478 | |||
479 | public function scopeWhereAttributeDisabled(Builder $query, string $attribute): Builder |
||
480 | { |
||
481 | return $query->leftJoin('devices_attribs', function (JoinClause $query) use ($attribute) { |
||
482 | $query->on('devices.device_id', 'devices_attribs.device_id') |
||
483 | ->where('devices_attribs.attrib_type', $attribute); |
||
484 | })->where(function (Builder $query) { |
||
485 | $query->whereNull('devices_attribs.attrib_value') |
||
486 | ->orWhere('devices_attribs.attrib_value', '!=', 'true'); |
||
487 | }); |
||
488 | } |
||
489 | |||
490 | public function scopeWhereUptime($query, $uptime, $modifier = '<') |
||
491 | { |
||
492 | return $query->where([ |
||
493 | ['uptime', '>', 0], |
||
494 | ['uptime', $modifier, $uptime], |
||
495 | ]); |
||
496 | } |
||
497 | |||
498 | public function scopeCanPing(Builder $query): Builder |
||
499 | { |
||
500 | return $this->scopeWhereAttributeDisabled($query->where('disabled', 0), 'override_icmp_disable'); |
||
501 | } |
||
502 | |||
503 | public function scopeHasAccess($query, User $user) |
||
504 | { |
||
505 | return $this->hasDeviceAccess($query, $user); |
||
506 | } |
||
507 | |||
508 | public function scopeInDeviceGroup($query, $deviceGroup) |
||
509 | { |
||
510 | return $query->whereIn( |
||
511 | $query->qualifyColumn('device_id'), function ($query) use ($deviceGroup) { |
||
512 | $query->select('device_id') |
||
513 | ->from('device_group_device') |
||
514 | ->where('device_group_id', $deviceGroup); |
||
515 | } |
||
516 | ); |
||
517 | } |
||
518 | |||
519 | public function scopeNotInDeviceGroup($query, $deviceGroup) |
||
520 | { |
||
521 | return $query->whereNotIn( |
||
522 | $query->qualifyColumn('device_id'), function ($query) use ($deviceGroup) { |
||
523 | $query->select('device_id') |
||
524 | ->from('device_group_device') |
||
525 | ->where('device_group_id', $deviceGroup); |
||
526 | } |
||
527 | ); |
||
528 | } |
||
529 | |||
530 | public function scopeInServiceTemplate($query, $serviceTemplate) |
||
531 | { |
||
532 | return $query->whereIn( |
||
533 | $query->qualifyColumn('device_id'), function ($query) use ($serviceTemplate) { |
||
534 | $query->select('device_id') |
||
535 | ->from('service_templates_device') |
||
536 | ->where('service_template_id', $serviceTemplate); |
||
537 | } |
||
538 | ); |
||
539 | } |
||
540 | |||
541 | public function scopeNotInServiceTemplate($query, $serviceTemplate) |
||
542 | { |
||
543 | return $query->whereNotIn( |
||
544 | $query->qualifyColumn('device_id'), function ($query) use ($serviceTemplate) { |
||
545 | $query->select('device_id') |
||
546 | ->from('service_templates_device') |
||
547 | ->where('service_template_id', $serviceTemplate); |
||
548 | } |
||
549 | ); |
||
550 | } |
||
551 | |||
552 | // ---- Define Relationships ---- |
||
553 | |||
554 | public function accessPoints(): HasMany |
||
555 | { |
||
556 | return $this->hasMany(AccessPoint::class, 'device_id'); |
||
557 | } |
||
558 | |||
559 | public function alerts(): HasMany |
||
560 | { |
||
561 | return $this->hasMany(\App\Models\Alert::class, 'device_id'); |
||
562 | } |
||
563 | |||
564 | public function attribs(): HasMany |
||
565 | { |
||
566 | return $this->hasMany(\App\Models\DeviceAttrib::class, 'device_id'); |
||
567 | } |
||
568 | |||
569 | public function alertSchedules(): MorphToMany |
||
570 | { |
||
571 | return $this->morphToMany(\App\Models\AlertSchedule::class, 'alert_schedulable', 'alert_schedulables', 'schedule_id', 'schedule_id'); |
||
572 | } |
||
573 | |||
574 | public function applications(): HasMany |
||
575 | { |
||
576 | return $this->hasMany(\App\Models\Application::class, 'device_id'); |
||
577 | } |
||
578 | |||
579 | public function bgppeers(): HasMany |
||
580 | { |
||
581 | return $this->hasMany(\App\Models\BgpPeer::class, 'device_id'); |
||
582 | } |
||
583 | |||
584 | public function cefSwitching(): HasMany |
||
585 | { |
||
586 | return $this->hasMany(\App\Models\CefSwitching::class, 'device_id'); |
||
587 | } |
||
588 | |||
589 | public function children(): BelongsToMany |
||
590 | { |
||
591 | return $this->belongsToMany(self::class, 'device_relationships', 'parent_device_id', 'child_device_id'); |
||
592 | } |
||
593 | |||
594 | public function components(): HasMany |
||
595 | { |
||
596 | return $this->hasMany(\App\Models\Component::class, 'device_id'); |
||
597 | } |
||
598 | |||
599 | public function hostResources(): HasMany |
||
600 | { |
||
601 | return $this->hasMany(HrDevice::class, 'device_id'); |
||
602 | } |
||
603 | |||
604 | public function entityPhysical(): HasMany |
||
605 | { |
||
606 | return $this->hasMany(EntPhysical::class, 'device_id'); |
||
607 | } |
||
608 | |||
609 | public function eventlogs(): HasMany |
||
610 | { |
||
611 | return $this->hasMany(\App\Models\Eventlog::class, 'device_id', 'device_id'); |
||
612 | } |
||
613 | |||
614 | public function graphs(): HasMany |
||
615 | { |
||
616 | return $this->hasMany(\App\Models\DeviceGraph::class, 'device_id'); |
||
617 | } |
||
618 | |||
619 | public function groups(): BelongsToMany |
||
620 | { |
||
621 | return $this->belongsToMany(\App\Models\DeviceGroup::class, 'device_group_device', 'device_id', 'device_group_id'); |
||
622 | } |
||
623 | |||
624 | public function ipsecTunnels(): HasMany |
||
625 | { |
||
626 | return $this->hasMany(IpsecTunnel::class, 'device_id'); |
||
627 | } |
||
628 | |||
629 | public function ipv4(): HasManyThrough |
||
630 | { |
||
631 | return $this->hasManyThrough(\App\Models\Ipv4Address::class, \App\Models\Port::class, 'device_id', 'port_id', 'device_id', 'port_id'); |
||
632 | } |
||
633 | |||
634 | public function ipv6(): HasManyThrough |
||
635 | { |
||
636 | return $this->hasManyThrough(\App\Models\Ipv6Address::class, \App\Models\Port::class, 'device_id', 'port_id', 'device_id', 'port_id'); |
||
637 | } |
||
638 | |||
639 | public function location(): BelongsTo |
||
640 | { |
||
641 | return $this->belongsTo(\App\Models\Location::class, 'location_id', 'id'); |
||
642 | } |
||
643 | |||
644 | public function mefInfo(): HasMany |
||
645 | { |
||
646 | return $this->hasMany(MefInfo::class, 'device_id'); |
||
647 | } |
||
648 | |||
649 | public function muninPlugins(): HasMany |
||
650 | { |
||
651 | return $this->hasMany(\App\Models\MuninPlugin::class, 'device_id'); |
||
652 | } |
||
653 | |||
654 | public function ospfInstances(): HasMany |
||
655 | { |
||
656 | return $this->hasMany(\App\Models\OspfInstance::class, 'device_id'); |
||
657 | } |
||
658 | |||
659 | public function ospfNbrs(): HasMany |
||
660 | { |
||
661 | return $this->hasMany(\App\Models\OspfNbr::class, 'device_id'); |
||
662 | } |
||
663 | |||
664 | public function ospfPorts(): HasMany |
||
665 | { |
||
666 | return $this->hasMany(\App\Models\OspfPort::class, 'device_id'); |
||
667 | } |
||
668 | |||
669 | public function isisAdjacencies(): HasMany |
||
670 | { |
||
671 | return $this->hasMany(\App\Models\IsisAdjacency::class, 'device_id', 'device_id'); |
||
672 | } |
||
673 | |||
674 | public function netscalerVservers(): HasMany |
||
675 | { |
||
676 | return $this->hasMany(NetscalerVserver::class, 'device_id'); |
||
677 | } |
||
678 | |||
679 | public function packages(): HasMany |
||
680 | { |
||
681 | return $this->hasMany(\App\Models\Package::class, 'device_id', 'device_id'); |
||
682 | } |
||
683 | |||
684 | public function parents(): BelongsToMany |
||
685 | { |
||
686 | return $this->belongsToMany(self::class, 'device_relationships', 'child_device_id', 'parent_device_id'); |
||
687 | } |
||
688 | |||
689 | public function perf(): HasMany |
||
690 | { |
||
691 | return $this->hasMany(\App\Models\DevicePerf::class, 'device_id'); |
||
692 | } |
||
693 | |||
694 | public function ports(): HasMany |
||
695 | { |
||
696 | return $this->hasMany(\App\Models\Port::class, 'device_id', 'device_id'); |
||
697 | } |
||
698 | |||
699 | public function portsFdb(): HasMany |
||
700 | { |
||
701 | return $this->hasMany(\App\Models\PortsFdb::class, 'device_id', 'device_id'); |
||
702 | } |
||
703 | |||
704 | public function portsNac(): HasMany |
||
705 | { |
||
706 | return $this->hasMany(\App\Models\PortsNac::class, 'device_id', 'device_id'); |
||
707 | } |
||
708 | |||
709 | public function processors(): HasMany |
||
710 | { |
||
711 | return $this->hasMany(\App\Models\Processor::class, 'device_id'); |
||
712 | } |
||
713 | |||
714 | public function routes(): HasMany |
||
715 | { |
||
716 | return $this->hasMany(Route::class, 'device_id'); |
||
717 | } |
||
718 | |||
719 | public function rules(): BelongsToMany |
||
720 | { |
||
721 | return $this->belongsToMany(\App\Models\AlertRule::class, 'alert_device_map', 'device_id', 'rule_id'); |
||
722 | } |
||
723 | |||
724 | public function sensors(): HasMany |
||
725 | { |
||
726 | return $this->hasMany(\App\Models\Sensor::class, 'device_id'); |
||
727 | } |
||
728 | |||
729 | public function serviceTemplates(): BelongsToMany |
||
730 | { |
||
731 | return $this->belongsToMany(\App\Models\ServiceTemplate::class, 'service_templates_device', 'device_id', 'service_template_id'); |
||
732 | } |
||
733 | |||
734 | public function services(): HasMany |
||
735 | { |
||
736 | return $this->hasMany(\App\Models\Service::class, 'device_id'); |
||
737 | } |
||
738 | |||
739 | public function storage(): HasMany |
||
740 | { |
||
741 | return $this->hasMany(\App\Models\Storage::class, 'device_id'); |
||
742 | } |
||
743 | |||
744 | public function stpInstances(): HasMany |
||
745 | { |
||
746 | return $this->hasMany(Stp::class, 'device_id'); |
||
747 | } |
||
748 | |||
749 | public function mempools(): HasMany |
||
750 | { |
||
751 | return $this->hasMany(\App\Models\Mempool::class, 'device_id'); |
||
752 | } |
||
753 | |||
754 | public function mplsLsps(): HasMany |
||
755 | { |
||
756 | return $this->hasMany(\App\Models\MplsLsp::class, 'device_id'); |
||
757 | } |
||
758 | |||
759 | public function mplsLspPaths(): HasMany |
||
760 | { |
||
761 | return $this->hasMany(\App\Models\MplsLspPath::class, 'device_id'); |
||
762 | } |
||
763 | |||
764 | public function mplsSdps(): HasMany |
||
765 | { |
||
766 | return $this->hasMany(\App\Models\MplsSdp::class, 'device_id'); |
||
767 | } |
||
768 | |||
769 | public function mplsServices(): HasMany |
||
770 | { |
||
771 | return $this->hasMany(\App\Models\MplsService::class, 'device_id'); |
||
772 | } |
||
773 | |||
774 | public function mplsSaps(): HasMany |
||
775 | { |
||
776 | return $this->hasMany(\App\Models\MplsSap::class, 'device_id'); |
||
777 | } |
||
778 | |||
779 | public function mplsSdpBinds(): HasMany |
||
780 | { |
||
781 | return $this->hasMany(\App\Models\MplsSdpBind::class, 'device_id'); |
||
782 | } |
||
783 | |||
784 | public function mplsTunnelArHops(): HasMany |
||
785 | { |
||
786 | return $this->hasMany(\App\Models\MplsTunnelArHop::class, 'device_id'); |
||
787 | } |
||
788 | |||
789 | public function mplsTunnelCHops(): HasMany |
||
790 | { |
||
791 | return $this->hasMany(\App\Models\MplsTunnelCHop::class, 'device_id'); |
||
792 | } |
||
793 | |||
794 | public function printerSupplies(): HasMany |
||
795 | { |
||
796 | return $this->hasMany(PrinterSupply::class, 'device_id'); |
||
797 | } |
||
798 | |||
799 | public function pseudowires(): HasMany |
||
800 | { |
||
801 | return $this->hasMany(Pseudowire::class, 'device_id'); |
||
802 | } |
||
803 | |||
804 | public function rServers(): HasMany |
||
805 | { |
||
806 | return $this->hasMany(LoadbalancerRserver::class, 'device_id'); |
||
807 | } |
||
808 | |||
809 | public function slas(): HasMany |
||
810 | { |
||
811 | return $this->hasMany(Sla::class, 'device_id'); |
||
812 | } |
||
813 | |||
814 | public function syslogs(): HasMany |
||
815 | { |
||
816 | return $this->hasMany(\App\Models\Syslog::class, 'device_id', 'device_id'); |
||
817 | } |
||
818 | |||
819 | public function users(): BelongsToMany |
||
820 | { |
||
821 | // FIXME does not include global read |
||
822 | return $this->belongsToMany(\App\Models\User::class, 'devices_perms', 'device_id', 'user_id'); |
||
823 | } |
||
824 | |||
825 | public function vminfo(): HasMany |
||
826 | { |
||
827 | return $this->hasMany(\App\Models\Vminfo::class, 'device_id'); |
||
828 | } |
||
829 | |||
830 | public function vlans(): HasMany |
||
831 | { |
||
832 | return $this->hasMany(\App\Models\Vlan::class, 'device_id'); |
||
833 | } |
||
834 | |||
835 | public function vrfLites(): HasMany |
||
836 | { |
||
837 | return $this->hasMany(\App\Models\VrfLite::class, 'device_id'); |
||
838 | } |
||
839 | |||
840 | public function vrfs(): HasMany |
||
841 | { |
||
842 | return $this->hasMany(\App\Models\Vrf::class, 'device_id'); |
||
843 | } |
||
844 | |||
845 | public function vServers(): HasMany |
||
846 | { |
||
847 | return $this->hasMany(LoadbalancerVserver::class, 'device_id'); |
||
848 | } |
||
849 | |||
850 | public function wirelessSensors(): HasMany |
||
851 | { |
||
852 | return $this->hasMany(\App\Models\WirelessSensor::class, 'device_id'); |
||
853 | } |
||
854 | } |
||
855 |