2016-08-21 08:07:14 -05:00
< ? php
/**
* Component . php
*
* LibreNMS module to Interface with the Component System
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http :// www . gnu . org / licenses />.
*
* @ package LibreNMS
* @ link http :// librenms . org
* @ copyright 2015 Aaron Daniels < aaron @ daniels . id . au >
* @ author Aaron Daniels < aaron @ daniels . id . au >
*/
namespace LibreNMS ;
2020-05-08 00:30:56 -05:00
use App\Models\ComponentPref ;
use App\Models\ComponentStatusLog ;
use Illuminate\Support\Arr ;
use Log ;
2016-08-28 17:32:55 -05:00
class Component
{
2016-08-21 08:07:14 -05:00
/*
* 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 .
*/
2020-05-08 00:30:56 -05:00
private $reserved = [
'type' => '' ,
'label' => '' ,
'status' => 0 ,
'ignore' => 0 ,
'disabled' => 0 ,
'error' => '' ,
];
2016-08-21 08:07:14 -05:00
2017-01-19 18:19:11 +10:00
public function getComponentCount ( $device_id = null )
{
2020-05-08 00:30:56 -05:00
$counts = \App\Models\Component :: query () -> when ( $device_id , function ( $query , $device_id ) {
$query -> where ( 'device_id' , $device_id );
}) -> selectRaw ( 'type, count(*) as count' ) -> groupBy ( 'type' ) -> pluck ( 'count' , 'type' );
2017-01-19 18:19:11 +10:00
2020-05-08 00:30:56 -05:00
return $counts -> isEmpty () ? false : $counts -> all ();
2017-01-19 18:19:11 +10:00
}
2020-05-08 00:30:56 -05:00
2016-08-28 17:32:55 -05:00
public function getComponentType ( $TYPE = null )
{
2016-08-21 08:07:14 -05:00
if ( is_null ( $TYPE )) {
$SQL = " SELECT DISTINCT `type` as `name` FROM `component` ORDER BY `name` " ;
2020-05-08 00:30:56 -05:00
$row = dbFetchRow ( $SQL , []);
2016-08-28 17:32:55 -05:00
} else {
2016-08-21 08:07:14 -05:00
$SQL = " SELECT DISTINCT `type` as `name` FROM `component` WHERE `type` = ? ORDER BY `name` " ;
2020-05-08 00:30:56 -05:00
$row = dbFetchRow ( $SQL , [ $TYPE ]);
2016-08-21 08:07:14 -05:00
}
if ( ! isset ( $row )) {
// We didn't find any component types
return false ;
2016-08-28 17:32:55 -05:00
} else {
2016-08-21 08:07:14 -05:00
// We found some..
return $row ;
}
}
2020-05-08 00:30:56 -05:00
public function getComponents ( $device_id = null , $options = [])
2016-08-28 17:32:55 -05:00
{
2020-05-08 00:30:56 -05:00
$query = \App\Models\Component :: query ()
-> with ( 'prefs' );
2016-08-21 08:07:14 -05:00
// Device_id is shorthand for filter C.device_id = $device_id.
if ( ! is_null ( $device_id )) {
2020-05-08 00:30:56 -05:00
$options [ 'filter' ][ 'device_id' ] = [ '=' , $device_id ];
2016-08-21 08:07:14 -05:00
}
// Type is shorthand for filter type = $type.
if ( isset ( $options [ 'type' ])) {
2020-05-08 00:30:56 -05:00
$options [ 'filter' ][ 'type' ] = [ '=' , $options [ 'type' ]];
2016-08-21 08:07:14 -05:00
}
2020-05-08 00:30:56 -05:00
$validFields = [ 'device_id' , 'type' , 'id' , 'label' , 'status' , 'disabled' , 'ignore' , 'error' ];
2016-08-21 08:07:14 -05:00
// filter field => array(operator,value)
// Filters results based on the field, operator and value
2020-05-08 00:30:56 -05:00
foreach ( array_intersect_key ( $options [ 'filter' ], array_flip ( $validFields )) as $field => $filter ) {
$op = $filter [ 0 ];
$value = $op == 'LIKE' ? " % { $filter [ 1 ] } % " : $filter [ 1 ];
$query -> where ( $field , $op , $value );
2016-08-21 08:07:14 -05:00
}
// sort column direction
// Add SQL sorting to the results
if ( isset ( $options [ 'sort' ])) {
2020-05-08 00:30:56 -05:00
[ $column , $direction ] = explode ( ' ' , $options [ 'sort' ]);
$query -> orderBy ( $column , $direction );
2016-08-21 08:07:14 -05:00
}
// limit array(start,count)
if ( isset ( $options [ 'limit' ])) {
2020-05-08 00:30:56 -05:00
$query -> offset ( $options [ 'limit' ][ 0 ]) -> limit ( $options [ 'limit' ][ 1 ]);
2016-08-21 08:07:14 -05:00
}
2020-05-08 00:30:56 -05:00
// get and format results as expected by receivers
return $query -> get () -> groupBy ( 'device_id' ) -> map ( function ( $group ) {
return $group -> keyBy ( 'id' ) -> map ( function ( $component ) {
return $component -> prefs -> pluck ( 'value' , 'attribute' )
-> merge ( $component -> only ( array_keys ( $this -> reserved )));
});
}) -> toArray ();
2016-08-21 08:07:14 -05:00
}
2016-08-28 17:32:55 -05:00
public function getComponentStatus ( $device = null )
{
2016-08-21 08:07:14 -05:00
$sql_query = " SELECT status, count(status) as count FROM component WHERE " ;
2020-05-08 00:30:56 -05:00
$sql_param = [];
2016-08-21 08:07:14 -05:00
$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
2020-05-08 00:30:56 -05:00
$sql_query = substr ( $sql_query , 0 , strlen ( $sql_query ) - 6 );
2016-08-21 08:07:14 -05:00
}
$sql_query .= " GROUP BY status " ;
2020-05-08 00:30:56 -05:00
d_echo ( " SQL Query: " . $sql_query );
2016-08-21 08:07:14 -05:00
// $service is not null, get only what we want.
$result = dbFetchRows ( $sql_query , $sql_param );
// Set our defaults to 0
2020-05-08 00:30:56 -05:00
$count = [ 0 => 0 , 1 => 0 , 2 => 0 ];
2016-08-21 08:07:14 -05:00
// Rebuild the array in a more convenient method
foreach ( $result as $v ) {
$count [ $v [ 'status' ]] = $v [ 'count' ];
}
2020-05-08 00:30:56 -05:00
d_echo ( " Component Count by Status: " . print_r ( $count , true ) . " \n " );
2016-08-21 08:07:14 -05:00
return $count ;
}
2017-11-13 14:43:28 -06:00
public function getComponentStatusLog ( $component_id , $start , $end )
2016-08-28 17:32:55 -05:00
{
2017-11-13 14:43:28 -06:00
if (( $component_id == null ) || ( $start == null ) || ( $end == null )) {
2016-08-21 08:07:14 -05:00
// Error...
2020-05-08 00:30:56 -05:00
d_echo ( " Required arguments are missing. Component ID: " . $component_id . " , Start: " . $start . " , End: " . $end . " \n " );
2016-08-21 08:07:14 -05:00
return false ;
}
// Create our return array.
2020-05-08 00:30:56 -05:00
$return = [];
2016-08-21 08:07:14 -05:00
// 1. find the previous value, this is the value when $start occurred.
2017-11-13 14:43:28 -06:00
$sql_query = " SELECT status FROM `component_statuslog` WHERE `component_id` = ? AND `timestamp` < ? ORDER BY `id` desc LIMIT 1 " ;
2020-05-08 00:30:56 -05:00
$sql_param = [ $component_id , $start ];
2016-08-21 08:07:14 -05:00
$result = dbFetchRow ( $sql_query , $sql_param );
if ( $result == false ) {
$return [ 'initial' ] = false ;
2016-08-28 17:32:55 -05:00
} else {
2016-08-21 08:07:14 -05:00
$return [ 'initial' ] = $result [ 'status' ];
}
// 2. Then we just need a list of all the entries for the time period.
2017-11-13 14:43:28 -06:00
$sql_query = " SELECT status, `timestamp`, message FROM `component_statuslog` WHERE `component_id` = ? AND `timestamp` >= ? AND `timestamp` < ? ORDER BY `timestamp` " ;
2020-05-08 00:30:56 -05:00
$sql_param = [ $component_id , $start , $end ];
2016-08-21 08:07:14 -05:00
$return [ 'data' ] = dbFetchRows ( $sql_query , $sql_param );
2020-05-08 00:30:56 -05:00
d_echo ( " Status Log Data: " . print_r ( $return , true ) . " \n " );
2016-08-21 08:07:14 -05:00
return $return ;
}
2020-05-08 00:30:56 -05:00
public function createComponent ( $device_id , $type )
2016-08-28 17:32:55 -05:00
{
2020-05-08 00:30:56 -05:00
$component = \App\Models\Component :: create ([ 'device_id' => $device_id , 'type' => $type ]);
2016-08-21 08:07:14 -05:00
// Add a default status log entry - we always start ok.
2020-05-08 00:30:56 -05:00
$this -> createStatusLogEntry ( $component -> id , 0 , 'Component Created' );
2016-08-21 08:07:14 -05:00
// Create a default component array based on what was inserted.
2020-05-08 00:30:56 -05:00
return [ $component -> id => $component -> only ( array_keys ( $this -> reserved ))];
2016-08-21 08:07:14 -05:00
}
2017-11-13 14:43:28 -06:00
public function createStatusLogEntry ( $component_id , $status , $message )
2016-08-28 17:32:55 -05:00
{
2020-05-08 00:30:56 -05:00
try {
return ComponentStatusLog :: create ([ 'component_id' => $component_id , 'status' => $status , 'message' => $message ]) -> id ;
} catch ( \Exception $e ) {
Log :: debug ( " Failed to create component status log " );
}
return 0 ;
2016-08-21 08:07:14 -05:00
}
2016-08-28 17:32:55 -05:00
public function deleteComponent ( $id )
{
2016-08-21 08:07:14 -05:00
// Delete a component from the database.
2020-05-08 00:30:56 -05:00
return \App\Models\Component :: destroy ( $id );
2016-08-21 08:07:14 -05:00
}
2020-05-08 00:30:56 -05:00
public function setComponentPrefs ( $device_id , $updated )
2016-08-28 17:32:55 -05:00
{
2020-05-08 00:30:56 -05:00
$updated = Arr :: wrap ( $updated );
\App\Models\Component :: whereIn ( 'id' , array_keys ( $updated ))
-> with ( 'prefs' )
-> get ()
-> each ( function ( \App\Models\Component $component ) use ( $updated ) {
2020-06-05 04:36:43 +03:00
$update = $updated [ $component -> id ];
unset ( $update [ 'type' ]); // can't change type
2020-05-08 00:30:56 -05:00
// update component attributes
2020-06-05 04:36:43 +03:00
$component -> fill ( $update );
2020-05-08 00:30:56 -05:00
if ( $component -> isDirty ()) {
// Log the update to the Eventlog.
$message = " Component $component->id has been modified: " ;
$message .= collect ( $component -> getDirty ()) -> map ( function ( $value , $key ) {
return " $key => $value " ;
}) -> implode ( ',' );
// If the Status has changed we need to add a log entry
if ( $component -> isDirty ( 'status' )) {
Log :: debug ( " Status Changed - Old: " . $component -> getOriginal ( 'status' ) . " , New: $component->status\n " );
$this -> createStatusLogEntry ( $component -> id , $component -> status , $component -> error );
2016-08-21 08:07:14 -05:00
}
2020-05-08 00:30:56 -05:00
$component -> save ();
2016-08-21 08:07:14 -05:00
2020-05-08 00:30:56 -05:00
Log :: event ( $message , $component -> device_id , 'component' , 3 , $component -> id );
2016-08-21 08:07:14 -05:00
}
2020-05-08 00:30:56 -05:00
// update preferences
$prefs = collect ( $updated [ $component -> id ]) -> filter ( function ( $value , $attr ) {
return ! array_key_exists ( $attr , $this -> reserved );
});
$invalid = $component -> prefs -> keyBy ( 'id' );
foreach ( $prefs as $attribute => $value ) {
$existing = $component -> prefs -> firstWhere ( 'attribute' , $attribute );
if ( $existing ) {
$invalid -> forget ( $existing -> id );
$existing -> fill ([ 'value' => $value ]);
if ( $existing -> isDirty ()) {
Log :: event ( " Component: $component->type ( $component->id ). Attribute: $attribute , was modified from: " . $existing -> getOriginal ( 'value' ) . " , to: $value " , $device_id , 'component' , 3 , $component_id );
$existing -> save ();
}
} else {
$component -> prefs () -> save ( new ComponentPref ([ 'attribute' => $attribute , 'value' => $value ]));
Log :: event ( " Component: $component->type ( $component->id ). Attribute: $attribute , was added with value: $value " , $component -> device_id , 'component' , 3 , $component -> id );
}
2016-08-21 08:07:14 -05:00
}
2020-05-08 00:30:56 -05:00
foreach ( $invalid as $pref ) {
$pref -> delete ();
Log :: event ( " Component: $component->type ( $component->id ). Attribute: $pref->attribute , was deleted. " , $component -> device_id , 'component' , 4 );
}
});
2016-08-21 08:07:14 -05:00
return true ;
}
2017-03-29 22:54:02 -05:00
/**
* Get the component id for the first component in the array
* Only set $device_id if using the array from getCompenents (), which is keyed by device_id
*
* @ param array $component_array
* @ param int $device_id
* @ return int the component id
*/
public function getFirstComponentID ( $component_array , $device_id = null )
{
if ( ! is_null ( $device_id ) && isset ( $component_array [ $device_id ])) {
$component_array = $component_array [ $device_id ];
}
foreach ( $component_array as $id => $array ) {
return $id ;
}
return - 1 ;
}
2016-08-21 08:07:14 -05:00
}