1<?php
2/**
3 * Observium
4 *
5 *   This file is part of Observium.
6 *
7 * @package    observium
8 * @subpackage functions
9 * @copyright  (C) 2006-2013 Adam Armstrong, (C) 2013-2019 Observium Limited
10 *
11 */
12
13// Include entity specific functions
14require_once($config['install_dir'] . "/includes/entities/port.inc.php");
15require_once($config['install_dir'] . "/includes/entities/sensor.inc.php");
16require_once($config['install_dir'] . "/includes/entities/status.inc.php");
17require_once($config['install_dir'] . "/includes/entities/counter.inc.php");
18
19/**
20 *
21 * Get attribute value for entity
22 *
23 * @param string $entity_type
24 * @param mixed $entity_id
25 * @param string $attrib_type
26 * @return string
27 */
28function get_entity_attrib($entity_type, $entity_id, $attrib_type)
29{
30  if (is_array($entity_id))
31  {
32    // Passed entity array, instead id
33    $translate = entity_type_translate_array($entity_type);
34    $entity_id = $entity_id[$translate['id_field']];
35  }
36  if (!$entity_id) { return NULL; }
37
38  if (isset($GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id][$attrib_type]))
39  {
40    return $GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id][$attrib_type];
41  }
42
43  if ($row = dbFetchRow("SELECT `attrib_value` FROM `entity_attribs` WHERE `entity_type` = ? AND `entity_id` = ? AND `attrib_type` = ?", array($entity_type, $entity_id, $attrib_type)))
44  {
45    return $row['attrib_value'];
46  }
47
48  return NULL;
49}
50
51/**
52 *
53 * Get all attributes for entity
54 *
55 * @param string $entity_type
56 * @param mixed $entity_id
57 * @return array
58 */
59function get_entity_attribs($entity_type, $entity_id)
60{
61  if (is_array($entity_id))
62  {
63    // Passed entity array, instead id
64    $translate = entity_type_translate_array($entity_type);
65    $entity_id = $entity_id[$translate['id_field']];
66  }
67  if (!$entity_id) { return NULL; }
68
69  if (!isset($GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id]))
70  {
71    $attribs = array();
72
73    foreach (dbFetchRows("SELECT * FROM `entity_attribs` WHERE `entity_type` = ? AND `entity_id` = ?", array($entity_type, $entity_id)) as $entry)
74    {
75      $attribs[$entry['attrib_type']] = $entry['attrib_value'];
76    }
77
78    $GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id] = $attribs;
79  }
80  return $GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id];
81}
82
83/**
84 *
85 * Set value for specific attribute and entity
86 *
87 * @param string $entity_type
88 * @param mixed $entity_id
89 * @param string $attrib_type
90 * @param string $attrib_value
91 * @param string $device_id
92 * @return boolean
93 */
94function set_entity_attrib($entity_type, $entity_id, $attrib_type, $attrib_value, $device_id = NULL)
95{
96  if (is_array($entity_id))
97  {
98    // Passed entity array, instead id
99    $translate = entity_type_translate_array($entity_type);
100    $entity = $entity_id;
101    $entity_id = $entity[$translate['id_field']];
102  }
103
104  if (!$entity_id) { return NULL; }
105
106  // If we're setting a device attribute, use the entity_id as the device_id
107  if($entity_type == "device") { $device_id = $entity_id; }
108
109
110  // If we don't have a device_id, try to work out what it should be
111  if(!$device_id)
112  {
113    if(isset($entity) && isset($entity['device_id']))
114    {
115      $device_id = $entity['device_id'];
116    } else {
117      $entity = get_entity_by_id_cache($entity_type, $entity_id);
118      $device_id = $entity['device_id'];
119    }
120  }
121  if (!$device_id) { print_error("Enable to set attrib data : $entity_type, $entity_id, $attrib_type, $attrib_value, $device_id");  return NULL; }
122
123  if (isset($GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id]))
124  {
125    // Reset entity attribs
126    unset($GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id]);
127  }
128
129  //if (dbFetchCell("SELECT COUNT(*) FROM `entity_attribs` WHERE `entity_type` = ? AND `entity_id` = ? AND `attrib_type` = ?", array($entity_type, $entity_id, $attrib_type)))
130  if (dbExist('entity_attribs', '`entity_type` = ? AND `entity_id` = ? AND `attrib_type` = ?', array($entity_type, $entity_id, $attrib_type)))
131  {
132    $return = dbUpdate(array('attrib_value' => $attrib_value), 'entity_attribs', '`entity_type` = ? AND `entity_id` = ? AND `attrib_type` = ?', array($entity_type, $entity_id, $attrib_type));
133  } else {
134    $return = dbInsert(array('device_id' => $device_id, 'entity_type' => $entity_type, 'entity_id' => $entity_id, 'attrib_type' => $attrib_type, 'attrib_value' => $attrib_value), 'entity_attribs');
135    if ($return !== FALSE) { $return = TRUE; } // Note dbInsert return IDs if exist or 0 for not indexed tables
136  }
137
138  return $return;
139}
140
141/**
142 *
143 * Delete specific attribute for entity
144 *
145 * @param string $entity_type
146 * @param mixed $entity_id
147 * @param string $attrib_type
148 * @return boolean
149 */
150function del_entity_attrib($entity_type, $entity_id, $attrib_type)
151{
152  if (is_array($entity_id))
153  {
154    // Passed entity array, instead id
155    $translate = entity_type_translate_array($entity_type);
156    $entity_id = $entity_id[$translate['id_field']];
157  }
158  if (!$entity_id) { return NULL; }
159
160  if (isset($GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id]))
161  {
162    // Reset entity attribs
163    unset($GLOBALS['cache']['entity_attribs'][$entity_type][$entity_id]);
164  }
165
166  return dbDelete('entity_attribs', '`entity_type` = ? AND `entity_id` = ? AND `attrib_type` = ?', array($entity_type, $entity_id, $attrib_type));
167
168}
169
170/**
171 *
172 * Get array of entities (id) linked to device
173 *
174 * @param mixed $device_id Device array of id
175 * @param mixed $entity_types List of entities as array, if empty get all
176 * @return array
177 */
178function get_device_entities($device_id, $entity_types = NULL)
179{
180  if (is_array($device_id))
181  {
182    // Passed device array, instead id
183    $device_id = $device_id['device_id'];
184  }
185  if (!$device_id) { return NULL; }
186
187  if (!is_array($entity_types) && strlen($entity_types))
188  {
189    // Single entity type passed, convert to array
190    $entity_types = array($entity_types);
191  }
192  $all = empty($entity_types);
193  $entities = array();
194  foreach (array_keys($GLOBALS['config']['entities']) as $entity_type)
195  {
196    if ($all || in_array($entity_type, $entity_types))
197    {
198      $translate = entity_type_translate_array($entity_type);
199      if (!$translate['device_id_field']) { continue; }
200      $query = 'SELECT `' . $translate['id_field'] . '` FROM `' . $translate['table'] . '` WHERE `' . $translate['device_id_field'] . '` = ?;';
201      $entity_ids = dbFetchColumn($query, array($device_id));
202      if (is_array($entity_ids) && count($entity_ids))
203      {
204        $entities[$entity_type] = $entity_ids;
205      }
206    }
207  }
208  return $entities;
209}
210
211/**
212 *
213 * Get all attributes for all entities from device
214 *
215 * @param string $entity_type
216 * @param mixed $entity_id
217 * @return array
218 */
219function get_device_entities_attribs($device_id, $entity_types = NULL)
220{
221  $attribs = array();
222
223  $query = "SELECT * FROM `entity_attribs` WHERE `device_id` = ?";
224  if($entity_types)
225  {
226    if(!is_array($entity_types)) { $entity_types = array($entity_types); }
227    $query .= " AND `entity_type` IN ('".implode("', '", $entity_types)."')";
228  }
229
230  foreach (dbFetchRows($query, array($device_id)) as $entry)
231  {
232    $attribs[$entry['entity_type']][$entry['entity_id']][$entry['attrib_type']] = $entry['attrib_value'];
233  }
234
235  return $attribs;
236}
237
238/* MIB & object specific functions */
239
240/**
241 * Check if MIB available and permitted for device
242 * if $check_permissions is TRUE, check permissions by config option $config['mibs'][$mib]
243 * and from the enable/disable panel in the device configuration in the web interface
244 * if $check_sysORID is TRUE, we fetch the device's supplied list as well - should only be FALSE in the sysORID code
245 *
246 * @param array $device Device array
247 * @param string $mib MIB name
248 * @param boolean $check_permissions Check device specific MIB permissions (if FALSE ignores it)
249 * @param boolean $check_sysORID Check if MIB exist in sysOROID table
250 *
251 * @return boolean MIB is permitted for device or not.
252 */
253function is_device_mib($device, $mib, $check_permissions = TRUE, $check_sysORID = TRUE)
254{
255  global $config;
256
257  $mib_permitted = in_array($mib, get_device_mibs($device, $check_sysORID)); // Check if mib available for device
258
259  if ($check_permissions && $mib_permitted)
260  {
261    // Check if MIB permitted by config
262    $mib_permitted = $mib_permitted && (!isset($config['mibs'][$mib]['enable']) || $config['mibs'][$mib]['enable']);
263
264    // Check if MIB disabled on device by web interface or polling process
265    $mibs_disabled = get_device_mibs_disabled($device);
266    $mib_permitted = $mib_permitted && !in_array($mib, $mibs_disabled);
267  }
268
269  return $mib_permitted;
270}
271
272/**
273 * Return cached MIBs array available for device (from os definitions)
274 * By default includes sysORID-supplied MIBs unless check_sysORID is false
275 * When requesting list without sysORID, result will NOT be cached
276 *
277 * @param array|integer $device Device array
278 * @param boolean $check_sysORID Check or not mibs from sysORID table
279 * @param array $mibs_order Order how load available mibs. Default: ['model', 'os', 'group', 'default']
280 * @return array List of supported MIBs
281 */
282function get_device_mibs($device, $check_sysORID = TRUE, $mibs_order = NULL)
283{
284  global $config, $cache;
285
286  if (is_numeric($device))
287  {
288    $device_id = $device;
289    $device    = device_by_id_cache($device_id);
290  } else {
291    $device_id = $device['device_id'];
292  }
293
294  // Set custom mibs order
295  $mibs_order_default = array('model', 'os', 'group', 'default');
296  if      (empty($mibs_order))
297  {
298    // Default order: per-model mibs (if model set) -> os mibs -> os group mibs -> default mibs
299    $mibs_order = $mibs_order_default;
300  }
301  else if (!is_array($mibs_order))
302  {
303    // Order can passed as string with comma: 'model,os,group,default'
304    $mibs_order = explode(',', $mibs_order);
305  }
306
307  // Check if custom order used, than set first from passed argument, second from default
308  if ($mibs_order_custom = $mibs_order !== $mibs_order_default)
309  {
310    // Set first from passed argument, second
311    $mibs_order = array_unique(array_merge($mibs_order, $mibs_order_default));
312  }
313
314  // Do not cache MIBs if custom order used, unknown $device_id or in PHPUNIT
315  $use_cache = $device_id && !$mibs_order_custom && !defined('__PHPUNIT_PHAR__');
316
317  // Cache main device MIBs list
318  if (!isset($cache['devices']['mibs'][$device_id]))
319  {
320    $mibs = array();
321    $model_array = get_model_array($device);
322    foreach ($mibs_order as $order)
323    {
324      switch ($order)
325      {
326        case 'model':
327          if (is_array($model_array) && isset($model_array['mibs']))
328          {
329            $mibs = array_merge($mibs, (array)$model_array['mibs']);
330          }
331          break;
332        case 'os':
333          $mibs = array_merge((array)$mibs, (array)$config['os'][$device['os']]['mibs']);
334          break;
335        case 'group':
336          $os_group = $config['os'][$device['os']]['group'];
337          $mibs = array_merge((array)$mibs, (array)$config['os_group'][$os_group]['mibs']);
338          break;
339        case 'default':
340          //var_dump($config['os_group']['default']['mibs']);
341          $mibs = array_merge((array)$mibs, (array)$config['os_group']['default']['mibs']);
342          break;
343      }
344    }
345    $mibs = array_unique($mibs);
346
347    //$mibs = array_unique(array_merge((array)$mibs, (array)$config['os'][$device['os']]['mibs'],
348    //                                 (array)$config['os_group'][$config['os'][$device['os']]['group']]['mibs'],
349    //                                 (array)$config['os_group']['default']['mibs']));
350
351    // Remove blacklisted MIBs from array
352    $mibs = array_diff($mibs, get_device_mibs_blacklist($device));
353
354    if ($use_cache)
355    {
356      $cache['devices']['mibs'][$device_id] = $mibs;
357    }
358  } else {
359    $mibs = $cache['devices']['mibs'][$device_id];
360  }
361  //print_error('$cache[\'devices\'][\'mibs\'][$device_id]');
362  //print_vars($cache['devices']['mibs'][$device_id]);
363  //print_vars($mibs);
364
365  // Add and cache sysORID supplied MIBs if any
366  if ($check_sysORID)
367  {
368    if (!isset($cache['devices']['mibs_sysORID'][$device_id]))
369    {
370      $sysORID = json_decode(get_entity_attrib('device', $device, 'sysORID'), TRUE);
371      if (is_array($sysORID))
372      {
373        // Leave only not exist in main MIBs and blacklist
374        $sysORID = array_diff($sysORID, get_device_mibs_blacklist($device), $mibs);
375        //print_vars($sysORID);
376      } else {
377        $sysORID = array(); // Leave empty
378      }
379      if ($use_cache)
380      {
381        $cache['devices']['mibs_sysORID'][$device_id] = $sysORID;
382      }
383    } else {
384      $sysORID = $cache['devices']['mibs_sysORID'][$device_id];
385    }
386    // Attach sysORID MIBs
387    $mibs = array_merge($mibs, (array)$sysORID);
388  }
389
390  //print_error('$mibs');
391  return $mibs;
392}
393
394/**
395 * Return array of permitted MIBs for device
396 *
397 * @param array $device
398 * @param mixed $mibs_order
399 *
400 * @return array All MIB permitted for device
401 */
402function get_device_mibs_permitted($device, $mibs_order = NULL)
403{
404  $mibs = [];
405  foreach (get_device_mibs($device, TRUE, $mibs_order) as $mib)
406  {
407    if (is_device_mib($device, $mib))
408    {
409      $mibs[] = $mib;
410    }
411  }
412
413  return $mibs;
414}
415
416/**
417 * Return array with blacklisted MIBs for current device
418 *
419 * @param array $device Device array
420 * @return array Blacklisted MIBs
421 */
422function get_device_mibs_blacklist(array $device)
423{
424  global $config;
425  $blacklist = array_unique(array_merge((array)$config['os'][$device['os']]['mib_blacklist'],
426                                        (array)$config['os_group'][$config['os'][$device['os']]['group']]['mib_blacklist']));
427  return $blacklist;
428}
429
430/**
431 * Return array from DB with disabled mibs for device
432 *
433 * @param array|integer $device Device array
434 * @return array List of disabled MIBs for device
435 */
436function get_device_mibs_disabled($device)
437{
438  global $cache;
439
440  if (is_numeric($device))
441  {
442    $device_id = $device;
443    $device    = device_by_id_cache($device_id);
444  } else {
445    $device_id = $device['device_id'];
446  }
447
448  // Return cached
449  if (isset($cache['devices']['mibs_disabled'][$device_id]))
450  {
451    return $cache['devices']['mibs_disabled'][$device_id];
452  }
453
454  // CLEANME. Compatibility, remove in r10000, but not before CE 0.19.4 (Apr, 2019)
455  if (get_db_version() < 405)
456  {
457    $disabled = [];
458    // Old disabled mibs stored in device attribs
459    foreach (get_entity_attribs('device', $device['device_id']) as $attrib => $value)
460    {
461      if (str_starts($attrib, 'mib_') && $value)
462      {
463        $disabled[] = substr($attrib, 4);
464      }
465    }
466
467    $cache['devices']['mibs_disabled'][$device_id] = $disabled;
468    return $disabled;
469  }
470
471  $params = [$device['device_id'], 'mib', '1'];
472  $where  = "`device_id` = ? AND `use` = ? AND `disabled` = ?";
473
474  if ($disabled = dbFetchColumn("SELECT `mib` FROM `devices_mibs` WHERE $where", $params))
475  {
476    $cache['devices']['mibs_disabled'][$device_id] = $disabled;
477  } else {
478    // If none disabled, cache anyway for do not query db again
479    $cache['devices']['mibs_disabled'][$device_id] = [];
480  }
481
482  return $cache['devices']['mibs_disabled'][$device_id];
483}
484
485/**
486 * Set mib disabled in DB for device.
487 * Return IDs added or changed in DB.
488 *
489 * @param array $device Device array
490 * @param string $mib MIB name
491 * @param boolean $remove Remove MIB db entry complete
492 * @param boolean $disabled TRUE for disable, FALSE for enable
493 *
494 * @return integer ID of db entry for disabled MIB
495 */
496function set_device_mib_disable($device, $mib, $remove = FALSE, $disabled = TRUE)
497{
498  if (empty($mib))
499  {
500    // MIB name required
501    print_debug(__FUNCTION__ . "() required non empty mib name.");
502    return FALSE;
503  }
504
505  if (is_numeric($device))
506  {
507    $device_id = $device;
508    $device    = device_by_id_cache($device_id);
509  }
510
511  // Fetch/validate if MIB in db
512  $mib_db = dbFetchRow("SELECT `mib_id`, `disabled` FROM `devices_mibs` WHERE `device_id` = ? AND `use` = ? AND `mib` = ?", [$device['device_id'], 'mib', $mib]);
513
514  // Just delete from DB if remove requested
515  if ($remove)
516  {
517    if ($mib_db['mib_id'])
518    {
519      return dbDelete('devices_mibs', '`mib_id` = ?', [$mib_db['mib_id']]);
520    } else {
521      return FALSE;
522    }
523  }
524
525  // Convert to sql boolean
526  $disabled = ($disabled ? '1' : '0');
527
528  if (!$mib_db['mib_id'])
529  {
530    // Not exist, insert
531    return dbInsert(array('device_id' => $device['device_id'], 'mib' => $mib,
532                          'use' => 'mib', 'disabled' => '1'), 'devices_mibs');
533  }
534  else if ($mib_db['disabled'] != $disabled)
535  {
536    // Exist, but changed
537    dbUpdate(array('disabled' => $disabled), 'devices_mibs', '`mib_id` = ?', array($mib_db['mib_id']));
538  }
539
540  return $mib_db['mib_id'];
541}
542
543/**
544 * Set mib enabled in DB for device.
545 * Return IDs added or changed in DB.
546 *
547 * @param array $device Device array
548 * @param string $mib MIB name
549 * @param boolean $remove Remove MIB db entry complete
550 * @param boolean $disabled TRUE for disable, FALSE for enable
551 *
552 * @return integer ID of db entry for disabled MIB
553 */
554function set_device_mib_enable($device, $mib, $remove = FALSE, $disabled = FALSE)
555{
556  // Call to disable, just with different default
557  return set_device_mib_disable($device, $mib, $remove, $disabled);
558}
559
560/**
561 * Return array from DB with disabled Objects for device and specified MIB name
562 *
563 * @param array|integer $device Device array
564 * @param string $mib MIB name
565 *
566 * @return array List of disabled MIBs for device
567 */
568function get_device_objects_disabled($device, $mib = NULL)
569{
570  global $cache;
571
572  if (is_numeric($device))
573  {
574    $device_id = $device;
575    $device    = device_by_id_cache($device_id);
576  } else {
577    $device_id = $device['device_id'];
578  }
579
580  $params = [$device['device_id'], 'oid', '1'];
581  $where  = "`device_id` = ? AND `use` = ? AND `disabled` = ?";
582  if (empty($mib))
583  {
584    // For empty mib see NULL or empty string
585    // This is common for numeric Oids
586    $where .= " AND (`mib` = '' OR `mib` IS NULL)";
587    $mib = '__mib'; // Just for caching
588  } else {
589    $where .= " AND `mib` = ?";
590    $params[] = $mib;
591  }
592
593  // Return cached
594  if (isset($cache['devices']['objects_disabled'][$device_id][$mib]))
595  {
596    return $cache['devices']['objects_disabled'][$device_id][$mib];
597  }
598
599  // Query db for objects
600  if ($disabled = dbFetchColumn("SELECT `object` FROM `devices_mibs` WHERE $where", $params))
601  {
602    $cache['devices']['objects_disabled'][$device_id][$mib] = $disabled;
603  } else {
604    // If none disabled, cache anyway for do not query db again
605    $cache['devices']['objects_disabled'][$device_id][$mib] = [];
606  }
607
608  return $cache['devices']['objects_disabled'][$device_id][$mib];
609}
610
611/**
612 * Set object disabled in DB for device.
613 * Return IDs added or changed in DB.
614 *
615 * @param array $device Device array
616 * @param string $object Object name
617 * @param string $mib MIB name (optional)
618 * @param boolean $remove Remove MIB db entry complete
619 * @param boolean $disabled TRUE for disable, FALSE for enable
620 *
621 * @return integer ID of db entry for disabled MIB
622 */
623function set_device_object_disable($device, $object, $mib = '', $remove = FALSE, $disabled = TRUE)
624{
625  if (empty($object))
626  {
627    // MIB name required
628    print_debug(__FUNCTION__ . "() required non empty object name.");
629    return FALSE;
630  }
631
632  if (is_numeric($device))
633  {
634    $device_id = $device;
635    $device    = device_by_id_cache($device_id);
636  }
637
638  // Initial insert array
639  $insert_array = [ 'device_id' => $device['device_id'], 'object' => $object,
640                    'use' => 'object', 'disabled' => '1' ];
641
642  $where = '`device_id` = ? AND `use` = ? AND `object` = ?';
643  $params = [$device['device_id'], 'object', $object];
644  if (empty($mib))
645  {
646    // For empty mib see NULL or empty string
647    // This is common for numeric Oids
648    $where .= " AND (`mib` = '' OR `mib` IS NULL)";
649  } else {
650    $where .= " AND `mib` = ?";
651    $params[] = $mib;
652
653    // Append mib to insert
654    $insert_array['mib'] = $mib;
655  }
656  // Fetch/validate if MIB in db
657  $mib_db = dbFetchRow("SELECT `mib_id`, `disabled` FROM `devices_mibs` WHERE $where", $params);
658
659  // Just delete from DB if remove requested
660  if ($remove)
661  {
662    if ($mib_db['mib_id'])
663    {
664      return dbDelete('devices_mibs', '`mib_id` = ?', [$mib_db['mib_id']]);
665    } else {
666      return FALSE;
667    }
668  }
669
670  // Convert to sql boolean
671  $disabled = ($disabled ? '1' : '0');
672
673  if (!$mib_db['mib_id'])
674  {
675    // Not exist, insert
676    return dbInsert($insert_array, 'devices_mibs');
677  }
678  else if ($mib_db['disabled'] != $disabled)
679  {
680    // Exist, but changed
681    dbUpdate(array('disabled' => $disabled), 'devices_mibs', '`mib_id` = ?', array($mib_db['mib_id']));
682  }
683
684  return $mib_db['mib_id'];
685}
686
687/**
688 * Set object enabled in DB for device.
689 * Return IDs added or changed in DB.
690 *
691 * @param array $device Device array
692 * @param string $object Object name
693 * @param string $mib MIB name (optional)
694 * @param boolean $remove Remove MIB db entry complete
695 * @param boolean $disabled TRUE for disable, FALSE for enable
696 *
697 * @return integer ID of db entry for disabled MIB
698 */
699function set_device_object_enable($device, $object, $mib = '', $remove = FALSE, $disabled = FALSE)
700{
701  // Call to disable, just with different default
702  return set_device_object_disable($device, $object, $mib, $remove, $disabled);
703}
704
705/* End mib functions */
706
707// DOCME needs phpdoc block
708// TESTME needs unit testing
709function get_entity_by_id_cache($entity_type, $entity_id)
710{
711  global $cache;
712
713  $translate = entity_type_translate_array($entity_type);
714
715  if (is_array($cache[$entity_type][$entity_id]))
716  {
717
718    return $cache[$entity_type][$entity_id];
719
720  } else {
721
722    switch($entity_type)
723    {
724      case "bill":
725        if (function_exists('get_bill_by_id'))
726        {
727          $entity = get_bill_by_id($entity_id);
728        }
729        break;
730
731      case "port":
732        $entity = get_port_by_id($entity_id);
733        break;
734
735      default:
736        $sql = 'SELECT * FROM `'.$translate['table'].'`';
737
738        if (isset($translate['state_table']))
739        {
740          $sql .= ' LEFT JOIN `'.$translate['state_table'].'` USING (`'.$translate['id_field'].'`)';
741        }
742
743          if (isset($translate['parent_table']))
744          {
745              $sql .= ' LEFT JOIN `'.$translate['parent_table'].'` USING (`'.$translate['parent_id_field'].'`)';
746          }
747
748        $sql .= ' WHERE `'.$translate['table'].'`.`'.$translate['id_field'].'` = ?';
749
750        $entity = dbFetchRow($sql, array($entity_id));
751        if (function_exists('humanize_'.$entity_type)) { $do = 'humanize_'.$entity_type; $do($entity); }
752        else if (isset($translate['humanize_function']) && function_exists($translate['humanize_function'])) { $do = $translate['humanize_function']; $do($entity); }
753        break;
754    }
755
756    if (is_array($entity))
757    {
758      entity_rewrite($entity_type, $entity);
759      $cache[$entity_type][$entity_id] = $entity;
760      return $entity;
761    }
762  }
763
764  return FALSE;
765}
766
767/* Network/ARP/MAC specific entity functions */
768
769/**
770 * Fetch entity IDs by network. Currently supported entities: device, port, ip (ipv4, ipv6 for force specific IP version)
771 *
772 * See parse_network() for possible valid network queries.
773 *
774 * @param string       $entity_type  Entity type (device, port)
775 * @param string|array $network      Valid network string (or array)
776 * @param string       $add_where    Custom where string
777 *
778 * @return array       Array with entity specific IDs
779 */
780function get_entity_ids_ip_by_network($entity_type, $network, $add_where = '')
781{
782
783  // Recursive query for array of networks
784  if (is_array($network))
785  {
786    $ids = array();
787    foreach ($network as $entry)
788    {
789      if ($entry_ids = get_entity_ids_ip_by_network($entity_type, $entry, $add_where))
790      {
791        $ids = array_merge($ids, $entry_ids);
792      }
793    }
794
795    return $ids;
796  }
797
798  // Parse for valid network string
799  $network_array = parse_network($network);
800  //print_vars($network_array);
801  if (!$network_array)
802  {
803    // Incorrect network/address string passed
804    return FALSE;
805  }
806
807  $query = 'SELECT ';
808  $join  = '';
809  $where = ' WHERE 1 ';
810  switch ($entity_type)
811  {
812    case 'ipv4':
813      // Force request IPv6 address
814      $network_array['ip_type'] = 'ipv4';
815      $query .= ' `ipv4_address_id`';
816      break;
817    case 'ipv6':
818      // Force request IPv6 address
819      $network_array['ip_type'] = 'ipv6';
820      $query .= ' `ipv6_address_id`';
821      break;
822    case 'ip':
823      $query .= ($network_array['ip_version'] == 4) ? ' `ipv4_address_id`' : ' `ipv6_address_id`';
824      break;
825
826    case 'device':
827    case 'devices':
828      $query .= ' DISTINCT `device_id`';
829      break;
830
831    case 'port':
832    case 'ports':
833      $query .= ' DISTINCT `port_id`';
834      break;
835  }
836
837  switch ($network_array['ip_type'])
838  {
839    case 'ipv4':
840      $query .= ' FROM `ipv4_addresses`';
841      if ($network_array['query_type'] == 'single')
842      {
843        // Exactly IP match
844        $where .= ' AND `ipv4_binary` = ?';
845        $param[] = $network_array['address_binary'];
846      }
847      else if ($network_array['query_type'] == 'network')
848      {
849        // Match IP in network
850        $where .= ' AND `ipv4_binary` >= ? AND `ipv4_binary` <= ?';
851        $param[] = $network_array['network_start_binary'];
852        $param[] = $network_array['network_end_binary'];
853      } else {
854        // Match IP addresses by part of string
855        $where .=  generate_query_values($network_array['address'], 'ipv4_address', $network_array['query_type']);
856      }
857      break;
858    case 'ipv6':
859      $query .= ' FROM `ipv6_addresses`';
860      if ($network_array['query_type'] == 'single')
861      {
862        // Exactly IP match
863        $where .= ' AND `ipv6_binary` = ?';
864        $param[] = $network_array['address_binary'];
865      }
866      else if ($network_array['query_type'] == 'network')
867      {
868        // Match IP in network
869        $where .= ' AND `ipv6_binary` >= ? AND `ipv6_binary` <= ?';
870        $param[] = $network_array['network_start_binary'];
871        $param[] = $network_array['network_end_binary'];
872      } else {
873        // Match IP addresses by part of string
874        $where .= ' AND (' . generate_query_values($network_array['address'], 'ipv6_address',    $network_array['query_type'], FALSE) .
875                  ' OR '   . generate_query_values($network_array['address'], 'ipv6_compressed', $network_array['query_type'], FALSE) . ')';
876      }
877      break;
878  }
879
880  if (FALSE)
881  {
882    // Ignore disabled/deleted/ignored
883    $where .= ' AND `device_id` NOT IN (SELECT `device_id` FROM `devices` WHERE `disabled` = "1" OR `ignore` = "1")';
884    $where .= ' AND `port_id` NOT IN (SELECT `port_id` FROM `ports` WHERE `deleted` = "1" OR `ignore` = "1")';
885  } else {
886    // Always ignore deleted ports
887    $join = ' LEFT JOIN `ports` USING (`device_id`, `port_id`) ';
888    // IS NULL allow to search addresses without associated port
889    $where .= ' AND (`ports`.`deleted` != "1" OR `ports`.`deleted` IS NULL)';
890  }
891  $query .= $join;
892  $where .= $add_where; // Additional query, ie limit by device_id or port_id
893
894  $ids = dbFetchColumn($query . $where, $param);
895  //$ids = dbFetchColumn($query . $where, $param);
896  //print_vars($ids);
897
898  return $ids;
899}
900
901// DOCME needs phpdoc block
902// TESTME needs unit testing
903function entity_type_translate($entity_type)
904{
905  $data = entity_type_translate_array($entity_type);
906  if (!is_array($data)) { return NULL; }
907
908  return array($data['table'], $data['id_field'], $data['name_field'], $data['ignore_field'], $data['entity_humanize']);
909}
910
911// Returns a text name from an entity type and an id
912// A little inefficient.
913// DOCME needs phpdoc block
914// TESTME needs unit testing
915function entity_name($type, $entity)
916{
917  global $config, $entity_cache;
918
919  if (is_numeric($entity))
920  {
921    $entity = get_entity_by_id_cache($type, $entity);
922  }
923
924  $translate = entity_type_translate_array($type);
925
926  $text = $entity[$translate['name_field']];
927
928  return($text);
929}
930
931// Returns a text name from an entity type and an id
932// A little inefficient.
933// DOCME needs phpdoc block
934// TESTME needs unit testing
935function entity_short_name($type, $entity)
936{
937  global $config, $entity_cache;
938
939  if (is_numeric($entity))
940  {
941    $entity = get_entity_by_id_cache($type, $entity);
942  }
943
944  $translate = entity_type_translate_array($type);
945
946  $text = $entity[$translate['name_field']];
947
948  return($text);
949}
950
951// Returns a text description from an entity type and an id
952// A little inefficient.
953// DOCME needs phpdoc block
954// TESTME needs unit testing
955function entity_descr($type, $entity)
956{
957  global $config, $entity_cache;
958
959  if (is_numeric($entity))
960  {
961    $entity = get_entity_by_id_cache($type, $entity);
962  }
963
964  $translate = entity_type_translate_array($type);
965
966  $text = $entity[$translate['entity_descr_field']];
967
968  return($text);
969}
970/**
971 * Generate entity description based on their type and discovery definition.
972 *
973 * @param string $entity_type Entity type
974 * @param array $definition Entity discovery definition entry
975 * @param array $descr_entry Array with possible descr strings received for example from snmpwalk, also used for tag replaces
976 * @param integer $count Optional entity count for current Table, when > 1 descr can use optional index or different descr
977 * @return string Parsed entity description
978 */
979function entity_descr_definition($entity_type, $definition, $descr_entry, $count = 1)
980{
981  //print_vars($definition);
982  //print_vars($descr_entry);
983
984  // Per index definitions
985  if (isset($descr_entry['index']) && isset($definition['indexes'][$descr_entry['index']]['descr']))
986  {
987    // Override with per index descr definition
988    $definition['descr'] = $definition['indexes'][$descr_entry['index']]['descr'];
989  }
990
991  // Descr contain tags, prefer tag replaces
992  $use_tags = isset($definition['descr']) && str_contains($definition['descr'], '%');
993
994  if (isset($definition['oid_descr']) && strpos($definition['oid_descr'], '::'))
995  {
996    list($mib, $definition['oid_descr']) = explode("::", $definition['oid_descr']);
997  }
998  if (isset($definition['oid_descr']) && strlen($descr_entry[$definition['oid_descr']]))
999  {
1000    $descr = $descr_entry[$definition['oid_descr']];
1001    if (!$use_tags)
1002    {
1003      // not tags and oid_descr exist, just return it
1004      if (isset($definition['descr_transform']))
1005      {
1006        $descr = string_transform($descr, $definition['descr_transform']);
1007      }
1008      return $descr;
1009    }
1010
1011    // Append to array for correct replace
1012    $descr_entry['oid_descr'] = $descr;
1013  }
1014
1015  if (isset($definition['descr']))
1016  {
1017    // Use definition descr
1018    $descr = $definition['descr'];
1019
1020    if ($use_tags)
1021    {
1022
1023      // Multipart index: Oid.0.1.2 -> %index0%, %index1%, %index2%
1024      if (isset($descr_entry['index']) && preg_match('/%index\d+%/', $descr))
1025      {
1026        // Multipart index
1027        foreach (explode('.', $descr_entry['index']) as $k => $k_index)
1028        {
1029          $descr_entry['index'.$k] = $k_index; // Multipart indexes
1030        }
1031      }
1032
1033      // Replace tags %tag%
1034      $descr = array_tag_replace($descr_entry, $descr);
1035    }
1036    else if ($count > 1 && isset($descr_entry['index']))
1037    {
1038      // For multi append index, but always prefer to USE TAGS!
1039      $descr .= ' ' . $descr_entry['index'];
1040    }
1041
1042  }
1043
1044  // Use Entity Defaults (not defined descr or oid_descr)
1045  if (!strlen($descr))
1046  {
1047    $translate = entity_type_translate_array($entity_type);
1048    //print_vars($translate);
1049
1050    if ($count > 1 && isset($translate['name_multiple']))
1051    {
1052      $descr = $translate['name_multiple'];
1053    }
1054    else if (isset($translate['name']))
1055    {
1056      $descr = $translate['name'];
1057    } else {
1058      //$descr = 'Entity';
1059      $descr = nicecase($entity_type);
1060    }
1061
1062    if ($count > 1 && isset($descr_entry['index']))
1063    {
1064      // For multi append index
1065      $descr .= ' ' . $descr_entry['index'];
1066    }
1067  }
1068
1069  // Transform/clean definition
1070  if (isset($definition['descr_transform']))
1071  {
1072    $descr = string_transform($descr, $definition['descr_transform']);
1073  }
1074
1075  return $descr;
1076}
1077
1078/**
1079 * Rule-based entity linking.
1080 *
1081 * @param $entity_type
1082 * @param $definition
1083 * @param $device
1084 * @param $entity
1085 *
1086 * @return array
1087 */
1088function entity_measured_match_definition($device, $definition, $entity, $entity_type = NULL)
1089{
1090  // $entity_type unused currently
1091
1092  $options = array();
1093  if (!isset($definition['measured_match'])) { return $options; }
1094
1095  // Convert single match array to multi-array
1096  if (isset($definition['measured_match']['match']))
1097  {
1098    $definition['measured_match'] = array($definition['measured_match']);
1099  }
1100
1101  $measured_found = FALSE;
1102  foreach ($definition['measured_match'] as $rule)
1103  {
1104
1105    // Allow tests here to allow multiple match rules on the same sensor table (entity-mib, etc)
1106
1107    // First we make substitutions using %key%, then we run transformations
1108
1109    $rule['match'] = array_tag_replace($entity, $rule['match']);
1110
1111    if (is_array($rule['transform'])) { string_transform($rule['match'], $rule['transform']); }
1112
1113    switch($rule['entity_type'])
1114    {
1115      case 'port':
1116
1117        switch($rule['field'])
1118        {
1119          case 'ifDescr':
1120          case 'label':
1121            $sql = "SELECT `port_id`, `ifIndex` FROM `ports` WHERE `device_id` = ? AND (`ifDescr` = ? OR `ifName` = ? OR `port_label` = ? OR `port_label_short` = ?) AND `deleted` = ? LIMIT 1";
1122            $params = array($device['device_id'], $rule['match'], $rule['match'], $rule['match'], $rule['match'], 0);
1123            if ($measured = dbFetchRow($sql, $params))
1124            {
1125              $options['measured_class']            = 'port';
1126              $options['measured_entity']           = $measured['port_id'];
1127              $options['port_label']                = $measured['port_label'];
1128              print_debug('Linked to port '.$measured['port_id'].' via ifDescr');
1129              $measured_found = TRUE;
1130            }
1131            break;
1132
1133          case 'ifAlias':
1134            if ($measured = dbFetchRow("SELECT `port_id`, `ifIndex` FROM `ports` WHERE `device_id` = ? AND `ifAlias` = ? AND `deleted` = ? LIMIT 1", array($device['device_id'], $rule['match'], 0)))
1135            {
1136              $options['measured_class']            = 'port';
1137              $options['measured_entity']           = $measured['port_id'];
1138              $options['port_label']                = $measured['port_label'];
1139              print_debug('Linked to port '.$measured['port_id'].' via ifAlias');
1140              $measured_found = TRUE;
1141            }
1142            break;
1143
1144          case 'ifIndex':
1145            if ($measured = get_port_by_index_cache($device['device_id'], $rule['match']))
1146            {
1147              $options['measured_class']            = 'port';
1148              $options['measured_entity']           = $measured['port_id'];
1149              //$options['entPhysicalIndex']          = $measured['ifIndex'];
1150              $options['port_label']                = $measured['port_label'];
1151              print_debug('Linked to port '.$measured['port_id'].' via ifIndex');
1152              $measured_found = TRUE;
1153            }
1154            break;
1155        }
1156
1157        break;
1158    }
1159    if ($measured_found) { break; } // Stop foreach if measured match found
1160  }
1161
1162  return $options;
1163}
1164
1165/**
1166 * Translate an entity type to the relevant table and the identifier field name
1167 *
1168 * @param string entity_type
1169 * @return string entity_table
1170 * @return array entity_id
1171*/
1172// TESTME needs unit testing
1173function entity_type_translate_array($entity_type)
1174{
1175  $translate = $GLOBALS['config']['entities'][$entity_type];
1176
1177  // Base fields
1178  // FIXME, not listed here: agg_graphs, metric_graphs
1179  $fields = array('name',               // Base entity name
1180                  'name_multiple',      // (Optional) Plural entity name
1181                  'table',              // Table name
1182                  'table_fields',       // Array with table fields
1183                  //'state_table',        // State table name (deprecated)
1184                  //'state_fields',       // Array with state fields (deprecated)
1185                  'humanize_function',  // Humanize function name
1186                  'parent_type',        // Parent table type
1187                  'parent_table',       // Parent table name
1188                  'parent_id_field',    // Main parent id field
1189                  'where',
1190                  'icon',               // Entity icon
1191                  'graph');
1192  foreach ($fields as $field)
1193  {
1194    if (isset($translate[$field]))
1195    {
1196      $data[$field] = $translate[$field];
1197    }
1198    else if (isset($GLOBALS['config']['entities']['default'][$field]))
1199    {
1200      $data[$field] = $GLOBALS['config']['entities']['default'][$field];
1201    }
1202  }
1203
1204  // Table fields
1205  $fields_table = array(// Common fields
1206                        'id',
1207                        'device_id',
1208                        'index',
1209                        'mib',
1210                        'object',
1211                        'oid',
1212                        'name',
1213                        'shortname',
1214                        'descr',
1215                        'ignore',
1216                        'disable',
1217                        'deleted',
1218                        // Limits fields
1219                        'limit_high',       // High critical limit
1220                        'limit_high_warn',  // High warning  limit
1221                        'limit_low',        // Low  critical limit
1222                        'limit_low_warn',   // Low  warning  limit
1223                        // Value fields
1224                        'value',            // RAW value
1225                        'status',           // Entity specific status name (
1226                        'event',            // Event name (ok, alert, warning, etc..)
1227                        'uptime',           // Uptime
1228                        'last_change',      // Last changed time
1229                        // Measured entity fields
1230                        'measured_type',    // Measured entity type
1231                        'measured_id',      // Measured entity id
1232    );
1233  if (isset($translate['table_fields']))
1234  {
1235    // New definition style
1236    foreach ($translate['table_fields'] as $field => $entry)
1237    {
1238      // Add old style name (ie 'id_field') for compatibility
1239      $data[$field . '_field'] = $entry;
1240    }
1241  }
1242
1243  return $data;
1244}
1245
1246/**
1247 * Returns TRUE if the logged in user is permitted to view the supplied entity.
1248 *
1249 * @param $entity_id
1250 * @param $entity_type
1251 * @param $device_id
1252 * @param $permissions Permissions array, by default used global var $permissions generated by permissions_cache()
1253 *
1254 * @return bool
1255 */
1256// TESTME needs unit testing
1257function is_entity_permitted($entity_id, $entity_type, $device_id = NULL, $permissions = NULL)
1258{
1259  if (is_null($permissions) && isset($GLOBALS['permissions']))
1260  {
1261    // Note, pass permissions array by param used in permissions_cache()
1262    $permissions = $GLOBALS['permissions'];
1263  }
1264
1265  //if (OBS_DEBUG)
1266  //{
1267  //  print_vars($permissions);
1268  //  print_vars($_SESSION);
1269  //  print_vars($GLOBALS['auth']);
1270  //  print_vars(is_graph());
1271  //}
1272
1273  if (!is_numeric($device_id)) { $device_id = get_device_id_by_entity_id($entity_id, $entity_type); }
1274
1275  if (isset($_SESSION['user_limited']) && !$_SESSION['user_limited'])
1276  {
1277    // User not limited (userlevel >= 5)
1278    $allowed = TRUE;
1279  }
1280  else if (is_numeric($device_id) && device_permitted($device_id))
1281  {
1282    $allowed = TRUE;
1283  }
1284  else if (isset($permissions[$entity_type][$entity_id]) && $permissions[$entity_type][$entity_id])
1285  {
1286    $allowed = TRUE;
1287  }
1288  else if (isset($GLOBALS['auth']) && is_graph())
1289  {
1290    $allowed = $GLOBALS['auth'];
1291  } else {
1292    $allowed = FALSE;
1293  }
1294
1295  if (OBS_DEBUG)
1296  {
1297    $debug_msg = "PERMISSIONS CHECK. Entity type: $entity_type, Entity ID: $entity_id, Device ID: ".($device_id ? $device_id : 'NULL').", Allowed: ".($allowed ? 'TRUE' : 'FALSE').".";
1298    if (isset($GLOBALS['notifications']))
1299    {
1300      $GLOBALS['notifications'][] = array('text' => $debug_msg, 'severity' => 'debug');
1301    } else {
1302      print_debug($debug_msg);
1303    }
1304  }
1305  return $allowed;
1306}
1307
1308/**
1309 * Generates standardised set of array fields for use in entity-generic functions and code.
1310 * Has no return value, it modifies the $entity array in-place.
1311 *
1312 * @param $entity_type string
1313 * @param $entity array
1314 *
1315 */
1316// TESTME needs unit testing
1317function entity_rewrite($entity_type, &$entity)
1318{
1319  $translate = entity_type_translate_array($entity_type);
1320
1321  // By default, fill $entity['entity_name'] with name_field contents.
1322  if (isset($translate['name_field'])) { $entity['entity_name'] = $entity[$translate['name_field']]; }
1323
1324  // By default, fill $entity['entity_shortname'] with shortname_field contents. Fallback to entity_name when field name is not set.
1325  if (isset($translate['shortname_field'])) { $entity['entity_shortname'] = $entity[$translate['name_field']]; } else { $entity['entity_shortname'] = $entity['entity_name']; }
1326
1327  // By default, fill $entity['entity_descr'] with descr_field contents.
1328  if (isset($translate['descr_field'])) { $entity['entity_descr'] = $entity[$translate['descr_field']]; }
1329
1330  // By default, fill $entity['entity_id'] with id_field contents.
1331  if (isset($translate['id_field'])) { $entity['entity_id'] = $entity[$translate['id_field']]; }
1332
1333  switch($entity_type)
1334  {
1335    case "bgp_peer":
1336      // Special handling of name/shortname/descr for bgp_peer, since it combines multiple elements.
1337
1338      if (Net_IPv6::checkIPv6($entity['bgpPeerRemoteAddr']))
1339      {
1340        $addr = Net_IPv6::compress($entity['bgpPeerRemoteAddr']);
1341      } else {
1342        $addr = $entity['bgpPeerRemoteAddr'];
1343      }
1344
1345      $entity['entity_name']      = "AS".$entity['bgpPeerRemoteAs'] ." ". $addr;
1346      $entity['entity_shortname'] = $addr;
1347      $entity['entity_descr']     = $entity['astext'];
1348      break;
1349
1350    case "sla":
1351      $entity['entity_name']      = 'SLA #' . $entity['sla_index'];
1352      if (!empty($entity['sla_target']) && ($entity['sla_target'] != $entity['sla_tag']))
1353      {
1354        if (get_ip_version($entity['sla_target']) === 6)
1355        {
1356          $sla_target = Net_IPv6::compress($entity['sla_target'], TRUE);
1357        } else {
1358          $sla_target = $entity['sla_target'];
1359        }
1360        $entity['entity_name']   .= ' (' . $entity['sla_tag'] . ': ' . $sla_target . ')';
1361      } else {
1362        $entity['entity_name']   .= ' (' . $entity['sla_tag'] . ')';
1363      }
1364      $entity['entity_shortname'] = "#". $entity['sla_index'] . " (". $entity['sla_tag'] . ")";
1365      break;
1366
1367    case "pseudowire":
1368      $entity['entity_name']      = $entity['pwID'] . ($entity['pwDescr'] ? " (". $entity['pwDescr'] . ")" : '');
1369      $entity['entity_shortname'] = $entity['pwID'];
1370      break;
1371  }
1372}
1373
1374/**
1375 * Generates a URL to reach the entity's page (or the most specific list page the entity appears on)
1376 * Has no return value, it modifies the $entity array in-place.
1377 *
1378 * @param $entity_type string
1379 * @param $entity array
1380 *
1381 */
1382// TESTME needs unit testing
1383function generate_entity_link($entity_type, $entity, $text = NULL, $graph_type = NULL, $escape = TRUE, $options = FALSE)
1384{
1385  if (is_numeric($entity))
1386  {
1387    $entity = get_entity_by_id_cache($entity_type, $entity);
1388  }
1389  // Compat with old boolean $short option
1390  if (is_array($options))
1391  {
1392    $short = isset($options['short']) && $options['short'];
1393    $icon  = isset($options['icon'])  && $options['icon'];
1394  } else {
1395    $short = $options;
1396    $icon  = FALSE;
1397  }
1398  if ($icon)
1399  {
1400    // Get entity icon and force do not escape
1401    $text = get_icon($GLOBALS['config']['entities'][$entity_type]['icon']);
1402    $escape = FALSE;
1403  }
1404
1405  entity_rewrite($entity_type, $entity);
1406
1407  switch($entity_type)
1408  {
1409    case "device":
1410      if ($icon)
1411      {
1412        $link = generate_device_link($entity, $text, [], FALSE);
1413      } else {
1414        $link = generate_device_link($entity, short_hostname($entity['hostname'], 16));
1415      }
1416      break;
1417    case "mempool":
1418      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'health', 'metric' => 'mempool'));
1419      break;
1420    case "processor":
1421      //r($entity);
1422      if (isset($entity['id']) && is_array($entity['id']))
1423      {
1424        // Multi-processors list
1425        $ids = implode(',', $entity['id']);
1426        $entity['entity_id'] = $ids;
1427      } else {
1428        $ids = $entity['processor_id'];
1429      }
1430      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'health', 'metric' => 'processor', 'processor_id' => $ids));
1431      break;
1432    case "status":
1433      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'health', 'metric' => 'status', 'id' => $entity['status_id']));
1434      break;
1435    case "sensor":
1436      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'health', 'metric' => $entity['sensor_class'], 'id' => $entity['sensor_id']));
1437      break;
1438    case "counter":
1439      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'health', 'metric' => 'counter', 'id' => $entity['counter_id']));
1440      break;
1441    case "printersupply":
1442      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'printing', 'supply' => $entity['supply_type']));
1443      break;
1444    case "port":
1445      if ($icon)
1446      {
1447        $link = generate_port_link($entity, $text, $graph_type, FALSE, FALSE);
1448      } else {
1449        $link = generate_port_link($entity, NULL, $graph_type, $escape, $short);
1450      }
1451      break;
1452    case "storage":
1453      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'health', 'metric' => 'storage'));
1454      break;
1455    case "bgp_peer":
1456      $url = generate_url(array('page' => 'device', 'device' => ($entity['peer_device_id'] ? $entity['peer_device_id'] : $entity['device_id']), 'tab' => 'routing', 'proto' => 'bgp'));
1457      break;
1458    case "netscalervsvr":
1459      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'loadbalancer', 'type' => 'netscaler_vsvr', 'vsvr' => $entity['vsvr_id']));
1460      break;
1461    case "netscalersvc":
1462      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'loadbalancer', 'type' => 'netscaler_services', 'svc' => $entity['svc_id']));
1463      break;
1464    case "netscalersvcgrpmem":
1465      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'loadbalancer', 'type' => 'netscaler_servicegroupmembers', 'svc' => $entity['svc_id']));
1466      break;
1467    case "p2pradio":
1468      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'p2pradios'));
1469      break;
1470    case "sla":
1471      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'slas', 'id' => $entity['sla_id']));
1472      break;
1473    case "pseudowire":
1474      $url = generate_url(array('page' => 'device', 'device' => $entity['device_id'], 'tab' => 'pseudowires', 'id' => $entity['pseudowire_id']));
1475      break;
1476    case "maintenance":
1477      $url = generate_url(array('page' => 'alert_maintenance', 'maintenance' => $entity['maint_id']));
1478      break;
1479    case "group":
1480      $url = generate_url(array('page' => 'group', 'group_id' => $entity['group_id']));
1481      break;
1482    case "virtualmachine":
1483      // If we know this device by its vm name in our system, create a link to it, else just print the name.
1484      if (get_device_id_by_hostname($entity['vm_name']))
1485      {
1486        $link = generate_device_link(device_by_name($entity['vm_name']));
1487      } else {
1488        // Hardcode $link to just show the name, no actual link
1489        $link = $entity['vm_name'];
1490      }
1491      break;
1492    default:
1493      $url = NULL;
1494  }
1495
1496  if (isset($link))
1497  {
1498    return $link;
1499  }
1500
1501  if (!isset($text))
1502  {
1503    if ($short && $entity['entity_shortname'])
1504    {
1505      $text = $entity['entity_shortname'];
1506    } else {
1507      $text = $entity['entity_name'];
1508    }
1509  }
1510  if ($escape) { $text = escape_html($text); }
1511  $link = '<a href="' . $url . '" class="entity-popup ' . $entity['html_class'] . '" data-eid="' . $entity['entity_id'] . '" data-etype="' . $entity_type . '">' . $text . '</a>';
1512
1513  return($link);
1514}
1515
1516/**
1517 * This function generate link to entity, but without any text descriptions
1518 *
1519 * @param $entity_type
1520 * @param $entity
1521 *
1522 * @return string
1523 */
1524function generate_entity_icon_link($entity_type, $entity)
1525{
1526  return generate_entity_link($entity_type, $entity, NULL, NULL, FALSE, ['icon' => TRUE]);
1527}
1528
1529/**
1530 * Fetch rrd filename for specified Entity ID
1531 *
1532 * @param string  $entity_type Entity type
1533 * @param integer $entity_id   Entity ID
1534 *
1535 * @return string      RRD filename
1536 */
1537function get_entity_rrd_by_id($entity_type, $entity_id)
1538{
1539  $entity = get_entity_by_id_cache($entity_type, $entity_id);
1540  $device = device_by_id_cache($entity['device_id']);
1541
1542  switch ($entity_type)
1543  {
1544    case 'sensor':
1545      $filename = get_sensor_rrd($device, $entity);
1546      break;
1547    case 'status':
1548      $filename = get_status_rrd($device, $entity);
1549      break;
1550    case 'counter':
1551      $filename = get_counter_rrd($device, $entity);
1552      break;
1553  }
1554
1555  return $filename;
1556}
1557
1558// EOF
1559