#!/usr/bin/env php 0) { $purges = purge_spike_backups(); } $end = microtime(true); $cacti_stats = sprintf( 'Time:%01.4f ' . 'Graphs:%s ' . 'Purges:%s ' . 'Kills:%s', round($end - $start,2), $graphs, $purges, $kills); // log to the database db_execute_prepared('REPLACE INTO settings (name,value) VALUES ("stats_spikekill", ?)', [$cacti_stats]); // log to the logfile cacti_log('SPIKEKILL STATS: ' . $cacti_stats , true, 'SYSTEM'); } print 'NOTE: SpikeKill Finished' . PHP_EOL; unregister_process('spikekill', 'master', 0); exit(0); function timeToRun() : bool { global $forcerun; $lastrun = read_config_option('spikekill_lastrun'); $frequency = read_config_option('spikekill_batch') * 3600; $basetime = strtotime(read_config_option('spikekill_basetime')); $baseupper = $basetime + 300; $baselower = $basetime - 300; $now = time(); debug("LastRun:'$lastrun', Frequency:'$frequency', BaseTime:'" . date('Y-m-d H:i:s', $basetime) . "', BaseUpper:'$baseupper', BaseLower:'$baselower', Now:'" . date('Y-m-d H:i:s', $now) . "'"); if ($frequency > 0 && ($now - $lastrun > $frequency)) { debug("Frequency is '$frequency' Seconds"); if (empty($lastrun) && ($now < $baseupper) && ($now > $baselower)) { debug('Time to Run'); db_execute_prepared('REPLACE INTO settings (name,value) VALUES ("spikekill_lastrun", ?)', [time()]); return true; } if (($now - $lastrun > $frequency) && ($now < $baseupper) && ($now > $baselower)) { debug('Time to Run'); db_execute_prepared('REPLACE INTO settings (name,value) VALUES ("spikekill_lastrun", ?)', [time()]); return true; } else { debug('Not Time to Run'); return false; } } elseif ($forcerun) { debug('Force to Run'); db_execute_prepared('REPLACE INTO settings (name,value) VALUES ("spikekill_lastrun", ?)', [time()]); return true; } else { debug('Not time to Run'); return false; } } function debug(string $message) : void { global $debug; if ($debug) { print 'DEBUG: ' . trim($message) . PHP_EOL; } } function purge_spike_backups() : mixed { $directory = read_config_option('spikekill_backupdir'); $retention = intval(read_config_option('spikekill_purge')); $purges = 0; if (empty($retention)) { return false; } $earlytime = time() - $retention; if ($directory != '' && is_dir($directory) && is_writable($directory)) { $files = array_diff(scandir($directory), ['.', '..']); if (cacti_sizeof($files)) { foreach ($files as $file) { $filepath = $directory . '/' . $file; if (is_file($filepath) && str_contains($filepath, 'rrd')) { $mtime = filemtime($filepath); if ($mtime < $earlytime) { if (is_writable($filepath)) { unlink($filepath); $purges++; } else { cacti_log('Unable to remove ' . $filepath . ' due to write permissions', false, 'SPIKES'); } } } } } } return $purges; } function kill_spikes(array $templates, int &$found) : int { global $debug; $rrdfiles = array_rekey(db_fetch_assoc('SELECT DISTINCT rrd_path FROM graph_templates AS gt INNER JOIN graph_templates_item AS gti ON gt.id=gti.graph_template_id INNER JOIN data_template_rrd AS dtr ON gti.task_item_id=dtr.id INNER JOIN poller_item AS pi ON pi.local_data_id=dtr.local_data_id WHERE gt.id IN (' . implode(',', $templates) . ')'), 'rrd_path', 'rrd_path'); if (cacti_sizeof($rrdfiles)) { foreach ($rrdfiles as $f) { debug("Removing Spikes from '$f'"); $response = exec(cacti_escapeshellcmd((string) read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg(CACTI_PATH_CLI . '/removespikes.php') . ' --rrdfile=' . cacti_escapeshellarg($f) . ($debug ? ' --debug' : '')); if (substr_count((string) $response, 'Spikes Found and Remediated')) { $found++; } debug(str_replace('NOTE: ', '', $response)); } } return cacti_sizeof($rrdfiles); } // display_version - displays version information function display_version() : void { $version = get_cacti_cli_version(); print "Cacti SpikeKiller Batch Poller, Version $version, " . COPYRIGHT_YEARS . PHP_EOL; } function display_help() : void { display_version(); print PHP_EOL . 'usage: poller_spikekill.php [--templates=N,N,...] [--force] [--debug]' . PHP_EOL . PHP_EOL; print "Cacti's SpikeKill batch removal poller. This poller will remove spikes" . PHP_EOL; print "in Cacti's RRDfiles based upon the settings maintained in Cacti's database." . PHP_EOL . PHP_EOL; print 'Optional:' . PHP_EOL; print ' --templates=N,N,... - Only despike the templates provided.' . PHP_EOL; print ' --force - Force running the despiking immediately.' . PHP_EOL; print ' --debug - Display verbose output during execution.' . PHP_EOL; }