2010-06-28 12:49:26 +00:00
< ? php
2017-02-23 22:45:50 +00:00
use LibreNMS\RRD\RrdDefinition ;
2016-08-28 12:32:58 -05:00
function get_service_status ( $device = null )
{
2016-03-15 22:16:08 +10:00
$sql_query = " SELECT service_status, count(service_status) as count FROM services WHERE " ;
$sql_param = array ();
$add = 0 ;
2015-07-10 13:36:21 +02:00
2016-03-15 22:16:08 +10:00
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 service_status " ;
// $service is not null, get only what we want.
$result = dbFetchRows ( $sql_query , $sql_param );
// Set our defaults to 0
$service_count = array ( 0 => 0 , 1 => 0 , 2 => 0 );
// Rebuild the array in a more convenient method
foreach ( $result as $v ) {
$service_count [ $v [ 'service_status' ]] = $v [ 'count' ];
}
return $service_count ;
}
2016-08-28 12:32:58 -05:00
function add_service ( $device , $type , $desc , $ip = 'localhost' , $param = " " , $ignore = 0 )
{
2016-03-15 22:16:08 +10:00
if ( ! is_array ( $device )) {
$device = device_by_id_cache ( $device );
}
if ( empty ( $ip )) {
$ip = $device [ 'hostname' ];
}
2017-01-13 12:47:16 +00:00
$insert = array ( 'device_id' => $device [ 'device_id' ], 'service_ip' => $ip , 'service_type' => $type , 'service_changed' => array ( 'UNIX_TIMESTAMP(NOW())' ), 'service_desc' => $desc , 'service_param' => $param , 'service_ignore' => $ignore , 'service_status' => 3 , 'service_message' => 'Service not yet checked' , 'service_ds' => '{}' );
2016-03-15 22:16:08 +10:00
return dbInsert ( $insert , 'services' );
}
2016-08-28 12:32:58 -05:00
function service_get ( $device = null , $service = null )
{
2016-03-15 22:16:08 +10:00
$sql_query = " SELECT `service_id`,`device_id`,`service_ip`,`service_type`,`service_desc`,`service_param`,`service_ignore`,`service_status`,`service_changed`,`service_message`,`service_disabled`,`service_ds` FROM `services` WHERE " ;
$sql_param = array ();
$add = 0 ;
d_echo ( " SQL Query: " . $sql_query );
if ( ! is_null ( $service )) {
// Add a service filter to the SQL query.
$sql_query .= " `service_id` = ? AND " ;
$sql_param [] = $service ;
$add ++ ;
}
if ( ! is_null ( $device )) {
// Add a device filter to the SQL query.
$sql_query .= " `device_id` = ? AND " ;
$sql_param [] = $device ;
$add ++ ;
}
if ( $add == 0 ) {
// No filters, remove " WHERE" -6
$sql_query = substr ( $sql_query , 0 , strlen ( $sql_query ) - 6 );
2016-08-28 12:32:58 -05:00
} else {
2016-03-15 22:16:08 +10:00
// We have filters, remove " AND" -4
$sql_query = substr ( $sql_query , 0 , strlen ( $sql_query ) - 4 );
}
d_echo ( " SQL Query: " . $sql_query );
// $service is not null, get only what we want.
$services = dbFetchRows ( $sql_query , $sql_param );
2016-08-28 12:32:58 -05:00
d_echo ( " Service Array: " . print_r ( $services , true ) . " \n " );
2016-03-15 22:16:08 +10:00
return $services ;
}
2016-08-28 12:32:58 -05:00
function edit_service ( $update = array (), $service = null )
{
2016-03-15 22:16:08 +10:00
if ( ! is_numeric ( $service )) {
return false ;
}
return dbUpdate ( $update , 'services' , '`service_id`=?' , array ( $service ));
}
2016-08-28 12:32:58 -05:00
function delete_service ( $service = null )
{
2016-03-15 22:16:08 +10:00
if ( ! is_numeric ( $service )) {
return false ;
}
return dbDelete ( 'services' , '`service_id` = ?' , array ( $service ));
}
2016-08-28 12:32:58 -05:00
function discover_service ( $device , $service )
{
2015-07-13 20:10:26 +02:00
if ( ! dbFetchCell ( 'SELECT COUNT(service_id) FROM `services` WHERE `service_type`= ? AND `device_id` = ?' , array ( $service , $device [ 'device_id' ]))) {
2016-03-22 07:35:39 +10:00
add_service ( $device , $service , " (Auto discovered) $service " );
2017-02-13 00:41:05 +02:00
log_event ( 'Autodiscovered service: type ' . mres ( $service ), $device , 'service' , 2 );
2015-07-10 13:36:21 +02:00
echo '+' ;
}
echo " $service " ;
2016-03-15 22:16:08 +10:00
}
2016-08-28 12:32:58 -05:00
function poll_service ( $service )
{
2016-03-22 07:35:39 +10:00
global $config ;
2016-07-07 01:33:43 -05:00
2016-03-15 22:16:08 +10:00
$update = array ();
$old_status = $service [ 'service_status' ];
2016-04-12 07:09:33 +10:00
$check_cmd = " " ;
2016-03-15 22:16:08 +10:00
// if we have a script for this check, use it.
$check_script = $config [ 'install_dir' ] . '/includes/services/check_' . strtolower ( $service [ 'service_type' ]) . '.inc.php' ;
if ( is_file ( $check_script )) {
include $check_script ;
}
// If we do not have a cmd from the check script, build one.
2016-04-12 07:09:33 +10:00
if ( $check_cmd == " " ) {
2016-03-15 22:16:08 +10:00
$check_cmd = $config [ 'nagios_plugins' ] . " /check_ " . $service [ 'service_type' ] . " -H " . ( $service [ 'service_ip' ] ? $service [ 'service_ip' ] : $service [ 'hostname' ]);
$check_cmd .= " " . $service [ 'service_param' ];
}
2016-07-07 01:33:43 -05:00
$service_id = $service [ 'service_id' ];
2016-03-15 22:16:08 +10:00
// Some debugging
2016-07-07 01:33:43 -05:00
d_echo ( " \n Nagios Service - $service_id\n " );
2016-11-04 00:09:40 -07:00
// the check_service function runs $check_cmd through escapeshellcmd, so
// echo the command as it will be run after being escaped
$escaped_check_cmd = escapeshellcmd ( $check_cmd );
d_echo ( " Request: $escaped_check_cmd\n " );
2016-03-29 17:11:21 +10:00
list ( $new_status , $msg , $perf ) = check_service ( $check_cmd );
2016-07-07 01:33:43 -05:00
d_echo ( " Response: $msg\n " );
2016-03-15 22:16:08 +10:00
// If we have performance data we will store it.
if ( count ( $perf ) > 0 ) {
// Yes, We have perf data.
2016-07-07 01:33:43 -05:00
$rrd_name = array ( 'services' , $service_id );
2016-03-15 22:16:08 +10:00
// Set the DS in the DB if it is blank.
$DS = array ();
foreach ( $perf as $k => $v ) {
$DS [ $k ] = $v [ 'uom' ];
}
d_echo ( " Service DS: " . _json_encode ( $DS ) . " \n " );
2017-01-25 18:41:48 +01:00
if (( $service [ 'service_ds' ] == " { } " ) || ( $service [ 'service_ds' ] == " " )) {
2016-03-15 22:16:08 +10:00
$update [ 'service_ds' ] = json_encode ( $DS );
}
2016-07-07 01:33:43 -05:00
// rrd definition
2017-02-23 22:45:50 +00:00
$rrd_def = new RrdDefinition ();
2016-07-07 01:33:43 -05:00
foreach ( $perf as $k => $v ) {
2016-11-16 01:24:56 -06:00
if (( $v [ 'uom' ] == 'c' ) && ! ( preg_match ( '/[Uu]ptime/' , $k ))) {
2016-07-07 01:33:43 -05:00
// This is a counter, create the DS as such
2017-02-23 22:45:50 +00:00
$rrd_def -> addDataset ( $k , 'COUNTER' , 0 );
2016-08-28 12:32:58 -05:00
} else {
2016-07-07 01:33:43 -05:00
// Not a counter, must be a gauge
2017-02-23 22:45:50 +00:00
$rrd_def -> addDataset ( $k , 'GAUGE' , 0 );
2016-03-15 22:16:08 +10:00
}
}
2016-07-07 01:33:43 -05:00
// Update data
$fields = array ();
2016-03-15 22:16:08 +10:00
foreach ( $perf as $k => $v ) {
2016-07-07 01:33:43 -05:00
$fields [ $k ] = $v [ 'value' ];
2016-03-15 22:16:08 +10:00
}
2016-07-07 01:33:43 -05:00
$tags = compact ( 'service_id' , 'rrd_name' , 'rrd_def' );
//TODO not sure if we have $device at this point, if we do replace faked $device
data_update ( array ( 'hostname' => $service [ 'hostname' ]), 'services' , $tags , $fields );
2016-03-15 22:16:08 +10:00
}
if ( $old_status != $new_status ) {
// Status has changed, update.
$update [ 'service_changed' ] = time ();
$update [ 'service_status' ] = $new_status ;
$update [ 'service_message' ] = $msg ;
}
2016-04-26 06:46:22 +10:00
if ( $service [ 'service_message' ] != $msg ) {
// Message has changed, update.
$update [ 'service_message' ] = $msg ;
}
2016-03-15 22:16:08 +10:00
if ( count ( $update ) > 0 ) {
2016-08-28 12:32:58 -05:00
edit_service ( $update , $service [ 'service_id' ]);
2016-03-15 22:16:08 +10:00
}
return true ;
}
2016-08-28 12:32:58 -05:00
function check_service ( $command )
{
2016-03-15 22:16:08 +10:00
// This array is used to test for valid UOM's to be used for graphing.
// Valid values from: https://nagios-plugins.org/doc/guidelines.html#AEN200
// Note: This array must be decend from 2 char to 1 char so that the search works correctly.
$valid_uom = array ( 'us' , 'ms' , 'KB' , 'MB' , 'GB' , 'TB' , 'c' , 's' , '%' , 'B' );
// Make our command safe.
2016-12-21 08:40:02 +10:00
$command = 'LC_NUMERIC="C" ' . escapeshellcmd ( $command );
2016-03-15 22:16:08 +10:00
// Run the command and return its response.
exec ( $command , $response_array , $status );
// exec returns an array, lets implode it back to a string.
$response_string = implode ( " \n " , $response_array );
// Split out the response and the performance data.
list ( $response , $perf ) = explode ( " | " , $response_string );
// Split each performance metric
$perf_arr = explode ( ' ' , $perf );
// Create an array for our metrics.
$metrics = array ();
// Loop through the perf string extracting our metric data
foreach ( $perf_arr as $string ) {
// Separate the DS and value: DS=value
list ( $ds , $values ) = explode ( '=' , trim ( $string ));
// Keep the first value, discard the others.
list ( $value ,,,) = explode ( ';' , trim ( $values ));
$value = trim ( $value );
// Set an empty uom
$uom = '' ;
// is the UOM valid - https://nagios-plugins.org/doc/guidelines.html#AEN200
foreach ( $valid_uom as $v ) {
2016-08-28 12:32:58 -05:00
if (( strlen ( $value ) - strlen ( $v )) === strpos ( $value , $v )) {
2016-03-15 22:16:08 +10:00
// Yes, store and strip it off the value
$uom = $v ;
$value = substr ( $value , 0 , - strlen ( $v ));
break ;
}
}
if ( $ds != " " ) {
2016-11-16 01:24:56 -06:00
// Normalize ds for rrd : ds-name must be 1 to 19 characters long in the characters [a-zA-Z0-9_]
// http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html
$normalized_ds = preg_replace ( '/[^a-zA-Z0-9_]/' , '' , $ds );
// if ds_name is longer than 19 characters, only use the first 19
if ( strlen ( $normalized_ds ) > 19 ) {
$normalized_ds = substr ( $normalized_ds , 0 , 19 );
d_echo ( $ds . " exceeded 19 characters, renaming to " . $normalized_ds . " \n " );
}
if ( $ds != $normalized_ds ) {
// ds has changed. check if normalized_ds is already in the array
if ( isset ( $metrics [ $normalized_ds ])) {
d_echo ( $normalized_ds . " collides with an existing index \n " );
$perf_unique = 0 ;
// Try to generate a unique name
for ( $i = 0 ; $i < 10 ; $i ++ ) {
$tmp_ds_name = substr ( $normalized_ds , 0 , 18 ) . $i ;
if ( ! isset ( $metrics [ $tmp_ds_name ])) {
d_echo ( $normalized_ds . " collides with an existing index \n " );
$normalized_ds = $tmp_ds_name ;
$perf_unique = 1 ;
break 1 ;
}
}
if ( $perf_unique == 0 ) {
// Try harder to generate a unique name
for ( $i = 0 ; $i < 10 ; $i ++ ) {
for ( $j = 0 ; $j < 10 ; $j ++ ) {
$tmp_ds_name = substr ( $normalized_ds , 0 , 17 ) . $j . $i ;
if ( ! isset ( $perf [ $tmp_ds_name ])) {
$normalized_ds = $tmp_ds_name ;
$perf_unique = 1 ;
break 2 ;
}
}
}
}
if ( $perf_unique == 0 ) {
d_echo ( " could not generate a unique ds-name for " . $ds . " \n " );
}
}
$ds = $normalized_ds ;
}
2016-03-15 22:16:08 +10:00
// We have a DS. Add an entry to the array.
d_echo ( " Perf Data - DS: " . $ds . " , Value: " . $value . " , UOM: " . $uom . " \n " );
$metrics [ $ds ] = array ( 'value' => $value , 'uom' => $uom );
2016-08-28 12:32:58 -05:00
} else {
2016-03-15 22:16:08 +10:00
// No DS. Don't add an entry to the array.
d_echo ( " Perf Data - None. \n " );
}
}
2015-07-10 13:36:21 +02:00
2016-03-15 22:16:08 +10:00
return array ( $status , $response , $metrics );
2015-07-10 13:36:21 +02:00
}