. * * @package LibreNMS * @link http://librenms.org * @copyright 2015 Aaron Daniels * @author Aaron Daniels */ namespace LibreNMS; class Component { /* * These fields are used in the component table. They are returned in the array * so that they can be modified but they can not be set as user attributes. We * also set their default values. */ private $reserved = array( 'type' => '', 'label' => '', 'status' => 0, 'ignore' => 0, 'disabled' => 0, 'error' => '', ); public function getComponentType($TYPE = null) { if (is_null($TYPE)) { $SQL = "SELECT DISTINCT `type` as `name` FROM `component` ORDER BY `name`"; $row = dbFetchRow($SQL, array()); } else { $SQL = "SELECT DISTINCT `type` as `name` FROM `component` WHERE `type` = ? ORDER BY `name`"; $row = dbFetchRow($SQL, array($TYPE)); } if (!isset($row)) { // We didn't find any component types return false; } else { // We found some.. return $row; } } public function getComponents($device_id = null, $options = array()) { // Define our results array, this will be set even if no rows are returned. $RESULT = array(); $PARAM = array(); // Our base SQL Query, with no options. $SQL = "SELECT `C`.`id`,`C`.`device_id`,`C`.`type`,`C`.`label`,`C`.`status`,`C`.`disabled`,`C`.`ignore`,`C`.`error`,`CP`.`attribute`,`CP`.`value` FROM `component` as `C` LEFT JOIN `component_prefs` as `CP` on `C`.`id`=`CP`.`component` WHERE "; // Device_id is shorthand for filter C.device_id = $device_id. if (!is_null($device_id)) { $options['filter']['device_id'] = array('=', $device_id); } // Type is shorthand for filter type = $type. if (isset($options['type'])) { $options['filter']['type'] = array('=', $options['type']); } // filter field => array(operator,value) // Filters results based on the field, operator and value $COUNT = 0; if (isset($options['filter'])) { $COUNT++; $validFields = array('device_id','type','id','label','status','disabled','ignore','error'); $SQL .= " ( "; foreach ($options['filter'] as $field => $array) { // Only add valid fields to the query if (in_array($field, $validFields)) { if ($array[0] == 'LIKE') { $SQL .= "`".$field."` LIKE ? AND "; $array[1] = "%".$array[1]."%"; } else { // Equals operator is the default $SQL .= "`".$field."` = ? AND "; } array_push($PARAM, $array[1]); } } // Strip the last " AND " before closing the bracket. $SQL = substr($SQL, 0, -5)." )"; } if ($COUNT == 0) { // Strip the " WHERE " that we didn't use. $SQL = substr($SQL, 0, -7); } // sort column direction // Add SQL sorting to the results if (isset($options['sort'])) { $SQL .= " ORDER BY ".$options['sort']; } // Get our component records using our built SQL. $COMPONENTS = dbFetchRows($SQL, $PARAM); // if we have no components we need to return nothing if (count($COMPONENTS) == 0) { return $RESULT; } // Add the AVP's to the array. foreach ($COMPONENTS as $COMPONENT) { if ($COMPONENT['attribute'] != "") { // if this component has attributes, set them in the array. $RESULT[$COMPONENT['device_id']][$COMPONENT['id']][$COMPONENT['attribute']] = $COMPONENT['value']; } } // Populate our reserved fields into the Array, these cant be used as user attributes. foreach ($COMPONENTS as $COMPONENT) { foreach ($this->reserved as $k => $v) { $RESULT[$COMPONENT['device_id']][$COMPONENT['id']][$k] = $COMPONENT[$k]; } // Sort each component array so the attributes are in order. ksort($RESULT[$RESULT[$COMPONENT['device_id']][$COMPONENT['id']]]); ksort($RESULT[$RESULT[$COMPONENT['device_id']]]); } // limit array(start,count) if (isset($options['limit'])) { $TEMP = array(); $COUNT = 0; // k = device_id, v = array of components for that device_id foreach ($RESULT as $k => $v) { // k1 = component id, v1 = component array foreach ($v as $k1 => $v1) { if (($COUNT >= $options['limit'][0]) && ($COUNT < $options['limit'][0]+$options['limit'][1])) { $TEMP[$k][$k1] = $v1; } // We are counting components. $COUNT++; } } $RESULT = $TEMP; } return $RESULT; } public function getComponentStatus($device = null) { $sql_query = "SELECT status, count(status) as count FROM component WHERE"; $sql_param = array(); $add = 0; if (!is_null($device)) { // Add a device filter to the SQL query. $sql_query .= " `device_id` = ?"; $sql_param[] = $device; $add++; } if ($add == 0) { // No filters, remove " WHERE" -6 $sql_query = substr($sql_query, 0, strlen($sql_query)-6); } $sql_query .= " GROUP BY status"; d_echo("SQL Query: ".$sql_query); // $service is not null, get only what we want. $result = dbFetchRows($sql_query, $sql_param); // Set our defaults to 0 $count = array(0 => 0, 1 => 0, 2 => 0); // Rebuild the array in a more convenient method foreach ($result as $v) { $count[$v['status']] = $v['count']; } d_echo("Component Count by Status: ".print_r($count, true)."\n"); return $count; } public function getComponentStatusLog($component = null, $start = null, $end = null) { if (($component == null) || ($start == null) || ($end == null)) { // Error... d_echo("Required arguments are missing. Component: ".$component.", Start: ".$start.", End: ".$end."\n"); return false; } // Create our return array. $return = array(); // 1. find the previous value, this is the value when $start occurred. $sql_query = "SELECT status FROM component_statuslog WHERE `component` = ? AND time < ? ORDER BY `id` desc LIMIT 1"; $sql_param = array($component,$start); $result = dbFetchRow($sql_query, $sql_param); if ($result == false) { $return['initial'] = false; } else { $return['initial'] = $result['status']; } // 2. Then we just need a list of all the entries for the time period. $sql_query = "SELECT status, time, message FROM component_statuslog WHERE `component` = ? AND time >= ? AND time < ? ORDER BY `time`"; $sql_param = array($component,$start,$end); $return['data'] = dbFetchRows($sql_query, $sql_param); d_echo("Status Log Data: ".print_r($return, true)."\n"); return $return; } public function createComponent($device_id, $TYPE) { // Prepare our default values to be inserted. $DATA = $this->reserved; // Add the device_id and type $DATA['device_id'] = $device_id; $DATA['type'] = $TYPE; // Insert a new component into the database. $id = dbInsert($DATA, 'component'); // Add a default status log entry - we always start ok. $this->createStatusLogEntry($id, 0, 'Component Created'); // Create a default component array based on what was inserted. $ARRAY = array(); $ARRAY[$id] = $DATA; unset($ARRAY[$id]['device_id']); // This doesn't belong here. return $ARRAY; } public function createStatusLogEntry($component, $status, $message) { // Add an entry to the statuslog table for a particular component. $DATA = array( 'component' => $component, 'status' => $status, 'message' => $message, ); return dbInsert($DATA, 'component_statuslog'); } public function deleteComponent($id) { // Delete a component from the database. return dbDelete('component', "`id` = ?", array($id)); } public function setComponentPrefs($device_id, $ARRAY) { // Compare the arrays. Update/Insert where necessary. $OLD = $this->getComponents($device_id); // Loop over each component. foreach ($ARRAY as $COMPONENT => $AVP) { // Make sure the component already exists. if (!isset($OLD[$device_id][$COMPONENT])) { // Error. Component doesn't exist in the database. continue; } // Ignore type, we cant change that. unset($AVP['type'],$OLD[$device_id][$COMPONENT]['type']); // If the Status has changed we need to add a log entry if ($AVP['status'] != $OLD[$device_id][$COMPONENT]['status']) { d_echo("Status Changed - Old: ".$OLD[$device_id][$COMPONENT]['status'].", New: ".$AVP['status']."\n"); $this->createStatusLogEntry($COMPONENT, $AVP['status'], $AVP['error']); } // Process our reserved components first. $UPDATE = array(); foreach ($this->reserved as $k => $v) { // does the reserved field exist, if not skip. if (isset($AVP[$k])) { // Has the value changed? if ($AVP[$k] != $OLD[$device_id][$COMPONENT][$k]) { // The value has been modified, add it to our update array. $UPDATE[$k] = $AVP[$k]; } // Unset the reserved field. We don't want to insert it below. unset($AVP[$k],$OLD[$device_id][$COMPONENT][$k]); } } // Has anything changed, do we need to update? if (count($UPDATE) > 0) { // We have data to update dbUpdate($UPDATE, 'component', '`id` = ?', array($COMPONENT)); // Log the update to the Eventlog. $MSG = "Component ".$COMPONENT." has been modified: "; foreach ($UPDATE as $k => $v) { $MSG .= $k." => ".$v.","; } $MSG = substr($MSG, 0, -1); log_event($MSG, $device_id, 'component', $COMPONENT); } // Process our AVP Adds and Updates foreach ($AVP as $ATTR => $VALUE) { // We have our AVP, lets see if we need to do anything with it. if (!isset($OLD[$device_id][$COMPONENT][$ATTR])) { // We have a newly added attribute, need to insert into the DB $DATA = array('component'=>$COMPONENT, 'attribute'=>$ATTR, 'value'=>$VALUE); dbInsert($DATA, 'component_prefs'); // Log the addition to the Eventlog. log_event("Component: " . $AVP[$COMPONENT]['type'] . "(" . $COMPONENT . "). Attribute: " . $ATTR . ", was added with value: " . $VALUE, $device_id, 'component', $COMPONENT); } elseif ($OLD[$device_id][$COMPONENT][$ATTR] != $VALUE) { // Attribute exists but the value is different, need to update $DATA = array('value'=>$VALUE); dbUpdate($DATA, 'component_prefs', '`component` = ? AND `attribute` = ?', array($COMPONENT, $ATTR)); // Add the modification to the Eventlog. log_event("Component: ".$AVP[$COMPONENT]['type']."(".$COMPONENT."). Attribute: ".$ATTR.", was modified from: ".$OLD[$COMPONENT][$ATTR].", to: ".$VALUE, $device_id, 'component', $COMPONENT); } } // End Foreach AVP // Process our Deletes. $DELETE = array_diff_key($OLD[$device_id][$COMPONENT], $AVP); foreach ($DELETE as $KEY => $VALUE) { // As the Attribute has been removed from the array, we should remove it from the database. dbDelete('component_prefs', "`component` = ? AND `attribute` = ?", array($COMPONENT,$KEY)); // Log the addition to the Eventlog. log_event("Component: " . $AVP[$COMPONENT]['type'] . "(" . $COMPONENT . "). Attribute: " . $KEY . ", was deleted.", $COMPONENT); } } return true; } }