2016-09-14 15:53:04 +00:00
#!/usr/bin/env php
2013-11-04 06:16:01 +00:00
< ? php
/*
* Daily Task Checks
* ( c ) 2013 LibreNMS Contributors
*/
2018-07-30 21:58:38 +00:00
use App\Models\Device ;
2019-06-19 21:01:53 +00:00
use App\Models\DeviceGroup ;
2018-07-30 21:58:38 +00:00
use Illuminate\Database\Eloquent\Collection ;
2019-07-18 16:05:43 +00:00
use LibreNMS\Alert\AlertDB ;
2017-10-22 18:30:31 +00:00
use LibreNMS\Config ;
2021-04-30 03:42:18 +00:00
use LibreNMS\Util\Debug ;
2020-04-24 09:04:36 +00:00
use LibreNMS\Validations\Php ;
2017-10-22 18:30:31 +00:00
2017-11-24 09:37:52 +00:00
$options = getopt ( 'df:o:t:r:' );
2016-01-11 21:58:40 +00:00
2022-02-02 16:33:23 +00:00
/**
* Scripts without dependencies
*/
if ( $options [ 'f' ] === 'composer_get_plugins' ) {
$output = [];
$plugins = is_file ( 'composer.plugins.json' ) ?
json_decode ( file_get_contents ( 'composer.plugins.json' )) : [];
foreach ( $plugins -> require ? ? [] as $package => $version ) {
$output [] = " $package : $version " ;
}
echo implode ( ' ' , $output );
return ;
}
/**
* Scripts with dependencies
*/
$init_modules = [ 'alerts' ];
require __DIR__ . '/includes/init.php' ;
include_once __DIR__ . '/includes/notifications.php' ;
2022-07-29 13:53:41 +00:00
if ( isset ( $options [ 'd' ])) {
echo " DEBUG \n " ;
Debug :: set ();
}
2014-10-24 22:40:42 +00:00
if ( $options [ 'f' ] === 'update' ) {
2019-06-26 13:49:04 +00:00
if ( ! Config :: get ( 'update' )) {
2016-02-22 22:10:56 +00:00
exit ( 0 );
}
2019-06-26 13:49:04 +00:00
if ( Config :: get ( 'update_channel' ) == 'master' ) {
2016-02-22 22:10:56 +00:00
exit ( 1 );
2019-06-26 13:49:04 +00:00
} elseif ( Config :: get ( 'update_channel' ) == 'release' ) {
2016-02-22 22:10:56 +00:00
exit ( 3 );
2015-07-29 22:03:25 +00:00
}
2016-02-22 22:10:56 +00:00
exit ( 0 );
2014-10-24 22:40:42 +00:00
}
2013-11-04 06:16:01 +00:00
2016-07-30 15:57:09 +00:00
if ( $options [ 'f' ] === 'rrd_purge' ) {
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'rrd_purge' , 86000 );
if ( $lock -> get ()) {
2017-11-24 09:37:52 +00:00
$rrd_purge = Config :: get ( 'rrd_purge' );
$rrd_dir = Config :: get ( 'rrd_dir' );
if ( is_numeric ( $rrd_purge ) && $rrd_purge > 0 ) {
$cmd = " find $rrd_dir -type f -mtime + $rrd_purge -print -exec rm -f { } + " ;
$purge = `$cmd` ;
if ( ! empty ( $purge )) {
echo " Purged the following RRD files due to old age (over $rrd_purge days old): \n " ;
echo $purge ;
}
}
2020-10-07 12:36:35 +00:00
$lock -> release ();
2016-07-30 15:57:09 +00:00
}
}
2014-10-24 22:40:42 +00:00
if ( $options [ 'f' ] === 'syslog' ) {
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'syslog_purge' , 86000 );
if ( $lock -> get ()) {
2017-11-24 09:37:52 +00:00
$syslog_purge = Config :: get ( 'syslog_purge' );
if ( is_numeric ( $syslog_purge )) {
$rows = ( int ) dbFetchCell ( 'SELECT MIN(seq) FROM syslog' );
2019-11-19 22:57:56 +00:00
$initial_rows = $rows ;
2017-11-24 09:37:52 +00:00
while ( true ) {
2019-11-19 19:25:11 +00:00
$limit = dbFetchCell ( 'SELECT seq FROM syslog WHERE seq >= ? ORDER BY seq LIMIT 1000,1' , [ $rows ]);
2017-11-24 09:37:52 +00:00
if ( empty ( $limit )) {
break ;
}
2015-07-13 18:10:26 +00:00
2019-11-19 22:57:56 +00:00
// Deletes are done in blocks of 1000 to avoid a single very large operation.
2017-11-24 09:37:52 +00:00
if ( dbDelete ( 'syslog' , 'seq >= ? AND seq < ? AND timestamp < DATE_SUB(NOW(), INTERVAL ? DAY)' , [ $rows , $limit , $syslog_purge ]) > 0 ) {
$rows = $limit ;
} else {
break ;
}
2015-07-13 18:10:26 +00:00
}
2017-11-24 09:37:52 +00:00
dbDelete ( 'syslog' , 'seq >= ? AND timestamp < DATE_SUB(NOW(), INTERVAL ? DAY)' , [ $rows , $syslog_purge ]);
2019-11-19 22:57:56 +00:00
$final_rows = $rows - $initial_rows ;
echo " Syslog cleared for entries over $syslog_purge days (about $final_rows rows) \n " ;
2017-11-24 09:37:52 +00:00
}
2020-10-07 12:36:35 +00:00
$lock -> release ();
2014-03-18 14:13:27 +00:00
}
}
2015-07-13 18:10:26 +00:00
2019-02-21 12:23:01 +00:00
if ( $options [ 'f' ] === 'ports_fdb' ) {
$ret = lock_and_purge ( 'ports_fdb' , 'updated_at < DATE_SUB(NOW(), INTERVAL ? DAY)' );
exit ( $ret );
}
2019-11-17 15:30:43 +00:00
if ( $options [ 'f' ] === 'route' ) {
$ret = lock_and_purge ( 'route' , 'updated_at < DATE_SUB(NOW(), INTERVAL ? DAY)' );
exit ( $ret );
}
2014-10-24 22:40:42 +00:00
if ( $options [ 'f' ] === 'eventlog' ) {
2017-11-24 09:37:52 +00:00
$ret = lock_and_purge ( 'eventlog' , 'datetime < DATE_SUB(NOW(), INTERVAL ? DAY)' );
exit ( $ret );
2014-03-18 14:13:27 +00:00
}
2015-07-13 18:10:26 +00:00
2014-10-24 22:40:42 +00:00
if ( $options [ 'f' ] === 'authlog' ) {
2017-11-24 09:37:52 +00:00
$ret = lock_and_purge ( 'authlog' , 'datetime < DATE_SUB(NOW(), INTERVAL ? DAY)' );
exit ( $ret );
2014-10-02 00:37:43 +00:00
}
2015-07-13 18:10:26 +00:00
2015-04-06 19:47:28 +00:00
if ( $options [ 'f' ] === 'callback' ) {
2022-07-29 13:53:41 +00:00
\LibreNMS\Util\Stats :: submit ();
2015-04-06 19:47:28 +00:00
}
2015-07-13 18:10:26 +00:00
2015-06-22 20:55:31 +00:00
if ( $options [ 'f' ] === 'device_perf' ) {
2017-11-24 09:37:52 +00:00
$ret = lock_and_purge ( 'device_perf' , 'timestamp < DATE_SUB(NOW(),INTERVAL ? DAY)' );
exit ( $ret );
2015-06-22 20:55:31 +00:00
}
2015-09-27 15:35:33 +00:00
2018-07-03 13:27:20 +00:00
if ( $options [ 'f' ] === 'ports_purge' ) {
2020-10-07 12:36:35 +00:00
if ( Config :: get ( 'ports_purge' )) {
$lock = Cache :: lock ( 'syslog_purge' , 86000 );
if ( $lock -> get ()) {
2020-04-16 14:19:58 +00:00
\App\Models\Port :: query () -> with ([ 'device' => function ( $query ) {
$query -> select ( 'device_id' , 'hostname' );
}]) -> isDeleted () -> chunk ( 100 , function ( $ports ) {
foreach ( $ports as $port ) {
$port -> delete ();
}
});
2018-07-03 13:27:20 +00:00
echo " All deleted ports now purged \n " ;
2020-10-07 12:36:35 +00:00
$lock -> release ();
2018-07-03 13:27:20 +00:00
}
}
}
2017-10-22 18:30:31 +00:00
if ( $options [ 'f' ] === 'handle_notifiable' ) {
2017-08-26 20:35:39 +00:00
if ( $options [ 't' ] === 'update' ) {
$title = 'Error: Daily update failed' ;
2017-11-24 09:37:52 +00:00
$poller_name = Config :: get ( 'distributed_poller_name' );
2017-08-26 20:35:39 +00:00
if ( $options [ 'r' ]) {
2017-10-22 18:30:31 +00:00
// result was a success (1), remove the notification
2017-08-26 20:35:39 +00:00
remove_notification ( $title );
} else {
2017-10-22 18:30:31 +00:00
// result was a failure (0), create the notification
2017-08-26 20:35:39 +00:00
new_notification (
$title ,
2017-11-24 09:37:52 +00:00
" The daily update script (daily.sh) has failed on $poller_name . "
. 'Please check output by hand. If you need assistance, '
2017-08-26 20:35:39 +00:00
. 'visit the <a href="https://www.librenms.org/#support">LibreNMS Website</a> to find out how.' ,
2 ,
'daily.sh'
);
}
2018-01-10 14:40:58 +00:00
} elseif ( $options [ 't' ] === 'phpver' ) {
$error_title = 'Error: PHP version too low' ;
// if update is not set to false and version is min or newer
if ( Config :: get ( 'update' ) && $options [ 'r' ]) {
2019-02-07 19:23:30 +00:00
if ( $options [ 'r' ] === 'php53' ) {
$phpver = '5.6.4' ;
$eol_date = 'January 10th, 2018' ;
2020-11-03 01:56:49 +00:00
} elseif ( $options [ 'r' ] === 'php56' || $options [ 'r' ] === 'php71' || $options [ 'r' ] === 'php72' ) {
2020-04-24 09:04:36 +00:00
$phpver = Php :: PHP_MIN_VERSION ;
$eol_date = Php :: PHP_MIN_VERSION_DATE ;
2019-02-07 19:23:30 +00:00
}
2019-02-08 14:17:02 +00:00
if ( isset ( $phpver )) {
new_notification (
$error_title ,
2020-04-24 09:04:36 +00:00
" PHP version $phpver is the minimum supported version as of $eol_date . We recommend you update to PHP a supported version of PHP ( " . Php :: PHP_RECOMMENDED_VERSION . ' suggested) to continue to receive updates. If you do not update PHP, LibreNMS will continue to function but stop receiving bug fixes and updates.' ,
2019-02-08 14:17:02 +00:00
2 ,
'daily.sh'
);
exit ( 1 );
}
2018-01-10 14:40:58 +00:00
}
2020-05-02 06:37:22 +00:00
remove_notification ( $error_title );
exit ( 0 );
} elseif ( $options [ 't' ] === 'pythonver' ) {
$error_title = 'Error: Python requirements not met' ;
// if update is not set to false and version is min or newer
if ( Config :: get ( 'update' ) && $options [ 'r' ]) {
if ( $options [ 'r' ] === 'python3-missing' ) {
new_notification (
$error_title ,
'Python 3 is required to run LibreNMS as of May, 2020. You need to install Python 3 to continue to receive updates. If you do not install Python 3 and required packages, LibreNMS will continue to function but stop receiving bug fixes and updates.' ,
2 ,
'daily.sh'
);
exit ( 1 );
} elseif ( $options [ 'r' ] === 'python3-deps' ) {
new_notification (
$error_title ,
'Python 3 dependencies are missing. You need to install them via pip3 install -r requirements.txt or system packages to continue to receive updates. If you do not install Python 3 and required packages, LibreNMS will continue to function but stop receiving bug fixes and updates.' ,
2 ,
'daily.sh'
);
exit ( 1 );
}
}
2018-01-10 14:40:58 +00:00
remove_notification ( $error_title );
exit ( 0 );
2017-08-26 20:35:39 +00:00
}
}
2015-09-27 15:35:33 +00:00
if ( $options [ 'f' ] === 'notifications' ) {
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'notifications' , 86000 );
if ( $lock -> get ()) {
2017-11-24 09:37:52 +00:00
post_notifications ();
2020-10-07 12:36:35 +00:00
$lock -> release ();
2017-11-24 09:37:52 +00:00
}
2015-09-27 15:35:33 +00:00
}
2015-12-13 16:16:39 +00:00
2016-03-02 18:39:16 +00:00
if ( $options [ 'f' ] === 'bill_data' ) {
2019-11-05 13:49:09 +00:00
// Deletes data older than XX months before the start of the last complete billing period
$msg = " Deleting billing data more than %d month before the last completed billing cycle \n " ;
$table = 'bill_data' ;
$sql = ' DELETE bill_data
FROM bill_data
2020-05-02 06:37:22 +00:00
INNER JOIN ( SELECT bill_id ,
2019-11-05 13:49:09 +00:00
SUBDATE (
SUBDATE (
ADDDATE (
subdate ( curdate (), ( day ( curdate ()) - 1 )), # Start of this month
bill_day - 1 ), # Billing anniversary
INTERVAL IF ( bill_day > DAY ( curdate ()), 1 , 0 ) MONTH ), # Deal with anniversary not yet happened this month
INTERVAL ? MONTH ) AS threshold # Adjust based on config threshold
FROM bills ) q
ON bill_data . bill_id = q . bill_id AND bill_data . timestamp < q . threshold ; ' ;
lock_and_purge_query ( $table , $sql , $msg );
2016-03-02 18:39:16 +00:00
}
2016-05-02 19:06:51 +00:00
if ( $options [ 'f' ] === 'alert_log' ) {
2019-11-05 13:49:09 +00:00
$msg = " Deleting alert_logs more than %d days that are not active \n " ;
$table = 'alert_log' ;
$sql = ' DELETE alert_log
FROM alert_log
INNER JOIN alerts
ON alerts . device_id = alert_log . device_id AND alerts . rule_id = alert_log . rule_id
WHERE alerts . state = 0 AND alert_log . time_logged < DATE_SUB ( NOW (), INTERVAL ? DAY )
' ;
lock_and_purge_query ( $table , $sql , $msg );
2020-05-02 06:37:22 +00:00
2019-11-05 13:49:09 +00:00
// alert_log older than $config['alert_log_purge'] days match now only the alert_log of active alerts
// in case of flapping of an alert, many entries are kept in alert_log
// we want only to keep the last alert_log that contains the alert details
$msg = " Deleting history of active alert_logs more than %d days \n " ;
$sql = ' DELETE
FROM alert_log
WHERE id IN (
SELECT id FROM (
SELECT id
FROM alert_log a1
WHERE
time_logged < DATE_SUB ( NOW (), INTERVAL ? DAY )
AND ( device_id , rule_id , time_logged ) NOT IN (
SELECT device_id , rule_id , max ( time_logged )
FROM alert_log a2 WHERE a1 . device_id = a2 . device_id AND a1 . rule_id = a2 . rule_id
AND a2 . time_logged < DATE_SUB ( NOW (), INTERVAL ? DAY )
)
) as c
)
' ;
$purge_duration = Config :: get ( 'alert_log_purge' );
if ( ! ( is_numeric ( $purge_duration ) && $purge_duration > 0 )) {
return - 2 ;
}
2022-08-14 14:12:46 +00:00
$sql = preg_replace ( '/\?/' , strval ( $purge_duration ), $sql , 1 );
2019-11-05 13:49:09 +00:00
lock_and_purge_query ( $table , $sql , $msg );
2016-05-02 19:06:51 +00:00
}
2015-12-13 16:16:39 +00:00
if ( $options [ 'f' ] === 'purgeusers' ) {
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'purgeusers' , 86000 );
if ( $lock -> get ()) {
2017-11-24 09:37:52 +00:00
$purge = 0 ;
2019-06-26 13:49:04 +00:00
if ( is_numeric ( \LibreNMS\Config :: get ( 'radius.users_purge' )) && Config :: get ( 'auth_mechanism' ) === 'radius' ) {
2019-06-23 05:29:12 +00:00
$purge = \LibreNMS\Config :: get ( 'radius.users_purge' );
2015-12-13 16:16:39 +00:00
}
2019-06-26 13:49:04 +00:00
if ( is_numeric ( \LibreNMS\Config :: get ( 'active_directory.users_purge' )) && Config :: get ( 'auth_mechanism' ) === 'active_directory' ) {
2019-06-23 05:29:12 +00:00
$purge = \LibreNMS\Config :: get ( 'active_directory.users_purge' );
2015-12-13 16:16:39 +00:00
}
2017-11-24 09:37:52 +00:00
if ( $purge > 0 ) {
2020-09-30 23:16:28 +00:00
$users = \App\Models\AuthLog :: where ( 'datetime' , '>=' , \Carbon\Carbon :: now () -> subDays ( $purge ))
-> distinct () -> pluck ( 'user' )
2021-10-06 12:29:47 +00:00
-> merge ( \App\Models\User :: has ( 'apiTokens' ) -> pluck ( 'username' )) // don't purge users with api tokens
2020-09-30 23:16:28 +00:00
-> unique ();
2018-08-26 12:42:21 +00:00
2020-09-30 23:16:28 +00:00
if ( \App\Models\User :: thisAuth () -> whereNotIn ( 'username' , $users ) -> delete ()) {
echo " Removed users that haven't logged in for $purge days \n " ;
2017-11-24 09:37:52 +00:00
}
}
2020-10-07 12:36:35 +00:00
$lock -> release ();
2015-12-13 16:16:39 +00:00
}
}
2016-10-14 23:29:55 +00:00
if ( $options [ 'f' ] === 'refresh_alert_rules' ) {
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'refresh_alert_rules' , 86000 );
if ( $lock -> get ()) {
2017-11-24 09:37:52 +00:00
echo 'Refreshing alert rules queries' . PHP_EOL ;
2018-10-15 21:03:56 +00:00
$rules = dbFetchRows ( 'SELECT `id`, `rule`, `builder`, `extra` FROM `alert_rules`' );
2017-11-24 09:37:52 +00:00
foreach ( $rules as $rule ) {
2018-10-15 21:03:56 +00:00
$rule_options = json_decode ( $rule [ 'extra' ], true );
2018-10-16 07:00:50 +00:00
if ( $rule_options [ 'options' ][ 'override_query' ] !== 'on' ) {
2019-07-18 16:05:43 +00:00
$data [ 'query' ] = AlertDB :: genSQL ( $rule [ 'rule' ], $rule [ 'builder' ]);
2018-10-15 21:03:56 +00:00
if ( ! empty ( $data [ 'query' ])) {
dbUpdate ( $data , 'alert_rules' , 'id=?' , [ $rule [ 'id' ]]);
unset ( $data );
}
2017-11-24 09:37:52 +00:00
}
}
2020-10-07 12:36:35 +00:00
$lock -> release ();
2016-10-14 23:29:55 +00:00
}
}
2016-12-12 14:26:17 +00:00
2019-06-19 21:01:53 +00:00
if ( $options [ 'f' ] === 'refresh_device_groups' ) {
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'refresh_device_groups' , 86000 );
if ( $lock -> get ()) {
2019-06-19 21:01:53 +00:00
echo 'Refreshing device group table relationships' . PHP_EOL ;
DeviceGroup :: all () -> each ( function ( $deviceGroup ) {
if ( $deviceGroup -> type == 'dynamic' ) {
/** @var DeviceGroup $deviceGroup */
$deviceGroup -> rules = $deviceGroup -> getParser () -> generateJoins () -> toArray ();
$deviceGroup -> save ();
}
});
2020-10-07 12:36:35 +00:00
$lock -> release ();
2019-06-19 21:01:53 +00:00
}
}
2016-12-12 14:26:17 +00:00
if ( $options [ 'f' ] === 'notify' ) {
2019-06-23 05:29:12 +00:00
if ( \LibreNMS\Config :: has ( 'alert.default_mail' )) {
2016-12-12 14:26:17 +00:00
send_mail (
2019-06-23 05:29:12 +00:00
\LibreNMS\Config :: get ( 'alert.default_mail' ),
2018-02-16 10:08:26 +00:00
'[LibreNMS] Auto update has failed for ' . Config :: get ( 'distributed_poller_name' ),
2016-12-12 14:26:17 +00:00
" We just attempted to update your install but failed. The information below should help you fix this. \r \n \r \n " . $options [ 'o' ]
);
}
}
2017-03-22 10:17:13 +00:00
if ( $options [ 'f' ] === 'peeringdb' ) {
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'peeringdb' , 86000 );
if ( $lock -> get ()) {
2017-11-24 09:37:52 +00:00
cache_peeringdb ();
2020-10-07 12:36:35 +00:00
$lock -> release ();
2017-11-24 09:37:52 +00:00
}
2017-03-22 10:17:13 +00:00
}
2017-10-27 20:03:58 +00:00
2021-05-10 19:56:48 +00:00
if ( $options [ 'f' ] === 'mac_oui' ) {
$lock = Cache :: lock ( 'macouidb' , 86000 );
if ( $lock -> get ()) {
$res = cache_mac_oui ();
$lock -> release ();
exit ( $res );
}
}
2017-10-27 20:03:58 +00:00
if ( $options [ 'f' ] === 'refresh_os_cache' ) {
2017-11-03 21:10:24 +00:00
echo 'Clearing OS cache' . PHP_EOL ;
2022-08-25 08:03:06 +00:00
if ( is_file ( Config :: get ( 'install_dir' ) . '/cache/os_defs.cache' )) {
unlink ( Config :: get ( 'install_dir' ) . '/cache/os_defs.cache' );
}
2017-10-27 20:03:58 +00:00
}
2018-07-30 21:58:38 +00:00
if ( $options [ 'f' ] === 'recalculate_device_dependencies' ) {
// fix broken dependency max_depth calculation in case things weren't done though eloquent
2020-10-07 12:36:35 +00:00
$lock = Cache :: lock ( 'recalculate_device_dependencies' , 86000 );
if ( $lock -> get ()) {
2018-07-30 21:58:38 +00:00
// update all root nodes and recurse, chunk so we don't blow up
Device :: doesntHave ( 'parents' ) -> with ( 'children' ) -> chunk ( 100 , function ( Collection $devices ) {
// anonymous recursive function
$recurse = function ( Device $device ) use ( & $recurse ) {
$device -> updateMaxDepth ();
$device -> children -> each ( $recurse );
};
$devices -> each ( $recurse );
});
2020-10-07 12:36:35 +00:00
$lock -> release ();
2018-07-30 21:58:38 +00:00
}
}