From 5de2af21516f28817ff0a7d6274142e26e3e1253 Mon Sep 17 00:00:00 2001 From: mcramer Date: Thu, 22 Aug 2013 12:42:24 +0000 Subject: [PATCH] - Implemented: New cron class and split up cron_daily - Implemented: FS#3110 - Turn monitoring module into cron jobs --- install/sql/ispconfig3.sql | 16 + server/cron.php | 90 + server/cron.sh | 12 + server/cron_daily.php | 1346 -------------- server/cron_daily.sh | 15 +- .../classes/cron.d/100-mailbox_stats.inc.php | 269 +++ .../cron.d/100-monitor_clamav_log.inc.php | 179 ++ .../classes/cron.d/100-monitor_cpu.inc.php | 136 ++ .../cron.d/100-monitor_disk_usage.inc.php | 166 ++ .../cron.d/100-monitor_email_quota.inc.php | 149 ++ .../cron.d/100-monitor_fail2ban.inc.php | 127 ++ .../cron.d/100-monitor_hd_quota.inc.php | 162 ++ .../cron.d/100-monitor_iptables.inc.php | 132 ++ .../cron.d/100-monitor_ispconfig_log.inc.php | 146 ++ .../100-monitor_ispconfig_version.inc.php | 110 ++ .../cron.d/100-monitor_mail_log.inc.php | 181 ++ .../cron.d/100-monitor_mail_queue.inc.php | 138 ++ .../cron.d/100-monitor_mem_usage.inc.php | 124 ++ .../cron.d/100-monitor_mongodb.inc.php | 127 ++ .../classes/cron.d/100-monitor_openvz.inc.php | 183 ++ .../cron.d/100-monitor_os_version.inc.php | 112 ++ .../classes/cron.d/100-monitor_raid.inc.php | 263 +++ .../cron.d/100-monitor_rkhunter.inc.php | 127 ++ .../classes/cron.d/100-monitor_server.inc.php | 133 ++ .../cron.d/100-monitor_services.inc.php | 94 + .../classes/cron.d/100-monitor_syslog.inc.php | 153 ++ .../cron.d/100-monitor_system_update.inc.php | 208 +++ server/lib/classes/cron.d/150-awstats.inc.php | 183 ++ .../lib/classes/cron.d/150-webalizer.inc.php | 142 ++ .../lib/classes/cron.d/200-logfiles.inc.php | 271 +++ .../classes/cron.d/300-quota_notify.inc.php | 479 +++++ server/lib/classes/cron.d/400-openvz.inc.php | 83 + server/lib/classes/cron.d/500-backup.inc.php | 330 ++++ server/lib/classes/cron.inc.php | 271 +++ server/lib/classes/cronjob.inc.php | 158 ++ server/lib/classes/functions.inc.php | 398 +++++ server/lib/classes/libdatetime.inc.php | 479 +++++ server/lib/classes/monitor_tools.inc.php | 1566 ++--------------- .../monitor_core_module.inc.php | 870 --------- 39 files changed, 6453 insertions(+), 3675 deletions(-) create mode 100644 server/cron.php create mode 100644 server/cron.sh delete mode 100644 server/cron_daily.php mode change 100644 => 100755 server/cron_daily.sh create mode 100644 server/lib/classes/cron.d/100-mailbox_stats.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_clamav_log.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_cpu.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_disk_usage.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_email_quota.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_fail2ban.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_hd_quota.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_iptables.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_ispconfig_log.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_ispconfig_version.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_mail_log.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_mail_queue.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_mem_usage.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_mongodb.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_openvz.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_os_version.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_raid.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_rkhunter.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_server.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_services.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_syslog.inc.php create mode 100644 server/lib/classes/cron.d/100-monitor_system_update.inc.php create mode 100644 server/lib/classes/cron.d/150-awstats.inc.php create mode 100644 server/lib/classes/cron.d/150-webalizer.inc.php create mode 100644 server/lib/classes/cron.d/200-logfiles.inc.php create mode 100644 server/lib/classes/cron.d/300-quota_notify.inc.php create mode 100644 server/lib/classes/cron.d/400-openvz.inc.php create mode 100644 server/lib/classes/cron.d/500-backup.inc.php create mode 100644 server/lib/classes/cron.inc.php create mode 100644 server/lib/classes/cronjob.inc.php create mode 100644 server/lib/classes/functions.inc.php create mode 100644 server/lib/classes/libdatetime.inc.php delete mode 100644 server/mods-available/monitor_core_module.inc.php diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql index 8480e76448..c562c0755b 100644 --- a/install/sql/ispconfig3.sql +++ b/install/sql/ispconfig3.sql @@ -1429,6 +1429,22 @@ CREATE TABLE `sys_config` ( `value` varchar(255) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sys_cron` +-- + +CREATE TABLE IF NOT EXISTS `sys_cron` ( + `name` varchar(50) NOT NULL, + `last_run` datetime NULL DEFAULT NULL, + `next_run` datetime NULL DEFAULT NULL, + `running` tinyint(1) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + + -- -------------------------------------------------------- -- diff --git a/server/cron.php b/server/cron.php new file mode 100644 index 0000000000..ce7a26fad6 --- /dev/null +++ b/server/cron.php @@ -0,0 +1,90 @@ +uses('ini_parser,file,services,getconf,system,cron,functions'); +$app->load('libdatetime,cronjob'); + + +// read all cron jobs +$path = SCRIPT_PATH . '/lib/classes/cron.d'; +if(!is_dir($path)) die('Cron path missing!'); +$files = array(); +$d = opendir($path); +while($f = readdir($d)) { + $file_path = $path . '/' . $f; + if($f === '.' || $f === '..' || !is_file($file_path)) continue; + if(substr($f, strrpos($f, '.')) !== '.php') continue; + $files[] = $f; +} +closedir($d); + +// sort in alphabetical order, so we can use prefixes like 000-xxx +sort($files); + +foreach($files as $f) { + $name = substr($f, 0, strpos($f, '.')); + if(preg_match('/^\d+\-(.*)$/', $name, $match)) $name = $match[1]; // strip numerical prefix from file name + + include($path . '/' . $f); + $class_name = 'cronjob_' . $name; + + if(class_exists($class_name, false)) { + $cronjob = new $class_name(); + if(get_parent_class($cronjob) !== 'cronjob') { + print 'Invalid class ' . $class_name . ' not extending class cronjob (' . get_parent_class($cronjob) . ')!' . "\n"; + unset($cronjob); + continue; + } + print 'Included ' . $class_name . ' from ' . $file_path . ' -> will now run job.' . "\n"; + + $cronjob->run(); + + print 'run job (' . $class_name . ') done.' . "\n"; + + unset($cronjob); + } +} +unset($files); + +die("finished.\n"); + +?> diff --git a/server/cron.sh b/server/cron.sh new file mode 100644 index 0000000000..281bb13afe --- /dev/null +++ b/server/cron.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin + +if [ -f /usr/local/ispconfig/server/lib/php.ini ]; then + PHPINIOWNER=`stat -c %U /usr/local/ispconfig/server/lib/php.ini` + if [ $PHPINIOWNER == 'root' ] || [ $PHPINIOWNER == 'ispconfig' ]; then + export PHPRC=/usr/local/ispconfig/server/lib + fi +fi + +/usr/bin/php -q /usr/local/ispconfig/server/cron.php diff --git a/server/cron_daily.php b/server/cron_daily.php deleted file mode 100644 index 029c4f30fb..0000000000 --- a/server/cron_daily.php +++ /dev/null @@ -1,1346 +0,0 @@ -uses('ini_parser,file,services,getconf,system'); - - -####################################################################################################### -// store the mailbox statistics in the database -####################################################################################################### - -$parse_mail_log = false; -$sql = "SELECT mailuser_id,maildir FROM mail_user WHERE server_id = ".$conf['server_id']; -$records = $app->db->queryAllRecords($sql); -if(count($records) > 0) $parse_mail_log = true; - -foreach($records as $rec) { - if(@is_file($rec['maildir'].'/ispconfig_mailsize')) { - $parse_mail_log = false; - - // rename file - rename($rec['maildir'].'/ispconfig_mailsize',$rec['maildir'].'/ispconfig_mailsize_save'); - - // Read the file - $lines = file($rec['maildir'].'/ispconfig_mailsize_save'); - $mail_traffic = 0; - foreach($lines as $line) { - $mail_traffic += intval($line); - } - unset($lines); - - // Delete backup file - if(@is_file($rec['maildir'].'/ispconfig_mailsize_save')) unlink($rec['maildir'].'/ispconfig_mailsize_save'); - - // Save the traffic stats in the sql database - $tstamp = date('Y-m'); - - $sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id']; - $tr = $app->dbmaster->queryOneRecord($sql); - - $mail_traffic += $tr['traffic']; - if($tr['traffic_id'] > 0) { - $sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id']; - } else { - $sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)"; - } - $app->dbmaster->query($sql); - //echo $sql; - - } - -} - -if($parse_mail_log == true) { - $mailbox_traffic = array(); - $mail_boxes = array(); - $mail_rewrites = array(); // we need to read all mail aliases and forwards because the address in amavis is not always the mailbox address - - function parse_mail_log_line($line) { - //Oct 31 17:35:48 mx01 amavis[32014]: (32014-05) Passed CLEAN, [IPv6:xxxxx] [IPv6:xxxxx] -> , Message-ID: , mail_id: xxxxxx, Hits: -1.89, size: 1591, queued_as: xxxxxxx, 946 ms - - if(preg_match('/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+[^ ]+\s+amavis.* <([^>]+)>\s+->\s+((<[^>]+>,)+) .*Message-ID:\s+<([^>]+)>.* size:\s+(\d+),.*$/', $line, $matches) == false) return false; - - $timestamp = strtotime($matches[1]); - if(!$timestamp) return false; - - $to = array(); - $recipients = explode(',', $matches[3]); - foreach($recipients as $recipient) { - $recipient = substr($recipient, 1, -1); - if(!$recipient || $recipient == $matches[2]) continue; - $to[] = $recipient; - } - - return array('line' => $line, 'timestamp' => $timestamp, 'size' => $matches[6], 'from' => $matches[2], 'to' => $to, 'message-id' => $matches[5]); - } - - function add_mailbox_traffic(&$traffic_array, $address, $traffic) { - global $mail_boxes, $mail_rewrites; - - $address = strtolower($address); - - if(in_array($address, $mail_boxes) == true) { - if(!isset($traffic_array[$address])) $traffic_array[$address] = 0; - $traffic_array[$address] += $traffic; - } elseif(array_key_exists($address, $mail_rewrites)) { - foreach($mail_rewrites[$address] as $address) { - if(!isset($traffic_array[$address])) $traffic_array[$address] = 0; - $traffic_array[$address] += $traffic; - } - } else { - // this is not a local address - skip it - } - } - - $sql = "SELECT email FROM mail_user WHERE server_id = ".$conf['server_id']; - $records = $app->db->queryAllRecords($sql); - foreach($records as $record) { - $mail_boxes[] = $record['email']; - } - $sql = "SELECT source, destination FROM mail_forwarding WHERE server_id = ".$conf['server_id']; - $records = $app->db->queryAllRecords($sql); - foreach($records as $record) { - $targets = preg_split('/[\n,]+/', $record['destination']); - foreach($targets as $target) { - if(in_array($target, $mail_boxes)) { - if(isset($mail_rewrites[$record['source']])) $mail_rewrites[$record['source']][] = $target; - else $mail_rewrites[$record['source']] = array($target); - } - } - } - - $state_file = dirname(__FILE__) . '/mail_log_parser.state'; - $prev_line = false; - $last_line = false; - $cur_line = false; - - if(file_exists($state_file)) { - $prev_line = parse_mail_log_line(trim(file_get_contents($state_file))); - //if($prev_line) echo "continuing from previous run, log position: " . $prev_line['message-id'] . " at " . strftime('%d.%m.%Y %H:%M:%S', $prev_line['timestamp']) . "\n"; - } - - if(file_exists('/var/log/mail.log')) { - $fp = fopen('/var/log/mail.log', 'r'); - //echo "Parsing mail.log...\n"; - $l = 0; - while($line = fgets($fp, 8192)) { - $l++; - //if($l % 1000 == 0) echo "\rline $l"; - $cur_line = parse_mail_log_line($line); - if(!$cur_line) continue; - - if($prev_line) { - // check if this line has to be processed - if($cur_line['timestamp'] < $prev_line['timestamp']) { - $parse_mail_log = false; // we do not need to parse the second file! - continue; // already processed - } elseif($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) { - $parse_mail_log = false; // we do not need to parse the second file! - $prev_line = false; // this line has already been processed but the next one has to be! - continue; - } - } - - add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']); - foreach($cur_line['to'] as $to) { - add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']); - } - $last_line = $line; // store for the state file - } - fclose($fp); - //echo "\n"; - } - - if($parse_mail_log == true && file_exists('/var/log/mail.log.1')) { - $fp = fopen('/var/log/mail.log.1', 'r'); - //echo "Parsing mail.log.1...\n"; - $l = 0; - while($line = fgets($fp, 8192)) { - $l++; - //if($l % 1000 == 0) echo "\rline $l"; - $cur_line = parse_mail_log_line($line); - if(!$cur_line) continue; - - if($prev_line) { - // check if this line has to be processed - if($cur_line['timestamp'] < $prev_line['timestamp']) continue; // already processed - if($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) { - $prev_line = false; // this line has already been processed but the next one has to be! - continue; - } - } - - add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']); - foreach($cur_line['to'] as $to) { - add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']); - } - } - fclose($fp); - //echo "\n"; - } - unset($mail_rewrites); - unset($mail_boxes); - - // Save the traffic stats in the sql database - $tstamp = date('Y-m'); - $sql = "SELECT mailuser_id,email FROM mail_user WHERE server_id = ".$conf['server_id']; - $records = $app->db->queryAllRecords($sql); - foreach($records as $rec) { - if(array_key_exists($rec['email'], $mailbox_traffic)) { - $sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id']; - $tr = $app->dbmaster->queryOneRecord($sql); - - $mail_traffic = $tr['traffic'] + $mailbox_traffic[$rec['email']]; - if($tr['traffic_id'] > 0) { - $sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id']; - } else { - $sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)"; - } - $app->dbmaster->query($sql); - //echo $sql; - } - } - - unset($mailbox_traffic); - if($last_line) file_put_contents($state_file, $last_line); -} - -####################################################################################################### -// Create webalizer statistics -####################################################################################################### - -function setConfigVar( $filename, $varName, $varValue, $append = 0 ) { - if($lines = @file($filename)) { - $out = ''; - $found = 0; - foreach($lines as $line) { - @list($key, $value) = preg_split('/[\t= ]+/', $line, 2); - if($key == $varName) { - $out .= $varName.' '.$varValue."\n"; - $found = 1; - } else { - $out .= $line; - } - } - if($found == 0) { - //* add \n if the last line does not end with \n or \r - if(substr($out,-1) != "\n" && substr($out,-1) != "\r") $out .= "\n"; - //* add the new line at the end of the file - if($append == 1) $out .= $varName.' '.$varValue."\n"; - } - - file_put_contents($filename,$out); - } -} - - -$sql = "SELECT domain_id, domain, document_root, web_folder, type, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') and stats_type = 'webalizer' AND server_id = ".$conf['server_id']; -$records = $app->db->queryAllRecords($sql); - -foreach($records as $rec) { - //$yesterday = date('Ymd',time() - 86400); - $yesterday = date('Ymd',strtotime("-1 day", time())); - - $log_folder = 'log'; - if($rec['type'] == 'vhostsubdomain') { - $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id'])); - $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']); - if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id']; - $log_folder .= '/' . $subdomain_host; - unset($tmp); - } - $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log'); - if(!@is_file($logfile)) { - $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz'); - if(!@is_file($logfile)) { - continue; - } - } - - $domain = escapeshellcmd($rec['domain']); - $statsdir = escapeshellcmd($rec['document_root'].'/'.($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web').'/stats'); - $webalizer = '/usr/bin/webalizer'; - $webalizer_conf_main = '/etc/webalizer/webalizer.conf'; - $webalizer_conf = escapeshellcmd($rec['document_root'].'/log/webalizer.conf'); - - if(is_file($statsdir.'/index.php')) unlink($statsdir.'/index.php'); - - if(!@is_file($webalizer_conf)) { - copy($webalizer_conf_main,$webalizer_conf); - } - - if(@is_file($webalizer_conf)) { - setConfigVar($webalizer_conf, 'Incremental', 'yes'); - setConfigVar($webalizer_conf, 'IncrementalName', $statsdir.'/webalizer.current'); - setConfigVar($webalizer_conf, 'HistoryName', $statsdir.'/webalizer.hist'); - } - - - if(!@is_dir($statsdir)) mkdir($statsdir); - exec("$webalizer -c $webalizer_conf -n $domain -s $domain -r $domain -q -T -p -o $statsdir $logfile"); -} - -####################################################################################################### -// Create awstats statistics -####################################################################################################### - -$sql = "SELECT domain_id, domain, document_root, web_folder, type, system_user, system_group, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') and stats_type = 'awstats' AND server_id = ".$conf['server_id']; -$records = $app->db->queryAllRecords($sql); - -$web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); - -foreach($records as $rec) { - //$yesterday = date('Ymd',time() - 86400); - $yesterday = date('Ymd',strtotime("-1 day", time())); - - $log_folder = 'log'; - if($rec['type'] == 'vhostsubdomain') { - $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id'])); - $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']); - if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id']; - $log_folder .= '/' . $subdomain_host; - unset($tmp); - } - $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log'); - if(!@is_file($logfile)) { - $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz'); - if(!@is_file($logfile)) { - continue; - } - } - $web_folder = ($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web'); - $domain = escapeshellcmd($rec['domain']); - $statsdir = escapeshellcmd($rec['document_root'].'/'.$web_folder.'/stats'); - $awstats_pl = $web_config['awstats_pl']; - $awstats_buildstaticpages_pl = $web_config['awstats_buildstaticpages_pl']; - - $awstats_conf_dir = $web_config['awstats_conf_dir']; - $awstats_website_conf_file = $web_config['awstats_conf_dir'].'/awstats.'.$domain.'.conf'; - - if(is_file($awstats_website_conf_file)) unlink($awstats_website_conf_file); - - $sql = "SELECT domain FROM web_domain WHERE (type = 'alias' OR type = 'subdomain') AND parent_domain_id = ".$rec['domain_id']; - $aliases = $app->db->queryAllRecords($sql); - $aliasdomain = ''; - - if(is_array($aliases)) { - foreach ($aliases as $alias) { - $aliasdomain.= ' '.$alias['domain']. ' www.'.$alias['domain']; - } - } - - if(!is_file($awstats_website_conf_file)) { - $awstats_conf_file_content = 'Include "'.$awstats_conf_dir.'/awstats.conf" -LogFile="/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log" -SiteDomain="'.$domain.'" -HostAliases="www.'.$domain.' localhost 127.0.0.1'.$aliasdomain.'"'; - file_put_contents($awstats_website_conf_file,$awstats_conf_file_content); - } - - if(!@is_dir($statsdir)) mkdir($statsdir); - if(is_link('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log')) unlink('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log'); - symlink($logfile,'/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log'); - - $awmonth = date("n"); - $awyear = date("Y"); - - if (date("d") == 1) { - $awmonth = date("m")-1; - if (date("m") == 1) { - $awyear = date("Y")-1; - $awmonth = "12"; - } - } - - // awstats_buildstaticpages.pl -update -config=mydomain.com -lang=en -dir=/var/www/domain.com/'.$web_folder.'/stats -awstatsprog=/path/to/awstats.pl - // $command = "$awstats_buildstaticpages_pl -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'"; - - $command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'"; - - if (date("d") == 2) { - $awmonth = date("m")-1; - if (date("m") == 1) { - $awyear = date("Y")-1; - $awmonth = "12"; - } - - $statsdirold = $statsdir."/".$awyear."-".$awmonth."/"; - mkdir($statsdirold); - $files = scandir($statsdir); - foreach ($files as $file) { - if (substr($file,0,1) != "." && !is_dir("$statsdir"."/"."$file") && substr($file,0,1) != "w" && substr($file,0,1) != "i") copy("$statsdir"."/"."$file","$statsdirold"."$file"); - } - } - - - if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) { - exec($command); - if(is_file($rec['document_root'].'/'.$web_folder.'/stats/index.html')) unlink($rec['document_root'].'/'.$web_folder.'/stats/index.html'); - rename($rec['document_root'].'/'.$web_folder.'/stats/awstats.'.$domain.'.html',$rec['document_root'].'/'.$web_folder.'/stats/awsindex.html'); - if(!is_file($rec['document_root']."/".$web_folder."/stats/index.php")) { - if(file_exists("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master")) { - copy("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php"); - } else { - copy("/usr/local/ispconfig/server/conf/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php"); - } - } - - $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG); - } else { - $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN); - } - - if(is_file($rec['document_root']."/".$web_folder."/stats/index.php")) { - chown($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_user']); - chgrp($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_group']); - } - -} - - -####################################################################################################### -// Make the web logfiles directories world readable to enable ftp access -####################################################################################################### - -if(is_dir('/var/log/ispconfig/httpd')) exec('chmod +r /var/log/ispconfig/httpd/*'); - -####################################################################################################### -// Manage and compress web logfiles and create traffic statistics -####################################################################################################### - -$sql = "SELECT domain_id, domain, type, document_root, web_folder, parent_domain_id FROM web_domain WHERE (type = 'vhost' or type = 'vhostsubdomain') AND server_id = ".$conf['server_id']; -$records = $app->db->queryAllRecords($sql); -foreach($records as $rec) { - - //* create traffic statistics based on yesterdays access log file - $yesterday = date('Ymd',time() - 86400); - - $log_folder = 'log'; - if($rec['type'] == 'vhostsubdomain') { - $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id'])); - $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']); - if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id']; - $log_folder .= '/' . $subdomain_host; - unset($tmp); - } - - $logfile = $rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log'; - $total_bytes = 0; - - $handle = @fopen($logfile, "r"); - if ($handle) { - while (($line = fgets($handle, 4096)) !== false) { - if (preg_match('/^\S+ \S+ \S+ \[.*?\] "\S+.*?" \d+ (\d+) ".*?" ".*?"/', $line, $m)) { - $total_bytes += intval($m[1]); - } - } - - //* Insert / update traffic in master database - $traffic_date = date('Y-m-d',time() - 86400); - $tmp = $app->dbmaster->queryOneRecord("select hostname from web_traffic where hostname='".$rec['domain']."' and traffic_date='".$traffic_date."'"); - if(is_array($tmp) && count($tmp) > 0) { - $sql = "update web_traffic set traffic_bytes=traffic_bytes+" - . $total_bytes - . " where hostname='" . $rec['domain'] - . "' and traffic_date='" . $traffic_date . "'"; - } else { - $sql = "insert into web_traffic (hostname, traffic_date, traffic_bytes) values ('".$rec['domain']."', '".$traffic_date."', '".$total_bytes."')"; - } - $app->dbmaster->query($sql); - - fclose($handle); - } - - $yesterday2 = date('Ymd',time() - 86400*2); - $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday2.'-access.log'); - - //* Compress logfile - if(@is_file($logfile)) { - // Compress yesterdays logfile - exec("gzip -c $logfile > $logfile.gz"); - unlink($logfile); - } - - // rotate and compress the error.log when it exceeds a size of 10 MB - $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/error.log'); - if(is_file($logfile) && filesize($logfile) > 10000000) { - exec("gzip -c $logfile > $logfile.1.gz"); - exec("cat /dev/null > $logfile"); - } - - // delete logfiles after 30 days - $month_ago = date('Ymd',time() - 86400 * 30); - $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$month_ago.'-access.log.gz'); - if(@is_file($logfile)) { - unlink($logfile); - } - - //* Delete older Log files, in case that we missed them before due to serverdowntimes. - $datepart = date('Ym',time() - 86400 * 31 * 2); - - $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log.gz'; - exec('rm -f '.$logfile); - - $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log'; - exec('rm -f '.$logfile); -} - -//* Delete old logfiles in /var/log/ispconfig/httpd/ that were created by vlogger for the hostname of the server -exec('hostname -f', $tmp_hostname); -if($tmp_hostname[0] != '' && is_dir('/var/log/ispconfig/httpd/'.$tmp_hostname[0])) { - exec('cd /var/log/ispconfig/httpd/'.$tmp_hostname[0]."; find . -mtime +30 -name '*.log' | xargs rm > /dev/null 2> /dev/null"); -} -unset($tmp_hostname); - -####################################################################################################### -// Rotate the ispconfig.log file -####################################################################################################### - -// rotate the ispconfig.log when it exceeds a size of 10 MB -$logfile = $conf['ispconfig_log_dir'].'/ispconfig.log'; -if(is_file($logfile) && filesize($logfile) > 10000000) { - exec("gzip -c $logfile > $logfile.1.gz"); - exec("cat /dev/null > $logfile"); -} - -// rotate the cron.log when it exceeds a size of 10 MB -$logfile = $conf['ispconfig_log_dir'].'/cron.log'; -if(is_file($logfile) && filesize($logfile) > 10000000) { - exec("gzip -c $logfile > $logfile.1.gz"); - exec("cat /dev/null > $logfile"); -} - -// rotate the auth.log when it exceeds a size of 10 MB -$logfile = $conf['ispconfig_log_dir'].'/auth.log'; -if(is_file($logfile) && filesize($logfile) > 10000000) { - exec("gzip -c $logfile > $logfile.1.gz"); - exec("cat /dev/null > $logfile"); -} - -####################################################################################################### -// Cleanup website tmp directories -####################################################################################################### - -$sql = "SELECT domain_id, domain, document_root, system_user FROM web_domain WHERE server_id = ".$conf['server_id']; -$records = $app->db->queryAllRecords($sql); -$app->uses('system'); -if(is_array($records)) { - foreach($records as $rec){ - $tmp_path = realpath(escapeshellcmd($rec['document_root'].'/tmp')); - if($tmp_path != '' && strlen($tmp_path) > 10 && is_dir($tmp_path) && $app->system->is_user($rec['system_user'])){ - exec('cd '.$tmp_path."; find . -mtime +1 -name 'sess_*' | grep -v -w .no_delete | xargs rm > /dev/null 2> /dev/null"); - } - } -} - -####################################################################################################### -// Cleanup logs in master database (only the "master-server") -####################################################################################################### - -if ($app->dbmaster == $app->db) { - /** 7 days */ - $tstamp = time() - (60*60*24*7); - - /* - * Keep 7 days in sys_log - * (we can delete the old items, because if they are OK, they don't interrest anymore - * if they are NOT ok, the server will try to process them in 1 minute and so the - * error appears again after 1 minute. So it is no problem to delete the old one! - */ - $sql = "DELETE FROM sys_log WHERE tstamp < " . $tstamp . " AND server_id != 0"; - $app->dbmaster->query($sql); - - /* - * Delete all remote-actions "done" and older than 7 days - * ATTENTION: We have the same problem as described in cleaning the datalog. We must not - * delete the last entry - */ - $sql = "SELECT max(action_id) FROM sys_remoteaction"; - $res = $app->dbmaster->queryOneRecord($sql); - $maxId = $res['max(action_id)']; - $sql = "DELETE FROM sys_remoteaction " . - "WHERE tstamp < " . $tstamp . " " . - " AND action_state = 'ok' " . - " AND action_id <" . intval($maxId); - $app->dbmaster->query($sql); - - /* - * The sys_datalog is more difficult. - * 1) We have to keet ALL entries with - * server_id=0, because they depend on ALL servers (even if they are not - * actually in the system (and will be insered in 3 days or so). - * 2) We have to keey ALL entries which are not actually precessed by the - * server never mind how old they are! - * 3) We have to keep the entry with the highest autoinc-id, because mysql calculates the - * autoinc-id as "new value = max(row) +1" and does not store this in a separate table. - * This means, if we delete to entry with the highest autoinc-value then this value is - * reused as autoinc and so there are more than one entries with the same value (over - * for example 4 Weeks). This is confusing for our system. - * ATTENTION 2) and 3) is in some case NOT the same! so we have to check both! - */ - - /* First we need all servers and the last sys_datalog-id they processed */ - $sql = "SELECT server_id, updated FROM server ORDER BY server_id"; - $records = $app->dbmaster->queryAllRecords($sql); - - /* Then we need the highest value ever */ - $sql = "SELECT max(datalog_id) FROM sys_datalog"; - $res = $app->dbmaster->queryOneRecord($sql); - $maxId = $res['max(datalog_id)']; - - /* Then delete server by server */ - foreach($records as $server) { - $tmp_server_id = intval($server['server_id']); - if($tmp_server_id > 0) { - $sql = "DELETE FROM sys_datalog " . - "WHERE tstamp < " . $tstamp . - " AND server_id = " . intval($server['server_id']) . - " AND datalog_id < " . intval($server['updated']) . - " AND datalog_id < " . intval($maxId); - } -// echo $sql . "\n"; - $app->dbmaster->query($sql); - } -} - -######### -// function for sending notification emails -######### -function send_notification_email($template, $placeholders, $recipients) { - global $conf; - - if(!is_array($recipients) || count($recipients) < 1) return false; - if(!is_array($placeholders)) $placeholders = array(); - - if(file_exists($conf['rootpath'].'/conf-custom/mail/' . $template . '_'.$conf['language'].'.txt')) { - $lines = file($conf['rootpath'].'/conf-custom/mail/' . $template . '_'.$conf['language'].'.txt'); - } elseif(file_exists($conf['rootpath'].'/conf-custom/mail/' . $template . '_en.txt')) { - $lines = file($conf['rootpath'].'/conf-custom/mail/' . $template . '_en.txt'); - } elseif(file_exists($conf['rootpath'].'/conf/mail/' . $template . '_'.$conf['language'].'.txt')) { - $lines = file($conf['rootpath'].'/conf/mail/' . $template . '_'.$conf['language'].'.txt'); - } else { - $lines = file($conf['rootpath'].'/conf/mail/' . $template . '_en.txt'); - } - - //* get mail headers, subject and body - $mailHeaders = ''; - $mailBody = ''; - $mailSubject = ''; - $inHeader = true; - for($l = 0; $l < count($lines); $l++) { - if($lines[$l] == '') { - $inHeader = false; - continue; - } - if($inHeader == true) { - $parts = explode(':', $lines[$l], 2); - if(strtolower($parts[0]) == 'subject') $mailSubject = trim($parts[1]); - unset($parts); - $mailHeaders .= trim($lines[$l]) . "\n"; - } else { - $mailBody .= trim($lines[$l]) . "\n"; - } - } - $mailBody = trim($mailBody); - - //* Replace placeholders - $mailHeaders = strtr($mailHeaders, $placeholders); - $mailSubject = strtr($mailSubject, $placeholders); - $mailBody = strtr($mailBody, $placeholders); - - for($r = 0; $r < count($recipients); $r++) { - mail($recipients[$r], $mailSubject, $mailBody, $mailHeaders); - } - - unset($mailSubject); - unset($mailHeaders); - unset($mailBody); - unset($lines); - - return true; -} - - -####################################################################################################### -// enforce traffic quota (run only on the "master-server") -####################################################################################################### - -if ($app->dbmaster == $app->db) { - - $global_config = $app->getconf->get_global_config('mail'); - - $current_month = date('Y-m'); - - //* Check website traffic quota - $sql = "SELECT sys_groupid,domain_id,domain,traffic_quota,traffic_quota_lock FROM web_domain WHERE (traffic_quota > 0 or traffic_quota_lock = 'y') and (type = 'vhost' OR type = 'vhostsubdomain')"; - $records = $app->db->queryAllRecords($sql); - if(is_array($records)) { - foreach($records as $rec) { - - $web_traffic_quota = $rec['traffic_quota']; - $domain = $rec['domain']; - - // get the client - /* - $client_group_id = $rec["sys_groupid"]; - $client = $app->db->queryOneRecord("SELECT limit_traffic_quota,parent_client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); - $reseller = $app->db->queryOneRecord("SELECT limit_traffic_quota FROM client WHERE client_id = ".intval($client['parent_client_id'])); - - $client_traffic_quota = intval($client['limit_traffic_quota']); - $reseller_traffic_quota = intval($reseller['limit_traffic_quota']); - */ - - //* get the traffic - $tmp = $app->db->queryOneRecord("SELECT SUM(traffic_bytes) As total_traffic_bytes FROM web_traffic WHERE traffic_date like '$current_month%' AND hostname = '$domain'"); - $web_traffic = round($tmp['total_traffic_bytes']/1024/1024); - - //* Website is over quota, we will disable it - /*if( ($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) || - ($client_traffic_quota > 0 && $web_traffic > $client_traffic_quota) || - ($reseller_traffic_quota > 0 && $web_traffic > $reseller_traffic_quota)) {*/ - if($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) { - $app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'y',active = 'n'", 'domain_id', $rec['domain_id']); - $app->log('Traffic quota for '.$rec['domain'].' exceeded. Disabling website.',LOGLEVEL_DEBUG); - - //* Send traffic notifications - if($rec['traffic_quota_lock'] != 'y' && ($web_config['overtraffic_notify_admin'] == 'y' || $web_config['overtraffic_notify_client'] == 'y')) { - - $placeholders = array('{domain}' => $rec['domain'], - '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root')); - - $recipients = array(); - //* send email to admin - if($global_config['admin_mail'] != '' && $web_config['overtraffic_notify_admin'] == 'y') { - $recipients[] = $global_config['admin_mail']; - } - - //* Send email to client - if($web_config['overtraffic_notify_client'] == 'y') { - $client_group_id = $rec["sys_groupid"]; - $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); - if($client['email'] != '') { - $recipients[] = $client['email']; - } - } - - send_notification_email('web_traffic_notification', $placeholders, $recipients); - } - - } else { - //* unlock the website, if traffic is lower then quota - if($rec['traffic_quota_lock'] == 'y') { - $app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'n',active = 'y'", 'domain_id', $rec['domain_id']); - $app->log('Traffic quota for '.$rec['domain'].' ok again. Re-enabling website.',LOGLEVEL_DEBUG); - } - } - } - } - - -} - - -####################################################################################################### -// send website quota warnings by email -####################################################################################################### - -if ($app->dbmaster == $app->db) { - - $global_config = $app->getconf->get_global_config('mail'); - - //* Check website disk quota - $sql = "SELECT domain_id,sys_groupid,domain,system_user,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM web_domain WHERE (type = 'vhost' OR type = 'vhostsubdomain')"; - $records = $app->db->queryAllRecords($sql); - if(is_array($records) && !empty($records)) { - - $tmp_rec = $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'harddisk_quota' ORDER BY created DESC"); - $monitor_data = array(); - if(is_array($tmp_rec)) { - foreach ($tmp_rec as $tmp_mon) { - $monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data']))); - } - } - - foreach($records as $rec) { - - //$web_hd_quota = $rec['hd_quota']; - $domain = $rec['domain']; - - $username = $rec['system_user']; - $rec['used'] = $monitor_data['user'][$username]['used']; - $rec['soft'] = $monitor_data['user'][$username]['soft']; - $rec['hard'] = $monitor_data['user'][$username]['hard']; - $rec['files'] = $monitor_data['user'][$username]['files']; - - if (!is_numeric($rec['used'])){ - if ($rec['used'][0] > $rec['used'][1]){ - $rec['used'] = $rec['used'][0]; - } else { - $rec['used'] = $rec['used'][1]; - } - } - if (!is_numeric($rec['soft'])) $rec['soft']=$rec['soft'][1]; - if (!is_numeric($rec['hard'])) $rec['hard']=$rec['hard'][1]; - if (!is_numeric($rec['files'])) $rec['files']=$rec['files'][1]; - - // used space ratio - if($rec['soft'] > 0){ - $used_ratio = $rec['used']/$rec['soft']; - } else { - $used_ratio = 0; - } - - $rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%'; - - if($rec['used'] > 1024) { - $rec['used'] = round($rec['used'] / 1024,2).' MB'; - } else { - if ($rec['used'] != '') $rec['used'] .= ' KB'; - } - - if($rec['soft'] > 1024) { - $rec['soft'] = round($rec['soft'] / 1024,2).' MB'; - } elseif($rec['soft'] == 0){ - $rec['soft'] = '----'; - } else { - $rec['soft'] .= ' KB'; - } - - if($rec['hard'] > 1024) { - $rec['hard'] = round($rec['hard'] / 1024,2).' MB'; - } elseif($rec['hard'] == 0){ - $rec['hard'] = '----'; - } else { - $rec['hard'] .= ' KB'; - } - - // send notifications only if 90% or more of the quota are used - if($used_ratio < 0.9) { - // reset notification date - if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = NULL", 'domain_id', $rec['domain_id']); - - // send notification - everything ok again - if($rec['last_quota_notification'] && $web_config['overquota_notify_onok'] == 'y' && ($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y')) { - $placeholders = array('{domain}' => $rec['domain'], - '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), - '{used}' => $rec['used'], - '{soft}' => $rec['soft'], - '{hard}' => $rec['hard'], - '{ratio}' => $rec['ratio']); - - $recipients = array(); - - //* send email to admin - if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') { - $recipients[] = $global_config['admin_mail']; - } - - //* Send email to client - if($web_config['overquota_notify_client'] == 'y') { - $client_group_id = $rec["sys_groupid"]; - $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); - if($client['email'] != '') { - $recipients[] = $client['email']; - } - } - send_notification_email('web_quota_ok_notification', $placeholders, $recipients); - } - - continue; - } - - // could a notification be sent? - $send_notification = false; - if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified - elseif($web_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $web_config['overquota_notify_freq']) $send_notification = true; - - //* Send quota notifications - if(($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y') && $send_notification == true) { - $app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = CURDATE()", 'domain_id', $rec['domain_id']); - - $placeholders = array('{domain}' => $rec['domain'], - '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), - '{used}' => $rec['used'], - '{soft}' => $rec['soft'], - '{hard}' => $rec['hard'], - '{ratio}' => $rec['ratio']); - - $recipients = array(); - - //* send email to admin - if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') { - $recipients[] = $global_config['admin_mail']; - } - - //* Send email to client - if($web_config['overquota_notify_client'] == 'y') { - $client_group_id = $rec["sys_groupid"]; - $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); - if($client['email'] != '') { - $recipients[] = $client['email']; - } - } - send_notification_email('web_quota_notification', $placeholders, $recipients); - } - } - } -} - - -####################################################################################################### -// send mail quota warnings by email -####################################################################################################### - -if ($app->dbmaster == $app->db) { - - $global_config = $app->getconf->get_global_config('mail'); - $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail'); - - //* Check email quota - $sql = "SELECT mailuser_id,sys_groupid,email,name,quota,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM mail_user"; - $records = $app->db->queryAllRecords($sql); - if(is_array($records) && !empty($records)) { - - $tmp_rec = $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'email_quota' ORDER BY created DESC"); - $monitor_data = array(); - if(is_array($tmp_rec)) { - foreach ($tmp_rec as $tmp_mon) { - //$monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data']))); - $tmp_array = unserialize($app->db->unquote($tmp_mon['data'])); - if(is_array($tmp_array)) { - foreach($tmp_array as $username => $data) { - if(@!$monitor_data[$username]['used']) $monitor_data[$username]['used'] = $data['used']; - } - } - } - } - - foreach($records as $rec) { - - $email = $rec['email']; - - $rec['used'] = isset($monitor_data[$email]['used']) ? $monitor_data[$email]['used'] : array(1 => 0); - - if (!is_numeric($rec['used'])) $rec['used']=$rec['used'][1]; - - // used space ratio - if($rec['quota'] > 0){ - $used_ratio = $rec['used']/$rec['quota']; - } else { - $used_ratio = 0; - } - - $rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%'; - - if($rec['quota'] > 0){ - $rec['quota'] = round($rec['quota'] / 1048576,4).' MB'; - } else { - $rec['quota'] = '----'; - } - - if($rec['used'] < 1544000) { - $rec['used'] = round($rec['used'] / 1024,4).' KB'; - } else { - $rec['used'] = round($rec['used'] / 1048576,4).' MB'; - } - - // send notifications only if 90% or more of the quota are used - if($used_ratio < 0.9) { - // reset notification date - if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = NULL", 'mailuser_id', $rec['mailuser_id']); - - // send notification - everything ok again - if($rec['last_quota_notification'] && $mail_config['overquota_notify_onok'] == 'y' && ($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y')) { - $placeholders = array('{email}' => $rec['email'], - '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), - '{used}' => $rec['used'], - '{name}' => $rec['name'], - '{quota}' => $rec['quota'], - '{ratio}' => $rec['ratio']); - - $recipients = array(); - //* send email to admin - if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') { - $recipients[] = $global_config['admin_mail']; - } - - //* Send email to client - if($mail_config['overquota_notify_client'] == 'y') { - $client_group_id = $rec["sys_groupid"]; - $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); - if($client['email'] != '') { - $recipients[] = $client['email']; - } - } - - send_notification_email('mail_quota_ok_notification', $placeholders, $recipients); - } - - continue; - } - - //* Send quota notifications - // could a notification be sent? - $send_notification = false; - if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified - elseif($mail_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $mail_config['overquota_notify_freq']) $send_notification = true; - - if(($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y') && $send_notification == true) { - $app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = CURDATE()", 'mailuser_id', $rec['mailuser_id']); - - $placeholders = array('{email}' => $rec['email'], - '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), - '{used}' => $rec['used'], - '{name}' => $rec['name'], - '{quota}' => $rec['quota'], - '{ratio}' => $rec['ratio']); - - $recipients = array(); - //* send email to admin - if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') { - $recipients[] = $global_config['admin_mail']; - } - - //* Send email to client - if($mail_config['overquota_notify_client'] == 'y') { - $client_group_id = $rec["sys_groupid"]; - $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); - if($client['email'] != '') { - $recipients[] = $client['email']; - } - } - - send_notification_email('mail_quota_notification', $placeholders, $recipients); - } - } - } -} - - -####################################################################################################### -// deactivate virtual servers (run only on the "master-server") -####################################################################################################### - -if ($app->dbmaster == $app->db) { - $current_date = date('Y-m-d'); - - //* Check which virtual machines have to be deactivated - $sql = "SELECT * FROM openvz_vm WHERE active = 'y' AND active_until_date != '0000-00-00' AND active_until_date < '$current_date'"; - $records = $app->db->queryAllRecords($sql); - if(is_array($records)) { - foreach($records as $rec) { - $app->dbmaster->datalogUpdate('openvz_vm', "active = 'n'", 'vm_id', $rec['vm_id']); - $app->log('Virtual machine active date expired. Disabling VM '.$rec['veid'],LOGLEVEL_DEBUG); - } - } - - -} - -####################################################################################################### -// Create website backups -####################################################################################################### -function formatBytes($size, $precision = 2) { - $base=log($size)/log(1024); - $suffixes=array('','k','M','G','T'); - return round(pow(1024,$base-floor($base)),$precision).$suffixes[floor($base)]; -} - -$server_config = $app->getconf->get_server_config($conf['server_id'], 'server'); -$backup_dir = $server_config['backup_dir']; -$backup_mode = $server_config['backup_mode']; -if($backup_mode == '') $backup_mode = 'userzip'; - -$web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); -$http_server_user = $web_config['user']; - -if($backup_dir != '') { - - if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') { - $backup_dir_permissions = 0755; - } else { - $backup_dir_permissions = 0750; - } - - if(!is_dir($backup_dir)) { - mkdir(escapeshellcmd($backup_dir), $backup_dir_permissions, true); - } else { - chmod(escapeshellcmd($backup_dir), $backup_dir_permissions); - } - - $sql = "SELECT * FROM web_domain WHERE server_id = '".$conf['server_id']."' AND (type = 'vhost' OR type = 'vhostsubdomain') AND backup_interval != 'none'"; - $records = $app->db->queryAllRecords($sql); - if(is_array($records)) { - foreach($records as $rec) { - - //* Do the website backup - if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) { - - $web_path = $rec['document_root']; - $web_user = $rec['system_user']; - $web_group = $rec['system_group']; - $web_id = $rec['domain_id']; - $web_backup_dir = $backup_dir.'/web'.$web_id; - if(!is_dir($web_backup_dir)) mkdir($web_backup_dir, 0750); - chmod($web_backup_dir, 0750); - //if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') { - chown($web_backup_dir, $rec['system_user']); - chgrp($web_backup_dir, $rec['system_group']); - /*} else { - chown($web_backup_dir, 'root'); - chgrp($web_backup_dir, 'root'); - }*/ - if($backup_mode == 'userzip') { - //* Create a .zip backup as web user and include also files owned by apache / nginx user - $web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.zip'; - exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -group '.escapeshellarg($web_group).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval); - if($retval == 0) exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -user '.escapeshellarg($http_server_user).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --update --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval); - } else { - //* Create a tar.gz backup as root user - $web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.tar.gz'; - exec('tar pczf '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' --exclude=backup\* --directory '.escapeshellarg($web_path).' .', $tmp_output, $retval); - } - if($retval == 0){ - chown($web_backup_dir.'/'.$web_backup_file, 'root'); - chgrp($web_backup_dir.'/'.$web_backup_file, 'root'); - chmod($web_backup_dir.'/'.$web_backup_file, 0750); - - //* Insert web backup record in database - //$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')"; - //$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id'); - $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')"; - $app->db->query($sql); - if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); - } else { - if(is_file($web_backup_dir.'/'.$web_backup_file)) unlink($web_backup_dir.'/'.$web_backup_file); - } - - //* Remove old backups - $backup_copies = intval($rec['backup_copies']); - - $dir_handle = dir($web_backup_dir); - $files = array(); - while (false !== ($entry = $dir_handle->read())) { - if($entry != '.' && $entry != '..' && substr($entry,0,3) == 'web' && is_file($web_backup_dir.'/'.$entry)) { - $files[] = $entry; - } - } - $dir_handle->close(); - - rsort($files); - - for ($n = $backup_copies; $n <= 10; $n++) { - if(isset($files[$n]) && is_file($web_backup_dir.'/'.$files[$n])) { - unlink($web_backup_dir.'/'.$files[$n]); - //$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($files[$n])."'"; - //$tmp = $app->dbmaster->queryOneRecord($sql); - //$app->dbmaster->datalogDelete('web_backup', 'backup_id', $tmp['backup_id']); - //$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']); - $sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($files[$n])."'"; - $app->db->query($sql); - if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); - } - } - - unset($files); - unset($dir_handle); - - //* Remove backupdir symlink and create as directory instead - $app->uses('system'); - $app->system->web_folder_protection($web_path,false); - - if(is_link($web_path.'/backup')) { - unlink($web_path.'/backup'); - } - if(!is_dir($web_path.'/backup')) { - mkdir($web_path.'/backup'); - chown($web_path.'/backup', $rec['system_user']); - chgrp($web_path.'/backup', $rec['system_group']); - } - - $app->system->web_folder_protection($web_path,true); - - } - - /* If backup_interval is set to none and we have a - backup directory for the website, then remove the backups */ - if($rec['backup_interval'] == 'none') { - $web_id = $rec['domain_id']; - $web_user = $rec['system_user']; - $web_backup_dir = realpath($backup_dir.'/web'.$web_id); - if(is_dir($web_backup_dir)) { - exec('sudo -u '.escapeshellarg($web_user).' rm -f '.escapeshellarg($web_backup_dir.'/*')); - } - } - } - } - - $sql = "SELECT * FROM web_database WHERE server_id = '".$conf['server_id']."' AND backup_interval != 'none'"; - $records = $app->db->queryAllRecords($sql); - if(is_array($records)) { - - include('lib/mysql_clientdb.conf'); - - foreach($records as $rec) { - - //* Do the database backup - if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) { - - $web_id = $rec['parent_domain_id']; - $db_backup_dir = $backup_dir.'/web'.$web_id; - if(!is_dir($db_backup_dir)) mkdir($db_backup_dir, 0750); - chmod($db_backup_dir, 0750); - chown($db_backup_dir, 'root'); - chgrp($db_backup_dir, 'root'); - - //* Do the mysql database backup with mysqldump or mongodump - $db_id = $rec['database_id']; - $db_name = $rec['database_name']; - - if ($rec['type'] == 'mysql') { - $db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i').'.sql'; - //$command = "mysqldump -h '".escapeshellcmd($clientdb_host)."' -u '".escapeshellcmd($clientdb_user)."' -p'".escapeshellcmd($clientdb_password)."' -c --add-drop-table --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'"; - $command = "mysqldump -h ".escapeshellarg($clientdb_host)." -u ".escapeshellarg($clientdb_user)." -p".escapeshellarg($clientdb_password)." -c --add-drop-table --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'"; - exec($command, $tmp_output, $retval); - - //* Compress the backup with gzip - if($retval == 0) exec("gzip -c '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file)."' > '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".gz'", $tmp_output, $retval); - - if($retval == 0){ - chmod($db_backup_dir.'/'.$db_backup_file.'.gz', 0750); - chown($db_backup_dir.'/'.$db_backup_file.'.gz', fileowner($db_backup_dir)); - chgrp($db_backup_dir.'/'.$db_backup_file.'.gz', filegroup($db_backup_dir)); - - //* Insert web backup record in database - //$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')"; - //$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id'); - $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')"; - $app->db->query($sql); - if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); - - } else { - if(is_file($db_backup_dir.'/'.$db_backup_file.'.gz')) unlink($db_backup_dir.'/'.$db_backup_file.'.gz'); - } - //* Remove the uncompressed file - if(is_file($db_backup_dir.'/'.$db_backup_file)) unlink($db_backup_dir.'/'.$db_backup_file); - } else if ($rec['type'] == 'mongo') { - $db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i'); - - try { - $connection = new MongoClient("mongodb://root:123456@127.0.0.1:27017/admin"); - $db = $connection->selectDB($db_name); - // exclude not supported by mongodump, only get user collections - $collections = $db->getCollectionNames(false); - - foreach ($collections as $collection) { - // mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d -c -o /tmp/test - $command = "mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d ".escapeshellcmd($db_name)." -c ".escapeshellcmd($collection)." -o ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file); - exec($command); - } - - if (is_dir(escapeshellcmd($db_backup_dir.'/'.$db_backup_file))) { - //* Compress the backup with gzip - exec("cd ".escapeshellcmd($db_backup_dir)." && tar -pczf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".tar.gz ".escapeshellcmd($db_backup_file)); - chmod($db_backup_dir.'/'.$db_backup_file.'.tar.gz', 0750); - chown($db_backup_dir.'/'.$db_backup_file.'.tar.gz', fileowner($db_backup_dir)); - chgrp($db_backup_dir.'/'.$db_backup_file.'.tar.gz', filegroup($db_backup_dir)); - - //* Insert web backup record in database - $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mongodb','rootgz',".time().",'".$app->db->quote($db_backup_file).".tar.gz')"; - $app->db->query($sql); - - if ($app->db->dbHost != $app->dbmaster->dbHost) { - $app->dbmaster->query($sql); - } - - //* Remove the uncompressed file - exec("rm -rf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file)); - } - } catch (MongoConnnectionException $e) { - // connecting to MongoDB failed - cannot create backup - } - } - - //* Remove old backups - $backup_copies = intval($rec['backup_copies']); - - $dir_handle = dir($db_backup_dir); - $files = array(); - while (false !== ($entry = $dir_handle->read())) { - if($entry != '.' && $entry != '..' && (preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.sql.gz$/', $entry, $matches) || preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.tar.gz$/', $entry, $matches)) && is_file($db_backup_dir.'/'.$entry)) { - if(array_key_exists($matches[1], $files) == false) $files[$matches[1]] = array(); - $files[$matches[1]][] = $entry; - } - } - $dir_handle->close(); - - reset($files); - foreach($files as $db_name => $filelist) { - rsort($filelist); - for ($n = $backup_copies; $n <= 10; $n++) { - if(isset($filelist[$n]) && is_file($db_backup_dir.'/'.$filelist[$n])) { - unlink($db_backup_dir.'/'.$filelist[$n]); - //$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'"; - //$tmp = $app->dbmaster->queryOneRecord($sql); - //$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']); - $sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'"; - $app->db->query($sql); - if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); - } - } - } - - unset($files); - unset($dir_handle); - } - } - - unset($clientdb_host); - unset($clientdb_user); - unset($clientdb_password); - - } -} - - -die("finished.\n"); -?> diff --git a/server/cron_daily.sh b/server/cron_daily.sh old mode 100644 new mode 100755 index 9ffedae9ed..a96da2f095 --- a/server/cron_daily.sh +++ b/server/cron_daily.sh @@ -1,16 +1,3 @@ #!/bin/sh -PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin - -if [ -f /usr/local/ispconfig/server/lib/php.ini ]; then - PHPINIOWNER=`stat -c %U /usr/local/ispconfig/server/lib/php.ini` - if [ $PHPINIOWNER == 'root' ] || [ $PHPINIOWNER == 'ispconfig' ]; then - export PHPRC=/usr/local/ispconfig/server/lib - fi -fi - -/usr/bin/php -q /usr/local/ispconfig/server/cron_daily.php - -if [ -f /usr/local/ispconfig/server/cron_daily_billing.sh ]; then - /usr/local/ispconfig/server/cron_daily_billing.sh -fi +echo "This script is no longer used. Use the cron.sh instead." diff --git a/server/lib/classes/cron.d/100-mailbox_stats.inc.php b/server/lib/classes/cron.d/100-mailbox_stats.inc.php new file mode 100644 index 0000000000..ed43e4e574 --- /dev/null +++ b/server/lib/classes/cron.d/100-mailbox_stats.inc.php @@ -0,0 +1,269 @@ +db->queryAllRecords($sql); + if(count($records) > 0) $parse_mail_log = true; + + foreach($records as $rec) { + if(@is_file($rec['maildir'].'/ispconfig_mailsize')) { + $parse_mail_log = false; + + // rename file + rename($rec['maildir'].'/ispconfig_mailsize',$rec['maildir'].'/ispconfig_mailsize_save'); + + // Read the file + $lines = file($rec['maildir'].'/ispconfig_mailsize_save'); + $mail_traffic = 0; + foreach($lines as $line) { + $mail_traffic += intval($line); + } + unset($lines); + + // Delete backup file + if(@is_file($rec['maildir'].'/ispconfig_mailsize_save')) unlink($rec['maildir'].'/ispconfig_mailsize_save'); + + // Save the traffic stats in the sql database + $tstamp = date('Y-m'); + + $sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id']; + $tr = $app->dbmaster->queryOneRecord($sql); + + $mail_traffic += $tr['traffic']; + if($tr['traffic_id'] > 0) { + $sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id']; + } else { + $sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)"; + } + $app->dbmaster->query($sql); + //echo $sql; + + } + + } + + if($parse_mail_log == true) { + $mailbox_traffic = array(); + $mail_boxes = array(); + $mail_rewrites = array(); // we need to read all mail aliases and forwards because the address in amavis is not always the mailbox address + + function parse_mail_log_line($line) { + //Oct 31 17:35:48 mx01 amavis[32014]: (32014-05) Passed CLEAN, [IPv6:xxxxx] [IPv6:xxxxx] -> , Message-ID: , mail_id: xxxxxx, Hits: -1.89, size: 1591, queued_as: xxxxxxx, 946 ms + + if(preg_match('/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+[^ ]+\s+amavis.* <([^>]+)>\s+->\s+((<[^>]+>,)+) .*Message-ID:\s+<([^>]+)>.* size:\s+(\d+),.*$/', $line, $matches) == false) return false; + + $timestamp = strtotime($matches[1]); + if(!$timestamp) return false; + + $to = array(); + $recipients = explode(',', $matches[3]); + foreach($recipients as $recipient) { + $recipient = substr($recipient, 1, -1); + if(!$recipient || $recipient == $matches[2]) continue; + $to[] = $recipient; + } + + return array('line' => $line, 'timestamp' => $timestamp, 'size' => $matches[6], 'from' => $matches[2], 'to' => $to, 'message-id' => $matches[5]); + } + + function add_mailbox_traffic(&$traffic_array, $address, $traffic) { + global $mail_boxes, $mail_rewrites; + + $address = strtolower($address); + + if(in_array($address, $mail_boxes) == true) { + if(!isset($traffic_array[$address])) $traffic_array[$address] = 0; + $traffic_array[$address] += $traffic; + } elseif(array_key_exists($address, $mail_rewrites)) { + foreach($mail_rewrites[$address] as $address) { + if(!isset($traffic_array[$address])) $traffic_array[$address] = 0; + $traffic_array[$address] += $traffic; + } + } else { + // this is not a local address - skip it + } + } + + $sql = "SELECT email FROM mail_user WHERE server_id = ".$conf['server_id']; + $records = $app->db->queryAllRecords($sql); + foreach($records as $record) { + $mail_boxes[] = $record['email']; + } + $sql = "SELECT source, destination FROM mail_forwarding WHERE server_id = ".$conf['server_id']; + $records = $app->db->queryAllRecords($sql); + foreach($records as $record) { + $targets = preg_split('/[\n,]+/', $record['destination']); + foreach($targets as $target) { + if(in_array($target, $mail_boxes)) { + if(isset($mail_rewrites[$record['source']])) $mail_rewrites[$record['source']][] = $target; + else $mail_rewrites[$record['source']] = array($target); + } + } + } + + $state_file = dirname(__FILE__) . '/mail_log_parser.state'; + $prev_line = false; + $last_line = false; + $cur_line = false; + + if(file_exists($state_file)) { + $prev_line = parse_mail_log_line(trim(file_get_contents($state_file))); + //if($prev_line) echo "continuing from previous run, log position: " . $prev_line['message-id'] . " at " . strftime('%d.%m.%Y %H:%M:%S', $prev_line['timestamp']) . "\n"; + } + + if(file_exists('/var/log/mail.log')) { + $fp = fopen('/var/log/mail.log', 'r'); + //echo "Parsing mail.log...\n"; + $l = 0; + while($line = fgets($fp, 8192)) { + $l++; + //if($l % 1000 == 0) echo "\rline $l"; + $cur_line = parse_mail_log_line($line); + if(!$cur_line) continue; + + if($prev_line) { + // check if this line has to be processed + if($cur_line['timestamp'] < $prev_line['timestamp']) { + $parse_mail_log = false; // we do not need to parse the second file! + continue; // already processed + } elseif($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) { + $parse_mail_log = false; // we do not need to parse the second file! + $prev_line = false; // this line has already been processed but the next one has to be! + continue; + } + } + + add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']); + foreach($cur_line['to'] as $to) { + add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']); + } + $last_line = $line; // store for the state file + } + fclose($fp); + //echo "\n"; + } + + if($parse_mail_log == true && file_exists('/var/log/mail.log.1')) { + $fp = fopen('/var/log/mail.log.1', 'r'); + //echo "Parsing mail.log.1...\n"; + $l = 0; + while($line = fgets($fp, 8192)) { + $l++; + //if($l % 1000 == 0) echo "\rline $l"; + $cur_line = parse_mail_log_line($line); + if(!$cur_line) continue; + + if($prev_line) { + // check if this line has to be processed + if($cur_line['timestamp'] < $prev_line['timestamp']) continue; // already processed + if($cur_line['timestamp'] == $prev_line['timestamp'] && $cur_line['message-id'] == $prev_line['message-id']) { + $prev_line = false; // this line has already been processed but the next one has to be! + continue; + } + } + + add_mailbox_traffic($mailbox_traffic, $cur_line['from'], $cur_line['size']); + foreach($cur_line['to'] as $to) { + add_mailbox_traffic($mailbox_traffic, $to, $cur_line['size']); + } + } + fclose($fp); + //echo "\n"; + } + unset($mail_rewrites); + unset($mail_boxes); + + // Save the traffic stats in the sql database + $tstamp = date('Y-m'); + $sql = "SELECT mailuser_id,email FROM mail_user WHERE server_id = ".$conf['server_id']; + $records = $app->db->queryAllRecords($sql); + foreach($records as $rec) { + if(array_key_exists($rec['email'], $mailbox_traffic)) { + $sql = "SELECT * FROM mail_traffic WHERE month = '$tstamp' AND mailuser_id = ".$rec['mailuser_id']; + $tr = $app->dbmaster->queryOneRecord($sql); + + $mail_traffic = $tr['traffic'] + $mailbox_traffic[$rec['email']]; + if($tr['traffic_id'] > 0) { + $sql = "UPDATE mail_traffic SET traffic = $mail_traffic WHERE traffic_id = ".$tr['traffic_id']; + } else { + $sql = "INSERT INTO mail_traffic (month,mailuser_id,traffic) VALUES ('$tstamp',".$rec['mailuser_id'].",$mail_traffic)"; + } + $app->dbmaster->query($sql); + //echo $sql; + } + } + + unset($mailbox_traffic); + if($last_line) file_put_contents($state_file, $last_line); + } + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_clamav_log.inc.php b/server/lib/classes/cron.d/100-monitor_clamav_log.inc.php new file mode 100644 index 0000000000..fc28bfbea1 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_clamav_log.inc.php @@ -0,0 +1,179 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'log_clamav'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + // Todo: the state should be calculated. + $state = 'ok'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + + /** The type of the data */ + $type = 'log_freshclam'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* Get the data from the LAST log-Entry. + * if there can be found: + * WARNING: Your ClamAV installation is OUTDATED! + * then the clamav is outdated. This is a warning! + */ + $state = 'ok'; + + $tmp = explode("\n", $data); + $lastLog = array(); + if ($tmp[sizeof($tmp) - 1] == '') { + /* the log ends with an empty line remove this */ + array_pop($tmp); + } + if (strpos($tmp[sizeof($tmp) - 1], '-------------') !== false) { + /* the log ends with "-----..." remove this */ + array_pop($tmp); + } + for ($i = sizeof($tmp) - 1; $i > 0; $i--) { + if (strpos($tmp[$i], '---------') === false) { + /* no delimiter found, so add this to the last-log */ + $lastLog[] = $tmp[$i]; + } else { + /* delimiter found, so there is no more line left! */ + break; + } + } + + /* + * Now we have the last log in the array. + * Check if the outdated-string is found... + */ + foreach ($lastLog as $line) { + if (strpos(strtolower($line), 'outdated') !== false) { + /* + * Outdatet is only info, because if we set this to warning, the server is + * as long in state warning, as there is a new version of ClamAv which takes + * sometimes weeks! + */ + $state = $this->_tools->_setState($state, 'info'); + } + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_cpu.inc.php b/server/lib/classes/cron.d/100-monitor_cpu.inc.php new file mode 100644 index 0000000000..b75239bb22 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_cpu.inc.php @@ -0,0 +1,136 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'cpu_info'; + + /* + Fetch the data into a array + */ + if (file_exists('/proc/cpuinfo')) { + $cpuData = shell_exec('cat /proc/cpuinfo'); + $cpuInfo = explode("\n", $cpuData); + $processor = 0; + + foreach ($cpuInfo as $line) { + + $part = preg_split('/:/', $line); + $key = trim($part[0]); + $value = trim($part[1]); + if ($key == 'processor') + $processor = intval($value); + if ($key != '') + $data[$key . ' ' . $processor] = $value; + } + + /* the cpu has no state. It is, what it is */ + $state = 'no_state'; + } else { + /* + * It is not Linux, so there is no data and no state + * + * no_state, NOT unknown, because "unknown" is shown as state + * inside the GUI. no_state is hidden. + * + * We have to write NO DATA inside the DB, because the GUI + * could not know, if there is any dat, or not... + */ + $state = 'no_state'; + $data['output'] = ''; + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_disk_usage.inc.php b/server/lib/classes/cron.d/100-monitor_disk_usage.inc.php new file mode 100644 index 0000000000..706be3d7ec --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_disk_usage.inc.php @@ -0,0 +1,166 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'disk_usage'; + + /** The state of the disk-usage */ + $state = 'ok'; + + /** Fetch the data of ALL devices into a array (needed for monitoring!) */ + //$dfData = shell_exec('df -hT 2>/dev/null'); + $app->uses('getconf'); + $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); + $dfData = shell_exec('df -hT|grep -v "'.$web_config['website_basedir'].'/" 2>/dev/null'); + + // split into array + $df = explode("\n", $dfData); + + /* + * ignore the first line, process the rest + */ + for ($i = 1; $i <= sizeof($df); $i++) { + if ($df[$i] != '') { + /* + * Make an array of the data + */ + $s = preg_split('/[\s]+/', $df[$i]); + $data[$i]['fs'] = $s[0]; + $data[$i]['type'] = $s[1]; + $data[$i]['size'] = $s[2]; + $data[$i]['used'] = $s[3]; + $data[$i]['available'] = $s[4]; + $data[$i]['percent'] = $s[5]; + $data[$i]['mounted'] = $s[6]; + /* + * calculate the state + */ + $usePercent = floatval($data[$i]['percent']); + + //* get the free memsize + if(substr($data[$i]['available'],-1) == 'G') { + $freesize = floatval($data[$i]['available'])*1024; + } elseif(substr($data[$i]['available'],-1) == 'T') { + $freesize = floatval($data[$i]['available'])*1024*1024; + } else { + $freesize = floatval($data[$i]['available']); + } + + //* We don't want to check some filesystem which have no sensible filling levels + switch ($data[$i]['type']) { + case 'iso9660': + case 'cramfs': + case 'udf': + case 'tmpfs': + case 'devtmpfs': + case 'udev': + break; + default: + if ($usePercent > 75 && $freesize < 2000) + $state = $this->_tools->_setState($state, 'info'); + if ($usePercent > 80 && $freesize < 1000) + $state = $this->_tools->_setState($state, 'warning'); + if ($usePercent > 90 && $freesize < 500) + $state = $this->_tools->_setState($state, 'critical'); + if ($usePercent > 95 && $freesize < 100) + $state = $this->_tools->_setState($state, 'error'); + break; + } + } + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_email_quota.inc.php b/server/lib/classes/cron.d/100-monitor_email_quota.inc.php new file mode 100644 index 0000000000..12bd3fed77 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_email_quota.inc.php @@ -0,0 +1,149 @@ +uses('getconf'); + $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail'); + if($mail_config['mailbox_quota_stats'] == 'n') return; + + /* used for all monitor cronjobs */ + $app->load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + + //* Initialize data array + $data = array(); + + //* the id of the server as int + $server_id = intval($conf['server_id']); + + //* The type of the data + $type = 'email_quota'; + + //* The state of the email_quota. + $state = 'ok'; + + $mailboxes = $app->db->queryAllRecords("SELECT email,maildir FROM mail_user WHERE server_id = $server_id"); + if(is_array($mailboxes)) { + foreach($mailboxes as $mb) { + $email = $mb['email']; + $email_parts = explode('@',$mb['email']); + $filename = $mb['maildir'].'/.quotausage'; + if(file_exists($filename) && !is_link($filename)) { + $quotafile = file($filename); + $data[$email]['used'] = trim($quotafile['1']); + unset($quotafile); + } else { + exec('du -s '.escapeshellcmd($mb['maildir']),$out); + $parts = explode(' ',$out[0]); + $data[$email]['used'] = intval($parts[0])*1024; + unset($out); + unset($parts); + } + } + } + + unset($mailboxes); + + //* Dovecot quota check Courier in progress lathama@gmail.com + /* + if($dir = opendir("/var/vmail")){ + while (($quotafiles = readdir($dir)) !== false){ + if(preg_match('/.\_quota$/', $quotafiles)){ + $quotafile = (file("/var/vmail/" . $quotafiles)); + $emailaddress = preg_replace('/_quota/',"", $quotafiles); + $emailaddress = preg_replace('/_/',"@", $emailaddress); + $data[$emailaddress]['used'] = trim($quotafile['1']); + } + } + closedir($dir); + } + */ + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_fail2ban.inc.php b/server/lib/classes/cron.d/100-monitor_fail2ban.inc.php new file mode 100644 index 0000000000..6c77a07626 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_fail2ban.inc.php @@ -0,0 +1,127 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'log_fail2ban'; + + /* This monitoring is only available if fail2ban is installed */ + system('which fail2ban-client', $retval); // Debian, Ubuntu, Fedora + if ($retval !== 0) + system('which fail2ban', $retval); // CentOS + if ($retval === 0) { + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* + * At this moment, there is no state (maybe later) + */ + $state = 'no_state'; + } else { + /* + * fail2ban is not installed, so there is no data and no state + * + * no_state, NOT unknown, because "unknown" is shown as state + * inside the GUI. no_state is hidden. + * + * We have to write NO DATA inside the DB, because the GUI + * could not know, if there is any dat, or not... + */ + $state = 'no_state'; + $data = ''; + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_hd_quota.inc.php b/server/lib/classes/cron.d/100-monitor_hd_quota.inc.php new file mode 100644 index 0000000000..14f00d4c75 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_hd_quota.inc.php @@ -0,0 +1,162 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + //* Initialize data array + $data = array(); + + //* the id of the server as int + $server_id = intval($conf['server_id']); + + //* The type of the data + $type = 'harddisk_quota'; + + //* The state of the harddisk_quota. + $state = 'ok'; + + //* Fetch the data for all users + $dfData = shell_exec('repquota -au 2>/dev/null'); + + //* Split into array + $df = explode("\n", $dfData); + + //* ignore the first 5 lines, process the rest + for ($i = 5; $i <= sizeof($df); $i++) { + if ($df[$i] != '') { + //* Make a array of the data + $s = preg_split('/[\s]+/', $df[$i]); + $username = $s[0]; + if (substr($username, 0, 3) == 'web') { + if (isset($data['user'][$username])) { + $data['user'][$username]['used'] += $s[2]; + $data['user'][$username]['soft'] += $s[3]; + $data['user'][$username]['hard'] += $s[4]; + $data['user'][$username]['files'] += $s[5]; + } else { + $data['user'][$username]['used'] = $s[2]; + $data['user'][$username]['soft'] = $s[3]; + $data['user'][$username]['hard'] = $s[4]; + $data['user'][$username]['files'] = $s[5]; + } + } + } + } + + //** Fetch the data for all users + $dfData = shell_exec('repquota -ag 2>/dev/null'); + + //* split into array + $df = explode("\n", $dfData); + + //* ignore the first 5 lines, process the rest + for ($i = 5; $i <= sizeof($df); $i++) { + if ($df[$i] != '') { + //* Make a array of the data + $s = preg_split('/[\s]+/', $df[$i]); + $groupname = $s[0]; + if (substr($groupname, 0, 6) == 'client') { + if (isset($data['group'][$groupname])) { + $data['group'][$groupname]['used'] += $s[1]; + $data['group'][$groupname]['soft'] += $s[2]; + $data['group'][$groupname]['hard'] += $s[3]; + } else { + $data['group'][$groupname]['used'] = $s[1]; + $data['group'][$groupname]['soft'] = $s[2]; + $data['group'][$groupname]['hard'] = $s[3]; + } + } + } + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_iptables.inc.php b/server/lib/classes/cron.d/100-monitor_iptables.inc.php new file mode 100644 index 0000000000..3b25e4c7ce --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_iptables.inc.php @@ -0,0 +1,132 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'iptables_rules'; + + /* This monitoring is only available if fail2ban is installed */ + system('which iptables', $retval); // Debian, Ubuntu, Fedora + if ($retval === 0) { + /* Get the data of the log */ + $data['output'] = '

iptables -S (ipv4)

'.shell_exec('iptables -S 2>/dev/null'); + + /* + * At this moment, there is no state (maybe later) + */ + $state = 'no_state'; + } else { + $state = 'no_state'; + $data = ''; + } + + + /* This monitoring is only available if fail2ban is installed */ + system('which ip6tables', $retval); // Debian, Ubuntu, Fedora + if ($retval === 0) { + /* Get the data of the log */ + $data['output'] .= '

ip6tables -S (ipv6)

'.shell_exec('ip6tables -S 2>/dev/null'); + + /* + * At this moment, there is no state (maybe later) + */ + $state = 'no_state'; + } else { + $state = 'no_state'; + $data = ''; + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_ispconfig_log.inc.php b/server/lib/classes/cron.d/100-monitor_ispconfig_log.inc.php new file mode 100644 index 0000000000..50674c4e20 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_ispconfig_log.inc.php @@ -0,0 +1,146 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'log_ispconfig'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + // Todo: the state should be calculated. + $state = 'ok'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + + /** The type of the data */ + $type = 'log_ispc_cron'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* + * actually this info has no state. + * maybe someone knows better...???... + */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + //* Ensure that output is encoded so that it does not break the serialize + if(is_array($res) && isset($res['data'])) $res['data'] = htmlentities($res['data']); + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_ispconfig_version.inc.php b/server/lib/classes/cron.d/100-monitor_ispconfig_version.inc.php new file mode 100644 index 0000000000..7f4688ced5 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_ispconfig_version.inc.php @@ -0,0 +1,110 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'ispc_info'; + + /* + Fetch the data into a array + */ + $data['name'] = ISPC_APP_TITLE; + $data['version'] = ISPC_APP_VERSION; + + /* the ISPC-Version has no state. It is, what it is */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_mail_log.inc.php b/server/lib/classes/cron.d/100-monitor_mail_log.inc.php new file mode 100644 index 0000000000..34194a712f --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_mail_log.inc.php @@ -0,0 +1,181 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'log_mail'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* + * actually this info has no state. + * maybe someone knows better...???... + */ + $state = 'no_state'; + + /* + * Return the Result + */ + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + /** The type of the data */ + $type = 'log_mail_warn'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* + * actually this info has no state. + * maybe someone knows better...???... + */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + /** The type of the data */ + $type = 'log_mail_err'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* + * actually this info has no state. + * maybe someone knows better...???... + */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_mail_queue.inc.php b/server/lib/classes/cron.d/100-monitor_mail_queue.inc.php new file mode 100644 index 0000000000..bda9031391 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_mail_queue.inc.php @@ -0,0 +1,138 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'mailq'; + + /* Get the data from the mailq */ + $data['output'] = shell_exec('mailq'); + + /* + * The last line has more informations + */ + $tmp = explode("\n", $data['output']); + $more = $tmp[sizeof($tmp) - 1]; + $res = $this->_getIntArray($more); + $data['bytes'] = $res[0]; + $data['requests'] = $res[1]; + + /** The state of the mailq. */ + $state = 'ok'; + if ($data['requests'] > 2000) + $state = 'info'; + if ($data['requests'] > 5000) + $state = 'warning'; + if ($data['requests'] > 8000) + $state = 'critical'; + if ($data['requests'] > 10000) + $state = 'error'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_mem_usage.inc.php b/server/lib/classes/cron.d/100-monitor_mem_usage.inc.php new file mode 100644 index 0000000000..91e3d410a8 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_mem_usage.inc.php @@ -0,0 +1,124 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'mem_usage'; + + /* + Fetch the data into a array + */ + $miData = shell_exec('cat /proc/meminfo'); + + $memInfo = explode("\n", $miData); + + foreach ($memInfo as $line) { + $part = preg_split('/:/', $line); + $key = trim($part[0]); + $tmp = explode(' ', trim($part[1])); + $value = 0; + if ($tmp[1] == 'kB') + $value = $tmp[0] * 1024; + $data[$key] = $value; + } + + /* + * actually this info has no state. + * maybe someone knows better...???... + */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_mongodb.inc.php b/server/lib/classes/cron.d/100-monitor_mongodb.inc.php new file mode 100644 index 0000000000..a3d19c9679 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_mongodb.inc.php @@ -0,0 +1,127 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'log_mongodb'; + + /* This monitoring is only available if MongoDB is installed */ + system('which mongod', $retval); // Debian, Ubuntu, Fedora + if ($retval !== 0) + system('which mongod', $retval); // CentOS + if ($retval === 0) { + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* + * At this moment, there is no state (maybe later) + */ + $state = 'no_state'; + } else { + /* + * MongoDB is not installed, so there is no data and no state + * + * no_state, NOT unknown, because "unknown" is shown as state + * inside the GUI. no_state is hidden. + * + * We have to write NO DATA inside the DB, because the GUI + * could not know, if there is any dat, or not... + */ + $state = 'no_state'; + $data = ''; + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_openvz.inc.php b/server/lib/classes/cron.d/100-monitor_openvz.inc.php new file mode 100644 index 0000000000..2abe6ccd21 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_openvz.inc.php @@ -0,0 +1,183 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'openvz_veinfo'; + + /* + Fetch the data into a array + */ + $app->load(openvz_tools); + $openVzTools = new openvz_tools(); + $data = $openVzTools->getOpenVzVeInfo(); + + /* the VE-Info has no state. It is, what it is */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + /** The type of the data */ + $type = 'openvz_beancounter'; + + /* + Fetch the data into a array + */ + $app->load(openvz_tools); + $openVzTools = new openvz_tools(); + $data = $openVzTools->getOpenVzVeBeanCounter(); + + /* calculate the state of the beancounter */ + if ($data == '') { + $state = 'no_state'; + } else { + $state = 'ok'; + + /* transfer this output-string into a array */ + $test = explode("\n", $data); + + /* the first list of the output is not needed */ + array_shift($test); + + /* now process all items of the rest */ + foreach ($test as $item) { + /* + * eliminate all doubled spaces and spaces at the beginning and end + */ + while (strpos($item, ' ') !== false) { + $item = str_replace(' ', ' ', $item); + } + $item = trim($item); + + /* + * The failcounter is the LAST + */ + if ($item != '') { + $tmp = explode(' ', $item); + $failCounter = $tmp[sizeof($tmp) - 1]; + if ($failCounter > 0) + $state = 'info'; + if ($failCounter > 50) + $state = 'warning'; + if ($failCounter > 200) + $state = 'critical'; + if ($failCounter > 10000) + $state = 'error'; + } + } + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_os_version.inc.php b/server/lib/classes/cron.d/100-monitor_os_version.inc.php new file mode 100644 index 0000000000..a5f213e141 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_os_version.inc.php @@ -0,0 +1,112 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = $app->functions->intval($conf['server_id']); + + /** The type of the data */ + $type = 'os_info'; + + /* + Fetch the data into a array + */ + $dist = $this->_tools->get_distname(); + + $data['name'] = $dist['name']; + $data['version'] = $dist['version']; + + /* the OS has no state. It is, what it is */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_raid.inc.php b/server/lib/classes/cron.d/100-monitor_raid.inc.php new file mode 100644 index 0000000000..969ff24649 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_raid.inc.php @@ -0,0 +1,263 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'raid_state'; + + /* + * We support several RAID types, but if we can't find any of them, we have no data + */ + $state = 'no_state'; + $data['output'] = ''; + + /* + * Check, if Software-RAID is enabled + */ + if (file_exists('/proc/mdstat')) { + /* + * Fetch the output + */ + $data['output'] = shell_exec('cat /proc/mdstat'); + + /* + * Then calc the state. + */ + $tmp = explode("\n", $data['output']); + $state = 'ok'; + for ($i = 0; $i < sizeof($tmp); $i++) { + /* fetch the next line */ + $line = $tmp[$i]; + + if ((strpos($line, '[U_]') !== false) || (strpos($line, '[_U]') !== false)) { + /* One Disk is not working. + * if the next line starts with "[>" or "[=" then + * recovery (resync) is in state and the state is + * information instead of critical + */ + $nextLine = $tmp[$i + 1]; + if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) { + $state = $this->_tools->_setState($state, 'critical'); + } else { + $state = $this->_tools->_setState($state, 'info'); + } + } + if (strpos($line, '[__]') !== false) { + /* both Disk are not working */ + $state = $this->_tools->_setState($state, 'error'); + } + if (strpos($line, '[UU]') !== false) { + /* The disks are OK. + * if the next line starts with "[>" or "[=" then + * recovery (resync) is in state and the state is + * information instead of ok + */ + $nextLine = $tmp[$i + 1]; + if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) { + $state = $this->_tools->_setState($state, 'ok'); + } else { + $state = $this->_tools->_setState($state, 'info'); + } + } + } + } + /* + * Check, if we have mpt-status installed (LSIsoftware-raid) + */ + if (file_exists('/proc/mpt/summary')) { + system('which mpt-status', $retval); + if ($retval === 0) { + /* + * Fetch the output + */ + $data['output'] = shell_exec('mpt-status --autoload'); + + /* + * Then calc the state. + */ + $state = 'ok'; + if(is_array($data['output'])) { + foreach ($data['output'] as $item) { + /* + * The output contains information for every RAID and every HDD. + * We only need the state of the RAID + */ + if (strpos($item, 'state ') !== false) { + /* + * We found a raid, process the state of it + */ + if (strpos($item, ' ONLINE ') !== false) { + $this->_tools->_setState($state, 'ok'); + } elseif (strpos($item, ' OPTIMAL ') !== false) { + $this->_tools->_setState($state, 'ok'); + } elseif (strpos($item, ' INITIAL ') !== false) { + $this->_tools->_setState($state, 'info'); + } elseif (strpos($item, ' INACTIVE ') !== false) { + $this->_tools->_setState($state, 'critical'); + } elseif (strpos($item, ' RESYNC ') !== false) { + $this->_tools->_setState($state, 'info'); + } elseif (strpos($item, ' DEGRADED ') !== false) { + $this->_tools->_setState($state, 'critical'); + } else { + /* we don't know the state. so we set the state to critical, that the + * admin is warned, that something is wrong + */ + $this->_tools->_setState($state, 'critical'); + } + } + } + } + } + } + + /* + * 3ware Controller + */ + system('which tw_cli', $retval); + if($retval === 0) { + + $data['output'] = shell_exec('tw_cli info c0'); + + $state = 'ok'; + if(is_array($data['output'])) { + foreach ($data['output'] as $item) { + if (strpos($item, 'RAID') !== false) { + if (strpos($item, ' VERIFYING ') !== false) { + $this->_tools->_setState($state, 'info'); + } + else if (strpos($item, ' MIGRATE-PAUSED ') !== false) { + $this->_tools->_setState($state, 'info'); + } + else if (strpos($item, ' MIGRATING ') !== false) { + $this->_tools->_setState($state, 'ok'); + } + else if (strpos($item, ' INITIALIZING ') !== false) { + $this->_tools->_setState($state, 'info'); + } + else if (strpos($item, ' INIT-PAUSED ') !== false) { + $this->_tools->_setState($state, 'info'); + } + else if (strpos($item, ' REBUILDING ') !== false) { + $this->_tools->_setState($state, 'info'); + } + else if (strpos($item, ' REBUILD-PAUSED ') !== false) { + $this->_tools->_setState($state, 'warning'); + } + else if (strpos($item, ' RECOVERY ') !== false) { + $this->_tools->_setState($state, 'warning'); + } + else if (strpos($item, ' DEGRADED ') !== false) { + $this->_tools->_setState($state, 'critical'); + } + else if (strpos($item, ' UNKNOWN ') !== false) { + $this->_tools->_setState($state, 'critical'); + } + else if (strpos($item, ' OK ') !== false) { + $this->_tools->_setState($state, 'ok'); + } + else if (strpos($item, ' OPTIMAL ') !== false) { + $this->_tools->_setState($state, 'ok'); + } + else { + $this->_tools->_setState($state, 'critical'); + } + } + } + } + } + + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_rkhunter.inc.php b/server/lib/classes/cron.d/100-monitor_rkhunter.inc.php new file mode 100644 index 0000000000..ba992dacfc --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_rkhunter.inc.php @@ -0,0 +1,127 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'rkhunter'; + + /* This monitoring is only available if rkhunter is installed */ + system('which rkhunter', $retval); + if ($retval === 0) { + /* + * Fetch the output + */ + $data['output'] = shell_exec('rkhunter --update --checkall --nocolors --skip-keypress'); + + /* + * At this moment, there is no state (maybe later) + */ + $state = 'no_state'; + } else { + /* + * rkhunter is not installed, so there is no data and no state + * + * no_state, NOT unknown, because "unknown" is shown as state + * inside the GUI. no_state is hidden. + * + * We have to write NO DATA inside the DB, because the GUI + * could not know, if there is any dat, or not... + */ + $state = 'no_state'; + $data['output'] = ''; + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_server.inc.php b/server/lib/classes/cron.d/100-monitor_server.inc.php new file mode 100644 index 0000000000..b732578301 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_server.inc.php @@ -0,0 +1,133 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'server_load'; + + /* + Fetch the data into a array + */ + $procUptime = shell_exec("cat /proc/uptime | cut -f1 -d' '"); + $data['up_days'] = floor($procUptime / 86400); + $data['up_hours'] = floor(($procUptime - $data['up_days'] * 86400) / 3600); + $data['up_minutes'] = floor(($procUptime - $data['up_days'] * 86400 - $data['up_hours'] * 3600) / 60); + + $data['uptime'] = shell_exec('uptime'); + + $tmp = explode(',', $data['uptime'], 4); + $tmpUser = explode(' ', trim($tmp[2])); + $data['user_online'] = intval($tmpUser[0]); + + //* New Load Average code to fix "always zero" bug in non-english distros. NEEDS TESTING + $loadTmp = shell_exec("cat /proc/loadavg | cut -f1-3 -d' '"); + $load = explode(' ', $loadTmp); + $data['load_1'] = floatval(str_replace(',', '.', $load[0])); + $data['load_5'] = floatval(str_replace(',', '.', $load[1])); + $data['load_15'] = floatval(str_replace(',', '.', $load[2])); + + /** The state of the server-load. */ + $state = 'ok'; + if ($data['load_1'] > 20) + $state = 'info'; + if ($data['load_1'] > 50) + $state = 'warning'; + if ($data['load_1'] > 100) + $state = 'critical'; + if ($data['load_1'] > 150) + $state = 'error'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_services.inc.php b/server/lib/classes/cron.d/100-monitor_services.inc.php new file mode 100644 index 0000000000..f3e9e72f2d --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_services.inc.php @@ -0,0 +1,94 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* + * First we get the Monitoring-data from the tools + */ + $res = $this->_tools->monitorServices(); + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_syslog.inc.php b/server/lib/classes/cron.d/100-monitor_syslog.inc.php new file mode 100644 index 0000000000..8aa8745198 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_syslog.inc.php @@ -0,0 +1,153 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'sys_log'; + + /* + * is there any warning or error for this server? + */ + $state = 'ok'; + $dbData = $app->dbmaster->queryAllRecords('SELECT loglevel FROM sys_log WHERE server_id = ' . $server_id . ' AND loglevel > 0'); + if (is_array($dbData)) { + foreach ($dbData as $item) { + if ($item['loglevel'] == 1) + $state = $this->_tools->_setState($state, 'warning'); + if ($item['loglevel'] == 2) + $state = $this->_tools->_setState($state, 'error'); + } + } + + /** There is no monitor-data because the data is in the sys_log table */ + $data['output'] = ''; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + /** The type of the data */ + $type = 'log_messages'; + + /* Get the data of the log */ + $data = $this->_tools->_getLogData($type); + + /* + * actually this info has no state. + * maybe someone knows better...???... + */ + $state = 'no_state'; + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/100-monitor_system_update.inc.php b/server/lib/classes/cron.d/100-monitor_system_update.inc.php new file mode 100644 index 0000000000..022d667154 --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_system_update.inc.php @@ -0,0 +1,208 @@ +load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + $type = 'system_update'; + + /* This monitoring is only available on Debian or Ubuntu */ + if (file_exists('/etc/debian_version')) { + + /* + * first update the "apt database" + */ + shell_exec('apt-get update'); + + /* + * Then test the upgrade. + * if there is any output, then there is a needed update + */ + $aptData = shell_exec('apt-get -s -qq dist-upgrade'); + if ($aptData == '') { + /* There is nothing to update! */ + $state = 'ok'; + } else { + /* + * There is something to update! this is in most cases not critical, so we can + * do a system-update once a month or so... + */ + $state = 'info'; + } + + /* + * Fetch the output + */ + $data['output'] = $aptData; + } elseif (file_exists('/etc/gentoo-release')) { + + /* + * first update the portage tree + */ + + // In keeping with gentoo's rsync policy, don't update to frequently (every four hours - taken from http://www.gentoo.org/doc/en/source_mirrors.xml) + $do_update = true; + if (file_exists('/usr/portage/metadata/timestamp.chk')) { + $datetime = file_get_contents('/usr/portage/metadata/timestamp.chk'); + $datetime = trim($datetime); + + $dstamp = strtotime($datetime); + if ($dstamp) { + $checkat = $dstamp + 14400; // + 4hours + if (mktime() < $checkat) { + $do_update = false; + } + } + } + + if ($do_update) { + shell_exec('emerge --sync --quiet'); + } + + /* + * Then test the upgrade. + * if there is any output, then there is a needed update + */ + $emergeData = shell_exec('glsa-check -t affected'); + if ($emergeData == '') { + /* There is nothing to update! */ + $state = 'ok'; + $data['output'] = 'No unapplied GLSA\'s found on the system.'; + } else { + /* There is something to update! */ + $state = 'info'; + $data['output'] = shell_exec('glsa-check -pv --nocolor affected 2>/dev/null'); + } + } elseif (file_exists('/etc/SuSE-release')) { + + /* + * update and find the upgrade. + * if there is any output, then there is a needed update + */ + $aptData = shell_exec('zypper -q lu'); + if ($aptData == '') { + /* There is nothing to update! */ + $state = 'ok'; + } else { + /* + * There is something to update! this is in most cases not critical, so we can + * do a system-update once a month or so... + */ + $state = 'info'; + } + + /* + * Fetch the output + */ + $data['output'] = shell_exec('zypper lu'); + } else { + /* + * It is not Debian/Ubuntu, so there is no data and no state + * + * no_state, NOT unknown, because "unknown" is shown as state + * inside the GUI. no_state is hidden. + * + * We have to write NO DATA inside the DB, because the GUI + * could not know, if there is any dat, or not... + */ + $state = 'no_state'; + $data['output'] = ''; + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + //* Ensure that output is encoded so that it does not break the serialize + //$res['data']['output'] = htmlentities($res['data']['output']); + $res['data']['output'] = htmlentities($res['data']['output'],ENT_QUOTES,'UTF-8'); + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (' . + $res['server_id'] . ', ' . + "'" . $app->dbmaster->quote($res['type']) . "', " . + 'UNIX_TIMESTAMP(), ' . + "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . + "'" . $res['state'] . "'" . + ')'; + $app->dbmaster->query($sql); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/150-awstats.inc.php b/server/lib/classes/cron.d/150-awstats.inc.php new file mode 100644 index 0000000000..0638f09738 --- /dev/null +++ b/server/lib/classes/cron.d/150-awstats.inc.php @@ -0,0 +1,183 @@ +db->queryAllRecords($sql); + + $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); + + foreach($records as $rec) { + //$yesterday = date('Ymd',time() - 86400); + $yesterday = date('Ymd',strtotime("-1 day", time())); + + $log_folder = 'log'; + if($rec['type'] == 'vhostsubdomain') { + $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id'])); + $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']); + if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id']; + $log_folder .= '/' . $subdomain_host; + unset($tmp); + } + $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log'); + if(!@is_file($logfile)) { + $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz'); + if(!@is_file($logfile)) { + continue; + } + } + $web_folder = ($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web'); + $domain = escapeshellcmd($rec['domain']); + $statsdir = escapeshellcmd($rec['document_root'].'/'.$web_folder.'/stats'); + $awstats_pl = $web_config['awstats_pl']; + $awstats_buildstaticpages_pl = $web_config['awstats_buildstaticpages_pl']; + + $awstats_conf_dir = $web_config['awstats_conf_dir']; + $awstats_website_conf_file = $web_config['awstats_conf_dir'].'/awstats.'.$domain.'.conf'; + + if(is_file($awstats_website_conf_file)) unlink($awstats_website_conf_file); + + $sql = "SELECT domain FROM web_domain WHERE (type = 'alias' OR type = 'subdomain') AND parent_domain_id = ".$rec['domain_id']; + $aliases = $app->db->queryAllRecords($sql); + $aliasdomain = ''; + + if(is_array($aliases)) { + foreach ($aliases as $alias) { + $aliasdomain.= ' '.$alias['domain']. ' www.'.$alias['domain']; + } + } + + if(!is_file($awstats_website_conf_file)) { + $awstats_conf_file_content = 'Include "'.$awstats_conf_dir.'/awstats.conf" + LogFile="/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log" + SiteDomain="'.$domain.'" + HostAliases="www.'.$domain.' localhost 127.0.0.1'.$aliasdomain.'"'; + file_put_contents($awstats_website_conf_file,$awstats_conf_file_content); + } + + if(!@is_dir($statsdir)) mkdir($statsdir); + if(is_link('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log')) unlink('/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log'); + symlink($logfile,'/var/log/ispconfig/httpd/'.$domain.'/yesterday-access.log'); + + $awmonth = date("n"); + $awyear = date("Y"); + + if (date("d") == 1) { + $awmonth = date("m")-1; + if (date("m") == 1) { + $awyear = date("Y")-1; + $awmonth = "12"; + } + } + + // awstats_buildstaticpages.pl -update -config=mydomain.com -lang=en -dir=/var/www/domain.com/'.$web_folder.'/stats -awstatsprog=/path/to/awstats.pl + // $command = "$awstats_buildstaticpages_pl -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'"; + + $command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang=".$conf['language']." -dir='$statsdir' -awstatsprog='$awstats_pl'"; + + if (date("d") == 2) { + $awmonth = date("m")-1; + if (date("m") == 1) { + $awyear = date("Y")-1; + $awmonth = "12"; + } + + $statsdirold = $statsdir."/".$awyear."-".$awmonth."/"; + mkdir($statsdirold); + $files = scandir($statsdir); + foreach ($files as $file) { + if (substr($file,0,1) != "." && !is_dir("$statsdir"."/"."$file") && substr($file,0,1) != "w" && substr($file,0,1) != "i") copy("$statsdir"."/"."$file","$statsdirold"."$file"); + } + } + + + if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) { + exec($command); + if(is_file($rec['document_root'].'/'.$web_folder.'/stats/index.html')) unlink($rec['document_root'].'/'.$web_folder.'/stats/index.html'); + rename($rec['document_root'].'/'.$web_folder.'/stats/awstats.'.$domain.'.html',$rec['document_root'].'/'.$web_folder.'/stats/awsindex.html'); + if(!is_file($rec['document_root']."/".$web_folder."/stats/index.php")) { + if(file_exists("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master")) { + copy("/usr/local/ispconfig/server/conf-custom/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php"); + } else { + copy("/usr/local/ispconfig/server/conf/awstats_index.php.master",$rec['document_root']."/".$web_folder."/stats/index.php"); + } + } + + $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG); + } else { + $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN); + } + + if(is_file($rec['document_root']."/".$web_folder."/stats/index.php")) { + chown($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_user']); + chgrp($rec['document_root']."/".$web_folder."/stats/index.php",$rec['system_group']); + } + + } + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/150-webalizer.inc.php b/server/lib/classes/cron.d/150-webalizer.inc.php new file mode 100644 index 0000000000..ba75b8b95a --- /dev/null +++ b/server/lib/classes/cron.d/150-webalizer.inc.php @@ -0,0 +1,142 @@ +db->queryAllRecords($sql); + + foreach($records as $rec) { + //$yesterday = date('Ymd',time() - 86400); + $yesterday = date('Ymd',strtotime("-1 day", time())); + + $log_folder = 'log'; + if($rec['type'] == 'vhostsubdomain') { + $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id'])); + $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']); + if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id']; + $log_folder .= '/' . $subdomain_host; + unset($tmp); + } + $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log'); + if(!@is_file($logfile)) { + $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log.gz'); + if(!@is_file($logfile)) { + continue; + } + } + + $domain = escapeshellcmd($rec['domain']); + $statsdir = escapeshellcmd($rec['document_root'].'/'.($rec['type'] == 'vhostsubdomain' ? $rec['web_folder'] : 'web').'/stats'); + $webalizer = '/usr/bin/webalizer'; + $webalizer_conf_main = '/etc/webalizer/webalizer.conf'; + $webalizer_conf = escapeshellcmd($rec['document_root'].'/log/webalizer.conf'); + + if(is_file($statsdir.'/index.php')) unlink($statsdir.'/index.php'); + + if(!@is_file($webalizer_conf)) { + copy($webalizer_conf_main,$webalizer_conf); + } + + if(@is_file($webalizer_conf)) { + setConfigVar($webalizer_conf, 'Incremental', 'yes'); + setConfigVar($webalizer_conf, 'IncrementalName', $statsdir.'/webalizer.current'); + setConfigVar($webalizer_conf, 'HistoryName', $statsdir.'/webalizer.hist'); + } + + + if(!@is_dir($statsdir)) mkdir($statsdir); + exec("$webalizer -c $webalizer_conf -n $domain -s $domain -r $domain -q -T -p -o $statsdir $logfile"); + } + + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/200-logfiles.inc.php b/server/lib/classes/cron.d/200-logfiles.inc.php new file mode 100644 index 0000000000..862f0f4ef3 --- /dev/null +++ b/server/lib/classes/cron.d/200-logfiles.inc.php @@ -0,0 +1,271 @@ +db->queryAllRecords($sql); + foreach($records as $rec) { + + //* create traffic statistics based on yesterdays access log file + $yesterday = date('Ymd',time() - 86400); + + $log_folder = 'log'; + if($rec['type'] == 'vhostsubdomain') { + $tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($rec['parent_domain_id'])); + $subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $rec['domain']); + if($subdomain_host == '') $subdomain_host = 'web'.$rec['domain_id']; + $log_folder .= '/' . $subdomain_host; + unset($tmp); + } + + $logfile = $rec['document_root'].'/' . $log_folder . '/'.$yesterday.'-access.log'; + $total_bytes = 0; + + $handle = @fopen($logfile, "r"); + if ($handle) { + while (($line = fgets($handle, 4096)) !== false) { + if (preg_match('/^\S+ \S+ \S+ \[.*?\] "\S+.*?" \d+ (\d+) ".*?" ".*?"/', $line, $m)) { + $total_bytes += intval($m[1]); + } + } + + //* Insert / update traffic in master database + $traffic_date = date('Y-m-d',time() - 86400); + $tmp = $app->dbmaster->queryOneRecord("select hostname from web_traffic where hostname='".$rec['domain']."' and traffic_date='".$traffic_date."'"); + if(is_array($tmp) && count($tmp) > 0) { + $sql = "update web_traffic set traffic_bytes=traffic_bytes+" + . $total_bytes + . " where hostname='" . $rec['domain'] + . "' and traffic_date='" . $traffic_date . "'"; + } else { + $sql = "insert into web_traffic (hostname, traffic_date, traffic_bytes) values ('".$rec['domain']."', '".$traffic_date."', '".$total_bytes."')"; + } + $app->dbmaster->query($sql); + + fclose($handle); + } + + $yesterday2 = date('Ymd',time() - 86400*2); + $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$yesterday2.'-access.log'); + + //* Compress logfile + if(@is_file($logfile)) { + // Compress yesterdays logfile + exec("gzip -c $logfile > $logfile.gz"); + unlink($logfile); + } + + // rotate and compress the error.log when it exceeds a size of 10 MB + $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/error.log'); + if(is_file($logfile) && filesize($logfile) > 10000000) { + exec("gzip -c $logfile > $logfile.1.gz"); + exec("cat /dev/null > $logfile"); + } + + // delete logfiles after 30 days + $month_ago = date('Ymd',time() - 86400 * 30); + $logfile = escapeshellcmd($rec['document_root'].'/' . $log_folder . '/'.$month_ago.'-access.log.gz'); + if(@is_file($logfile)) { + unlink($logfile); + } + + //* Delete older Log files, in case that we missed them before due to serverdowntimes. + $datepart = date('Ym',time() - 86400 * 31 * 2); + + $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log.gz'; + exec('rm -f '.$logfile); + + $logfile = escapeshellcmd($rec['document_root']).'/' . $log_folder . '/'.$datepart.'*-access.log'; + exec('rm -f '.$logfile); + } + + //* Delete old logfiles in /var/log/ispconfig/httpd/ that were created by vlogger for the hostname of the server + exec('hostname -f', $tmp_hostname); + if($tmp_hostname[0] != '' && is_dir('/var/log/ispconfig/httpd/'.$tmp_hostname[0])) { + exec('cd /var/log/ispconfig/httpd/'.$tmp_hostname[0]."; find . -mtime +30 -name '*.log' | xargs rm > /dev/null 2> /dev/null"); + } + unset($tmp_hostname); + + ####################################################################################################### + // Rotate the ispconfig.log file + ####################################################################################################### + + // rotate the ispconfig.log when it exceeds a size of 10 MB + $logfile = $conf['ispconfig_log_dir'].'/ispconfig.log'; + if(is_file($logfile) && filesize($logfile) > 10000000) { + exec("gzip -c $logfile > $logfile.1.gz"); + exec("cat /dev/null > $logfile"); + } + + // rotate the cron.log when it exceeds a size of 10 MB + $logfile = $conf['ispconfig_log_dir'].'/cron.log'; + if(is_file($logfile) && filesize($logfile) > 10000000) { + exec("gzip -c $logfile > $logfile.1.gz"); + exec("cat /dev/null > $logfile"); + } + + // rotate the auth.log when it exceeds a size of 10 MB + $logfile = $conf['ispconfig_log_dir'].'/auth.log'; + if(is_file($logfile) && filesize($logfile) > 10000000) { + exec("gzip -c $logfile > $logfile.1.gz"); + exec("cat /dev/null > $logfile"); + } + + ####################################################################################################### + // Cleanup website tmp directories + ####################################################################################################### + + $sql = "SELECT domain_id, domain, document_root, system_user FROM web_domain WHERE server_id = ".$conf['server_id']; + $records = $app->db->queryAllRecords($sql); + $app->uses('system'); + if(is_array($records)) { + foreach($records as $rec){ + $tmp_path = realpath(escapeshellcmd($rec['document_root'].'/tmp')); + if($tmp_path != '' && strlen($tmp_path) > 10 && is_dir($tmp_path) && $app->system->is_user($rec['system_user'])){ + exec('cd '.$tmp_path."; find . -mtime +1 -name 'sess_*' | grep -v -w .no_delete | xargs rm > /dev/null 2> /dev/null"); + } + } + } + + ####################################################################################################### + // Cleanup logs in master database (only the "master-server") + ####################################################################################################### + + if ($app->dbmaster == $app->db) { + /** 7 days */ + $tstamp = time() - (60*60*24*7); + + /* + * Keep 7 days in sys_log + * (we can delete the old items, because if they are OK, they don't interrest anymore + * if they are NOT ok, the server will try to process them in 1 minute and so the + * error appears again after 1 minute. So it is no problem to delete the old one! + */ + $sql = "DELETE FROM sys_log WHERE tstamp < " . $tstamp . " AND server_id != 0"; + $app->dbmaster->query($sql); + + /* + * Delete all remote-actions "done" and older than 7 days + * ATTENTION: We have the same problem as described in cleaning the datalog. We must not + * delete the last entry + */ + $sql = "SELECT max(action_id) FROM sys_remoteaction"; + $res = $app->dbmaster->queryOneRecord($sql); + $maxId = $res['max(action_id)']; + $sql = "DELETE FROM sys_remoteaction " . + "WHERE tstamp < " . $tstamp . " " . + " AND action_state = 'ok' " . + " AND action_id <" . intval($maxId); + $app->dbmaster->query($sql); + + /* + * The sys_datalog is more difficult. + * 1) We have to keet ALL entries with + * server_id=0, because they depend on ALL servers (even if they are not + * actually in the system (and will be insered in 3 days or so). + * 2) We have to keey ALL entries which are not actually precessed by the + * server never mind how old they are! + * 3) We have to keep the entry with the highest autoinc-id, because mysql calculates the + * autoinc-id as "new value = max(row) +1" and does not store this in a separate table. + * This means, if we delete to entry with the highest autoinc-value then this value is + * reused as autoinc and so there are more than one entries with the same value (over + * for example 4 Weeks). This is confusing for our system. + * ATTENTION 2) and 3) is in some case NOT the same! so we have to check both! + */ + + /* First we need all servers and the last sys_datalog-id they processed */ + $sql = "SELECT server_id, updated FROM server ORDER BY server_id"; + $records = $app->dbmaster->queryAllRecords($sql); + + /* Then we need the highest value ever */ + $sql = "SELECT max(datalog_id) FROM sys_datalog"; + $res = $app->dbmaster->queryOneRecord($sql); + $maxId = $res['max(datalog_id)']; + + /* Then delete server by server */ + foreach($records as $server) { + $tmp_server_id = intval($server['server_id']); + if($tmp_server_id > 0) { + $sql = "DELETE FROM sys_datalog " . + "WHERE tstamp < " . $tstamp . + " AND server_id = " . intval($server['server_id']) . + " AND datalog_id < " . intval($server['updated']) . + " AND datalog_id < " . intval($maxId); + } + // echo $sql . "\n"; + $app->dbmaster->query($sql); + } + } + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/300-quota_notify.inc.php b/server/lib/classes/cron.d/300-quota_notify.inc.php new file mode 100644 index 0000000000..c2ce89527f --- /dev/null +++ b/server/lib/classes/cron.d/300-quota_notify.inc.php @@ -0,0 +1,479 @@ +dbmaster == $app->db) { + + $global_config = $app->getconf->get_global_config('mail'); + + $current_month = date('Y-m'); + + //* Check website traffic quota + $sql = "SELECT sys_groupid,domain_id,domain,traffic_quota,traffic_quota_lock FROM web_domain WHERE (traffic_quota > 0 or traffic_quota_lock = 'y') and (type = 'vhost' OR type = 'vhostsubdomain')"; + $records = $app->db->queryAllRecords($sql); + if(is_array($records)) { + foreach($records as $rec) { + + $web_traffic_quota = $rec['traffic_quota']; + $domain = $rec['domain']; + + // get the client + /* + $client_group_id = $rec["sys_groupid"]; + $client = $app->db->queryOneRecord("SELECT limit_traffic_quota,parent_client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); + $reseller = $app->db->queryOneRecord("SELECT limit_traffic_quota FROM client WHERE client_id = ".intval($client['parent_client_id'])); + + $client_traffic_quota = intval($client['limit_traffic_quota']); + $reseller_traffic_quota = intval($reseller['limit_traffic_quota']); + */ + + //* get the traffic + $tmp = $app->db->queryOneRecord("SELECT SUM(traffic_bytes) As total_traffic_bytes FROM web_traffic WHERE traffic_date like '$current_month%' AND hostname = '$domain'"); + $web_traffic = round($tmp['total_traffic_bytes']/1024/1024); + + //* Website is over quota, we will disable it + /*if( ($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) || + ($client_traffic_quota > 0 && $web_traffic > $client_traffic_quota) || + ($reseller_traffic_quota > 0 && $web_traffic > $reseller_traffic_quota)) {*/ + if($web_traffic_quota > 0 && $web_traffic > $web_traffic_quota) { + $app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'y',active = 'n'", 'domain_id', $rec['domain_id']); + $app->log('Traffic quota for '.$rec['domain'].' exceeded. Disabling website.',LOGLEVEL_DEBUG); + + //* Send traffic notifications + if($rec['traffic_quota_lock'] != 'y' && ($web_config['overtraffic_notify_admin'] == 'y' || $web_config['overtraffic_notify_client'] == 'y')) { + + $placeholders = array('{domain}' => $rec['domain'], + '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root')); + + $recipients = array(); + //* send email to admin + if($global_config['admin_mail'] != '' && $web_config['overtraffic_notify_admin'] == 'y') { + $recipients[] = $global_config['admin_mail']; + } + + //* Send email to client + if($web_config['overtraffic_notify_client'] == 'y') { + $client_group_id = $rec["sys_groupid"]; + $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); + if($client['email'] != '') { + $recipients[] = $client['email']; + } + } + + send_notification_email('web_traffic_notification', $placeholders, $recipients); + } + + } else { + //* unlock the website, if traffic is lower then quota + if($rec['traffic_quota_lock'] == 'y') { + $app->dbmaster->datalogUpdate('web_domain', "traffic_quota_lock = 'n',active = 'y'", 'domain_id', $rec['domain_id']); + $app->log('Traffic quota for '.$rec['domain'].' ok again. Re-enabling website.',LOGLEVEL_DEBUG); + } + } + } + } + + + } + + + ####################################################################################################### + // send website quota warnings by email + ####################################################################################################### + + if ($app->dbmaster == $app->db) { + + $global_config = $app->getconf->get_global_config('mail'); + + //* Check website disk quota + $sql = "SELECT domain_id,sys_groupid,domain,system_user,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM web_domain WHERE (type = 'vhost' OR type = 'vhostsubdomain')"; + $records = $app->db->queryAllRecords($sql); + if(is_array($records) && !empty($records)) { + + $tmp_rec = $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'harddisk_quota' ORDER BY created DESC"); + $monitor_data = array(); + if(is_array($tmp_rec)) { + foreach ($tmp_rec as $tmp_mon) { + $monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data']))); + } + } + + foreach($records as $rec) { + + //$web_hd_quota = $rec['hd_quota']; + $domain = $rec['domain']; + + $username = $rec['system_user']; + $rec['used'] = $monitor_data['user'][$username]['used']; + $rec['soft'] = $monitor_data['user'][$username]['soft']; + $rec['hard'] = $monitor_data['user'][$username]['hard']; + $rec['files'] = $monitor_data['user'][$username]['files']; + + if (!is_numeric($rec['used'])){ + if ($rec['used'][0] > $rec['used'][1]){ + $rec['used'] = $rec['used'][0]; + } else { + $rec['used'] = $rec['used'][1]; + } + } + if (!is_numeric($rec['soft'])) $rec['soft']=$rec['soft'][1]; + if (!is_numeric($rec['hard'])) $rec['hard']=$rec['hard'][1]; + if (!is_numeric($rec['files'])) $rec['files']=$rec['files'][1]; + + // used space ratio + if($rec['soft'] > 0){ + $used_ratio = $rec['used']/$rec['soft']; + } else { + $used_ratio = 0; + } + + $rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%'; + + if($rec['used'] > 1024) { + $rec['used'] = round($rec['used'] / 1024,2).' MB'; + } else { + if ($rec['used'] != '') $rec['used'] .= ' KB'; + } + + if($rec['soft'] > 1024) { + $rec['soft'] = round($rec['soft'] / 1024,2).' MB'; + } elseif($rec['soft'] == 0){ + $rec['soft'] = '----'; + } else { + $rec['soft'] .= ' KB'; + } + + if($rec['hard'] > 1024) { + $rec['hard'] = round($rec['hard'] / 1024,2).' MB'; + } elseif($rec['hard'] == 0){ + $rec['hard'] = '----'; + } else { + $rec['hard'] .= ' KB'; + } + + // send notifications only if 90% or more of the quota are used + if($used_ratio < 0.9) { + // reset notification date + if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = NULL", 'domain_id', $rec['domain_id']); + + // send notification - everything ok again + if($rec['last_quota_notification'] && $web_config['overquota_notify_onok'] == 'y' && ($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y')) { + $placeholders = array('{domain}' => $rec['domain'], + '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), + '{used}' => $rec['used'], + '{soft}' => $rec['soft'], + '{hard}' => $rec['hard'], + '{ratio}' => $rec['ratio']); + + $recipients = array(); + + //* send email to admin + if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') { + $recipients[] = $global_config['admin_mail']; + } + + //* Send email to client + if($web_config['overquota_notify_client'] == 'y') { + $client_group_id = $rec["sys_groupid"]; + $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); + if($client['email'] != '') { + $recipients[] = $client['email']; + } + } + send_notification_email('web_quota_ok_notification', $placeholders, $recipients); + } + + continue; + } + + // could a notification be sent? + $send_notification = false; + if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified + elseif($web_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $web_config['overquota_notify_freq']) $send_notification = true; + + //* Send quota notifications + if(($web_config['overquota_notify_admin'] == 'y' || $web_config['overquota_notify_client'] == 'y') && $send_notification == true) { + $app->dbmaster->datalogUpdate('web_domain', "last_quota_notification = CURDATE()", 'domain_id', $rec['domain_id']); + + $placeholders = array('{domain}' => $rec['domain'], + '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), + '{used}' => $rec['used'], + '{soft}' => $rec['soft'], + '{hard}' => $rec['hard'], + '{ratio}' => $rec['ratio']); + + $recipients = array(); + + //* send email to admin + if($global_config['admin_mail'] != '' && $web_config['overquota_notify_admin'] == 'y') { + $recipients[] = $global_config['admin_mail']; + } + + //* Send email to client + if($web_config['overquota_notify_client'] == 'y') { + $client_group_id = $rec["sys_groupid"]; + $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); + if($client['email'] != '') { + $recipients[] = $client['email']; + } + } + send_notification_email('web_quota_notification', $placeholders, $recipients); + } + } + } + } + + + ####################################################################################################### + // send mail quota warnings by email + ####################################################################################################### + + if ($app->dbmaster == $app->db) { + + $global_config = $app->getconf->get_global_config('mail'); + $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail'); + + //* Check email quota + $sql = "SELECT mailuser_id,sys_groupid,email,name,quota,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM mail_user"; + $records = $app->db->queryAllRecords($sql); + if(is_array($records) && !empty($records)) { + + $tmp_rec = $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'email_quota' ORDER BY created DESC"); + $monitor_data = array(); + if(is_array($tmp_rec)) { + foreach ($tmp_rec as $tmp_mon) { + //$monitor_data = array_merge_recursive($monitor_data,unserialize($app->db->unquote($tmp_mon['data']))); + $tmp_array = unserialize($app->db->unquote($tmp_mon['data'])); + if(is_array($tmp_array)) { + foreach($tmp_array as $username => $data) { + if(@!$monitor_data[$username]['used']) $monitor_data[$username]['used'] = $data['used']; + } + } + } + } + + foreach($records as $rec) { + + $email = $rec['email']; + + $rec['used'] = isset($monitor_data[$email]['used']) ? $monitor_data[$email]['used'] : array(1 => 0); + + if (!is_numeric($rec['used'])) $rec['used']=$rec['used'][1]; + + // used space ratio + if($rec['quota'] > 0){ + $used_ratio = $rec['used']/$rec['quota']; + } else { + $used_ratio = 0; + } + + $rec['ratio'] = number_format($used_ratio * 100, 2, '.', '').'%'; + + if($rec['quota'] > 0){ + $rec['quota'] = round($rec['quota'] / 1048576,4).' MB'; + } else { + $rec['quota'] = '----'; + } + + if($rec['used'] < 1544000) { + $rec['used'] = round($rec['used'] / 1024,4).' KB'; + } else { + $rec['used'] = round($rec['used'] / 1048576,4).' MB'; + } + + // send notifications only if 90% or more of the quota are used + if($used_ratio < 0.9) { + // reset notification date + if($rec['last_quota_notification']) $app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = NULL", 'mailuser_id', $rec['mailuser_id']); + + // send notification - everything ok again + if($rec['last_quota_notification'] && $mail_config['overquota_notify_onok'] == 'y' && ($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y')) { + $placeholders = array('{email}' => $rec['email'], + '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), + '{used}' => $rec['used'], + '{name}' => $rec['name'], + '{quota}' => $rec['quota'], + '{ratio}' => $rec['ratio']); + + $recipients = array(); + //* send email to admin + if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') { + $recipients[] = $global_config['admin_mail']; + } + + //* Send email to client + if($mail_config['overquota_notify_client'] == 'y') { + $client_group_id = $rec["sys_groupid"]; + $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); + if($client['email'] != '') { + $recipients[] = $client['email']; + } + } + + send_notification_email('mail_quota_ok_notification', $placeholders, $recipients); + } + + continue; + } + + //* Send quota notifications + // could a notification be sent? + $send_notification = false; + if(!$rec['last_quota_notification']) $send_notification = true; // not yet notified + elseif($mail_config['overquota_notify_freq'] > 0 && $rec['notified_before'] >= $mail_config['overquota_notify_freq']) $send_notification = true; + + if(($mail_config['overquota_notify_admin'] == 'y' || $mail_config['overquota_notify_client'] == 'y') && $send_notification == true) { + $app->dbmaster->datalogUpdate('mail_user', "last_quota_notification = CURDATE()", 'mailuser_id', $rec['mailuser_id']); + + $placeholders = array('{email}' => $rec['email'], + '{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'), + '{used}' => $rec['used'], + '{name}' => $rec['name'], + '{quota}' => $rec['quota'], + '{ratio}' => $rec['ratio']); + + $recipients = array(); + //* send email to admin + if($global_config['admin_mail'] != '' && $mail_config['overquota_notify_admin'] == 'y') { + $recipients[] = $global_config['admin_mail']; + } + + //* Send email to client + if($mail_config['overquota_notify_client'] == 'y') { + $client_group_id = $rec["sys_groupid"]; + $client = $app->db->queryOneRecord("SELECT client.email FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id"); + if($client['email'] != '') { + $recipients[] = $client['email']; + } + } + + send_notification_email('mail_quota_notification', $placeholders, $recipients); + } + } + } + } + + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/400-openvz.inc.php b/server/lib/classes/cron.d/400-openvz.inc.php new file mode 100644 index 0000000000..daee5c44aa --- /dev/null +++ b/server/lib/classes/cron.d/400-openvz.inc.php @@ -0,0 +1,83 @@ +dbmaster == $app->db) { + $current_date = date('Y-m-d'); + + //* Check which virtual machines have to be deactivated + $sql = "SELECT * FROM openvz_vm WHERE active = 'y' AND active_until_date != '0000-00-00' AND active_until_date < '$current_date'"; + $records = $app->db->queryAllRecords($sql); + if(is_array($records)) { + foreach($records as $rec) { + $app->dbmaster->datalogUpdate('openvz_vm', "active = 'n'", 'vm_id', $rec['vm_id']); + $app->log('Virtual machine active date expired. Disabling VM '.$rec['veid'],LOGLEVEL_DEBUG); + } + } + } + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.d/500-backup.inc.php b/server/lib/classes/cron.d/500-backup.inc.php new file mode 100644 index 0000000000..39c721c9fd --- /dev/null +++ b/server/lib/classes/cron.d/500-backup.inc.php @@ -0,0 +1,330 @@ +getconf->get_server_config($conf['server_id'], 'server'); + $backup_dir = $server_config['backup_dir']; + $backup_mode = $server_config['backup_mode']; + if($backup_mode == '') $backup_mode = 'userzip'; + + $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); + $http_server_user = $web_config['user']; + + if($backup_dir != '') { + + if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') { + $backup_dir_permissions = 0755; + } else { + $backup_dir_permissions = 0750; + } + + if(!is_dir($backup_dir)) { + mkdir(escapeshellcmd($backup_dir), $backup_dir_permissions, true); + } else { + chmod(escapeshellcmd($backup_dir), $backup_dir_permissions); + } + + $sql = "SELECT * FROM web_domain WHERE server_id = '".$conf['server_id']."' AND (type = 'vhost' OR type = 'vhostsubdomain') AND backup_interval != 'none'"; + $records = $app->db->queryAllRecords($sql); + if(is_array($records)) { + foreach($records as $rec) { + + //* Do the website backup + if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) { + + $web_path = $rec['document_root']; + $web_user = $rec['system_user']; + $web_group = $rec['system_group']; + $web_id = $rec['domain_id']; + $web_backup_dir = $backup_dir.'/web'.$web_id; + if(!is_dir($web_backup_dir)) mkdir($web_backup_dir, 0750); + chmod($web_backup_dir, 0750); + //if(isset($server_config['backup_dir_ftpread']) && $server_config['backup_dir_ftpread'] == 'y') { + chown($web_backup_dir, $rec['system_user']); + chgrp($web_backup_dir, $rec['system_group']); + /*} else { + chown($web_backup_dir, 'root'); + chgrp($web_backup_dir, 'root'); + }*/ + if($backup_mode == 'userzip') { + //* Create a .zip backup as web user and include also files owned by apache / nginx user + $web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.zip'; + exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -group '.escapeshellarg($web_group).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval); + if($retval == 0) exec('cd '.escapeshellarg($web_path).' && sudo -u '.escapeshellarg($web_user).' find . -user '.escapeshellarg($http_server_user).' -print 2> /dev/null | zip -b /tmp --exclude=backup\* --update --symlinks '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' -@', $tmp_output, $retval); + } else { + //* Create a tar.gz backup as root user + $web_backup_file = 'web'.$web_id.'_'.date('Y-m-d_H-i').'.tar.gz'; + exec('tar pczf '.escapeshellarg($web_backup_dir.'/'.$web_backup_file).' --exclude=backup\* --directory '.escapeshellarg($web_path).' .', $tmp_output, $retval); + } + if($retval == 0){ + chown($web_backup_dir.'/'.$web_backup_file, 'root'); + chgrp($web_backup_dir.'/'.$web_backup_file, 'root'); + chmod($web_backup_dir.'/'.$web_backup_file, 0750); + + //* Insert web backup record in database + //$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')"; + //$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id'); + $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",".$web_id.",'web','".$backup_mode."',".time().",'".$app->db->quote($web_backup_file)."')"; + $app->db->query($sql); + if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); + } else { + if(is_file($web_backup_dir.'/'.$web_backup_file)) unlink($web_backup_dir.'/'.$web_backup_file); + } + + //* Remove old backups + $backup_copies = intval($rec['backup_copies']); + + $dir_handle = dir($web_backup_dir); + $files = array(); + while (false !== ($entry = $dir_handle->read())) { + if($entry != '.' && $entry != '..' && substr($entry,0,3) == 'web' && is_file($web_backup_dir.'/'.$entry)) { + $files[] = $entry; + } + } + $dir_handle->close(); + + rsort($files); + + for ($n = $backup_copies; $n <= 10; $n++) { + if(isset($files[$n]) && is_file($web_backup_dir.'/'.$files[$n])) { + unlink($web_backup_dir.'/'.$files[$n]); + //$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($files[$n])."'"; + //$tmp = $app->dbmaster->queryOneRecord($sql); + //$app->dbmaster->datalogDelete('web_backup', 'backup_id', $tmp['backup_id']); + //$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']); + $sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($files[$n])."'"; + $app->db->query($sql); + if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); + } + } + + unset($files); + unset($dir_handle); + + //* Remove backupdir symlink and create as directory instead + $app->uses('system'); + $app->system->web_folder_protection($web_path,false); + + if(is_link($web_path.'/backup')) { + unlink($web_path.'/backup'); + } + if(!is_dir($web_path.'/backup')) { + mkdir($web_path.'/backup'); + chown($web_path.'/backup', $rec['system_user']); + chgrp($web_path.'/backup', $rec['system_group']); + } + + $app->system->web_folder_protection($web_path,true); + + } + + /* If backup_interval is set to none and we have a + backup directory for the website, then remove the backups */ + if($rec['backup_interval'] == 'none') { + $web_id = $rec['domain_id']; + $web_user = $rec['system_user']; + $web_backup_dir = realpath($backup_dir.'/web'.$web_id); + if(is_dir($web_backup_dir)) { + exec('sudo -u '.escapeshellarg($web_user).' rm -f '.escapeshellarg($web_backup_dir.'/*')); + } + } + } + } + + $sql = "SELECT * FROM web_database WHERE server_id = '".$conf['server_id']."' AND backup_interval != 'none'"; + $records = $app->db->queryAllRecords($sql); + if(is_array($records)) { + + include('lib/mysql_clientdb.conf'); + + foreach($records as $rec) { + + //* Do the database backup + if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) { + + $web_id = $rec['parent_domain_id']; + $db_backup_dir = $backup_dir.'/web'.$web_id; + if(!is_dir($db_backup_dir)) mkdir($db_backup_dir, 0750); + chmod($db_backup_dir, 0750); + chown($db_backup_dir, 'root'); + chgrp($db_backup_dir, 'root'); + + //* Do the mysql database backup with mysqldump or mongodump + $db_id = $rec['database_id']; + $db_name = $rec['database_name']; + + if ($rec['type'] == 'mysql') { + $db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i').'.sql'; + //$command = "mysqldump -h '".escapeshellcmd($clientdb_host)."' -u '".escapeshellcmd($clientdb_user)."' -p'".escapeshellcmd($clientdb_password)."' -c --add-drop-table --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'"; + $command = "mysqldump -h ".escapeshellarg($clientdb_host)." -u ".escapeshellarg($clientdb_user)." -p".escapeshellarg($clientdb_password)." -c --add-drop-table --quote-names --routines --events --triggers --hex-blob --create-options --quick --result-file='".$db_backup_dir.'/'.$db_backup_file."' '".$db_name."'"; + exec($command, $tmp_output, $retval); + + //* Compress the backup with gzip + if($retval == 0) exec("gzip -c '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file)."' > '".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".gz'", $tmp_output, $retval); + + if($retval == 0){ + chmod($db_backup_dir.'/'.$db_backup_file.'.gz', 0750); + chown($db_backup_dir.'/'.$db_backup_file.'.gz', fileowner($db_backup_dir)); + chgrp($db_backup_dir.'/'.$db_backup_file.'.gz', filegroup($db_backup_dir)); + + //* Insert web backup record in database + //$insert_data = "(server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')"; + //$app->dbmaster->datalogInsert('web_backup', $insert_data, 'backup_id'); + $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mysql','sqlgz',".time().",'".$app->db->quote($db_backup_file).".gz')"; + $app->db->query($sql); + if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); + + } else { + if(is_file($db_backup_dir.'/'.$db_backup_file.'.gz')) unlink($db_backup_dir.'/'.$db_backup_file.'.gz'); + } + //* Remove the uncompressed file + if(is_file($db_backup_dir.'/'.$db_backup_file)) unlink($db_backup_dir.'/'.$db_backup_file); + } else if ($rec['type'] == 'mongo') { + $db_backup_file = 'db_'.$db_name.'_'.date('Y-m-d_H-i'); + + try { + $connection = new MongoClient("mongodb://root:123456@127.0.0.1:27017/admin"); + $db = $connection->selectDB($db_name); + // exclude not supported by mongodump, only get user collections + $collections = $db->getCollectionNames(false); + + foreach ($collections as $collection) { + // mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d -c
-o /tmp/test + $command = "mongodump -h 127.0.0.1 --port 27017 -u root -p 123456 --authenticationDatabase admin -d ".escapeshellcmd($db_name)." -c ".escapeshellcmd($collection)." -o ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file); + exec($command); + } + + if (is_dir(escapeshellcmd($db_backup_dir.'/'.$db_backup_file))) { + //* Compress the backup with gzip + exec("cd ".escapeshellcmd($db_backup_dir)." && tar -pczf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file).".tar.gz ".escapeshellcmd($db_backup_file)); + chmod($db_backup_dir.'/'.$db_backup_file.'.tar.gz', 0750); + chown($db_backup_dir.'/'.$db_backup_file.'.tar.gz', fileowner($db_backup_dir)); + chgrp($db_backup_dir.'/'.$db_backup_file.'.tar.gz', filegroup($db_backup_dir)); + + //* Insert web backup record in database + $sql = "INSERT INTO web_backup (server_id,parent_domain_id,backup_type,backup_mode,tstamp,filename) VALUES (".$conf['server_id'].",$web_id,'mongodb','rootgz',".time().",'".$app->db->quote($db_backup_file).".tar.gz')"; + $app->db->query($sql); + + if ($app->db->dbHost != $app->dbmaster->dbHost) { + $app->dbmaster->query($sql); + } + + //* Remove the uncompressed file + exec("rm -rf ".escapeshellcmd($db_backup_dir.'/'.$db_backup_file)); + } + } catch (MongoConnnectionException $e) { + // connecting to MongoDB failed - cannot create backup + } + } + + //* Remove old backups + $backup_copies = intval($rec['backup_copies']); + + $dir_handle = dir($db_backup_dir); + $files = array(); + while (false !== ($entry = $dir_handle->read())) { + if($entry != '.' && $entry != '..' && (preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.sql.gz$/', $entry, $matches) || preg_match('/^db_(.*?)_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}\.tar.gz$/', $entry, $matches)) && is_file($db_backup_dir.'/'.$entry)) { + if(array_key_exists($matches[1], $files) == false) $files[$matches[1]] = array(); + $files[$matches[1]][] = $entry; + } + } + $dir_handle->close(); + + reset($files); + foreach($files as $db_name => $filelist) { + rsort($filelist); + for ($n = $backup_copies; $n <= 10; $n++) { + if(isset($filelist[$n]) && is_file($db_backup_dir.'/'.$filelist[$n])) { + unlink($db_backup_dir.'/'.$filelist[$n]); + //$sql = "SELECT backup_id FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'"; + //$tmp = $app->dbmaster->queryOneRecord($sql); + //$sql = "DELETE FROM web_backup WHERE backup_id = ".intval($tmp['backup_id']); + $sql = "DELETE FROM web_backup WHERE server_id = ".$conf['server_id']." AND parent_domain_id = $web_id AND filename = '".$app->db->quote($filelist[$n])."'"; + $app->db->query($sql); + if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); + } + } + } + + unset($files); + unset($dir_handle); + } + } + + unset($clientdb_host); + unset($clientdb_user); + unset($clientdb_password); + + } + } + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/cron.inc.php b/server/lib/classes/cron.inc.php new file mode 100644 index 0000000000..c7bea321ce --- /dev/null +++ b/server/lib/classes/cron.inc.php @@ -0,0 +1,271 @@ +_sMinute = ''; + $this->_sHour = ''; + $this->_sDay = ''; + $this->_sMonth = ''; + $this->_sWDay = ''; + $this->_bParsed = false; + $this->_aValidValues = array('minute' => array(), + 'hour' => array(), + 'day' => array(), + 'month' => array(), + 'weekday' => array()); + } + + private function _calcValidValues() { + // minute field + $this->_aValidValues['minute'] = $this->_calcFieldValues('minute', $this->_sMinute); + $this->_aValidValues['hour'] = $this->_calcFieldValues('hour', $this->_sHour); + $this->_aValidValues['day'] = $this->_calcFieldValues('day', $this->_sDay); + $this->_aValidValues['month'] = $this->_calcFieldValues('month', $this->_sMonth); + $this->_aValidValues['weekday'] = $this->_calcFieldValues('weekday', $this->_sWDay); + $this->_bParsed = true; + } + + private function _calcFieldValues($sField, $sValue) { + global $app; + + $aValidValues = array(); + + // global checks + $iFrom = 0; + $iTo = 0; + switch($sField) { + case 'minute': + $iTo = 59; + break; + case 'hour': + $iTo = 23; + break; + case 'day': + $iFrom = 1; + $iTo = 31; + break; + case 'month': + $sValue = strtr($sValue, array('JAN' => 1, + 'FEB' => 2, + 'MAR' => 3, + 'APR' => 4, + 'MAY' => 5, + 'JUN' => 6, + 'JUL' => 7, + 'AUG' => 8, + 'SEP' => 9, + 'OCT' => 10, + 'NOV' => 11, + 'DEC' => 12) + ); + $iFrom = 1; + $iTo = 12; + break; + case 'weekday': + $sValue = strtr($sValue, array('SUN' => 0, + 'MON' => 1, + 'TUE' => 2, + 'WED' => 3, + 'THU' => 4, + 'FRI' => 5, + 'SAT' => 6, + '7' => 0) + ); + $iTo = 6; + break; + } + $aParts = explode(',', $sValue); + for($a = 0; $a < count($aParts); $a++) { + $sValue = $aParts[$a]; + $iValue = $app->functions->intval($sValue); + + if($sValue === '*') { + // everything is valid + for($i = $iFrom; $i <= $iTo; $i++) { + $aValidValues[] = $i; + } + break; // no need to go any further + } elseif((string)$iValue == $sValue) { + if($iValue >= $iFrom && $iValue <= $iTo) $aValidValues[] = $iValue; + } elseif(preg_match('/^([0-9]+)-([0-9]+)(\/([1-9][0-9]*))?$/', $sValue, $aMatch)) { + if($aMatch[1] < $iFrom) $aMatch[1] = $iFrom; + if($aMatch[2] > $iTo) $aMatch[2] = $iTo; + if(isset($aMatch[3])) { + for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) { + if(($i - $aMatch[1]) % $aMatch[4] == 0) $aValidValues[] = $i; + } + } else { + for($i = $aMatch[1]; $i <= $aMatch[2]; $i++) $aValidValues[] = $i; + } + } elseif(preg_match('/^\*\/([1-9][0-9]*)$/', $sValue, $aMatch)) { + for($i = $iFrom; $i <= $iTo; $i++) { + if($i % $aMatch[1] == 0) $aValidValues[] = $i; + } + } + } + + $aValidValues = array_unique($aValidValues); + sort($aValidValues); + + return $aValidValues; + } + + /**#@-*/ + + /** + * Set the cron field values + * + * @param string $sMinute the minute field value + * @param string $sHour the hour field value + * @param string $sDay the day field value + * @param string $sWDay the weekday field value + * @param string $sMonth the month field value + */ + public function setCronFields($sMinute = '*', $sHour = '*', $sDay = '*', $sMonth = '*', $sWDay = '*') { + $this->_sMinute = $sMinute; + $this->_sHour = $sHour; + $this->_sDay = $sDay; + $this->_sMonth = $sMonth; + $this->_sWDay = $sWDay; + $this->_bParsed = false; + } + + /** + * Parse a line of a cron and set the internal field values + * + * @param string $sLine cron line + */ + public function parseCronLine($sLine) { + $aFields = preg_split('/[ \t]+/', trim($sLine)); + for($i = 0; $i < 5; $i++) { + if(!isset($aFields[$i])) $aFields[$i] = '*'; + } + if($aFields[0] == '@yearly' || $aFields[0] == '@annually') $aFields = array(0, 0, 1, 1, '*'); + elseif($aFields[0] == '@monthly') $aFields = array(0, 0, 1, '*', '*'); + elseif($aFields[0] == '@weekly') $aFields = array(0, 0, '*', '*', 0); + elseif($aFields[0] == '@daily' || $aFields[0] == '@midnight') $aFields = array(0, 0, '*', '*', '*'); + elseif($aFields[0] == '@hourly') $aFields = array(0, '*', '*', '*', '*'); + + $this->setCronFields($aFields[0], $aFields[1], $aFields[2], $aFields[3], $aFields[4]); + } + + public function getNextRun($vDate) { + global $app; + + $iTimestamp = ISPConfigDatetime::to_timestamp($vDate); + if($iTimestamp === false) return $iTimestamp; + + if($this->_bParsed == false) $this->_calcValidValues(); + + // get the field values for the given Date. + list($iMinute, $iHour, $iDay, $iWDay, $iMonth, $iYear) = explode(':', ISPConfigDateTime::to_string($vDate, 'custom:%M:%H:%d:%w:%m:%Y')); + + $bValid = false; + $iStartYear = $iYear; + while($bValid == false) { + $iCurMinute = $this->_getNextValue('minute', $iMinute, true); + $iCurHour = $this->_getNextValue('hour', $iHour, true); + $iCurDay = $this->_getNextValue('day', $iDay, true); + $iCurMonth = $this->_getNextValue('month', $iMonth, true); + $iCurWDay = $this->_getNextValue('weekday', $iWDay, true); + + $iNextMinute = $this->_getNextValue('minute', $iMinute); + $iNextHour = $this->_getNextValue('hour', $iHour); + $iNextDay = $this->_getNextValue('day', $iDay); + $iNextMonth = $this->_getNextValue('month', $iMonth); + $iNextWDay = $this->_getNextValue('weekday', $iWDay); + + if($iNextMinute > $iMinute && $iHour == $iCurHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) { + $iMinute = $iNextMinute; + } elseif($iNextHour > $iHour && $iDay == $iCurDay && $iWDay == $iCurWDay && $iMonth == $iCurMonth) { + $iMinute = reset($this->_aValidValues['minute']); + $iHour = $iNextHour; + } elseif($iNextDay > $iDay && ISPConfigDateTime::last_day($iMonth) >= $iNextDay && $iMonth == $iCurMonth) { + $iMinute = reset($this->_aValidValues['minute']); + $iHour = reset($this->_aValidValues['hour']); + $iDay = $iNextDay; + } elseif($iNextMonth > $iMonth) { + $iMinute = reset($this->_aValidValues['minute']); + $iHour = reset($this->_aValidValues['hour']); + $iDay = reset($this->_aValidValues['day']); + $iMonth = $iNextMonth; + } else { + $iMinute = reset($this->_aValidValues['minute']); + $iHour = reset($this->_aValidValues['hour']); + $iDay = reset($this->_aValidValues['day']); + $iMonth = reset($this->_aValidValues['month']); + $iYear++; + } + + $ts = mktime($iHour, $iMinute, 0, $iMonth, $iDay, $iYear); + //print strftime('%d.%m.%Y (%A) %H:%M', $ts) . "\n"; + //var_dump($iCurMinute, $iCurHour, $iCurDay, $iCurMonth, $iCurWDay, '--', $iNextMinute, $iNextHour, $iNextDay, $iNextMonth, $iNextWDay); + if(ISPConfigDateTime::last_day($iMonth, $iYear) >= $iDay && in_array($app->functions->intval(strftime('%w', $ts)), $this->_aValidValues['weekday'], true) === true) { + $bValid = true; + } else { + if($iYear - $iStartYear > 5) { + if(LOG_PRIORITY <= PRIO_ERROR) $portal->log('No valid run dates for schedule ' . $this->_sMinute . ' ' . $this->_sHour . ' ' . $this->_sDay . ' ' . $this->_sMonth . ' ' . $this->_sWDay . ' in the next 5 years!', PRIO_ERROR, __FILE__, __LINE__); + return false; + } + } + } + + //var_dump($vDate, implode('-', array($iYear, $iMonth, $iDay, $iHour, $iNextMinute, 0)), $this->_sMinute, $this->_sHour, $this->_sDay, $this->_sWDay, $this->_sMonth, $this->_aValidValues); + return $iYear . '-' . $iMonth . '-' . $iDay . ' ' . $iHour . ':' . $iNextMinute . ':0'; + } + + private function _getNextValue($sField, $iValue, $bIncludeCurrent = false) { + if(!array_key_exists($sField, $this->_aValidValues)) return false; + + reset($this->_aValidValues[$sField]); + while(($cur = each($this->_aValidValues[$sField])) !== false) { + if($bIncludeCurrent == true && $cur['value'] >= $iValue) return $cur['value']; + elseif($cur['value'] > $iValue) return $cur['value']; + } + return reset($this->_aValidValues[$sField]); + } +} + +?> diff --git a/server/lib/classes/cronjob.inc.php b/server/lib/classes/cronjob.inc.php new file mode 100644 index 0000000000..6513654401 --- /dev/null +++ b/server/lib/classes/cronjob.inc.php @@ -0,0 +1,158 @@ +_schedule; + } + + /** run through cronjob sequence **/ + public function run() { + + print "Called run() for class " . get_class($this) . "\n"; + print "Job has schedule: " . $this->_schedule . "\n"; + $this->onPrepare(); + $run_it = $this->onBeforeRun(); + if($run_it == true) { + $this->onRunJob(); + $this->onAfterRun(); + } + $this->onCompleted(); + + return; + } + + /* this function prepares some data for the job and sets next run time if first executed */ + protected function onPrepare() { + global $app; + + print "Called onPrepare() for class " . get_class($this) . "\n"; + // check the run time and values for this job + + // get previous run data + $data = $app->db->queryOneRecord("SELECT `last_run`, `next_run`, `running` FROM `sys_cron` WHERE `name` = '" . $app->db->quote(get_class($this)) . "'"); + if($data) { + if($data['last_run']) $this->_last_run = $data['last_run']; + if($data['next_run']) $this->_next_run = $data['next_run']; + if($data['running'] == 1) $this->_running = true; + } + if(!$this->_next_run) { + if($this->_run_at_new == true) { + $this->_next_run = ISPConfigDateTime::dbtime(); // run now. + } else { + $app->cron->parseCronLine($this->_schedule); + $next_run = $app->cron->getNextRun(ISPConfigDateTime::dbtime()); + $this->_next_run = $next_run; + + $app->db->query("REPLACE INTO `sys_cron` (`name`, `last_run`, `next_run`, `running`) VALUES ('" . $app->db->quote(get_class($this)) . "', " . ($this->_last_run ? "'" . $app->db->quote($this->_last_run) . "'" : "NULL") . ", " . ($next_run === false ? "NULL" : "'" . $app->db->quote($next_run) . "'") . ", " . ($this->_running == true ? "1" : "0") . ")"); + } + } + } + + /* this function checks if a cron job's next runtime is reached and returns true or false */ + protected function onBeforeRun() { + global $app; + + print "Called onBeforeRun() for class " . get_class($this) . "\n"; + + if($this->_running == true) return false; // job is still marked as running! + + print "Jobs next run is " . $this->_next_run . "\n"; + $reached = ISPConfigDateTime::compare($this->_next_run, ISPConfigDateTime::dbtime()); + print "Date compare of " . ISPConfigDateTime::to_timestamp($this->_next_run) . " and " . ISPConfigDateTime::dbtime() . " is " . $reached . "\n"; + if($reached === false) return false; // error! + + if($reached === -1) { + // next_run time not reached + return false; + } + + // next_run time reached (reached === 0 or -1) + + // calculare next run time based on last_run or current time + $app->cron->parseCronLine($this->_schedule); + if($this->_no_skip == true) { + // we need to calculare the next run based on the previous next_run, as we may not skip one. + $next_run = $app->cron->getNextRun($this->_next_run); + if($next_run === false) { + // we could not calculate next run, try it with current time + $next_run = $app->cron->getNextRun(ISPConfigDateTime::dbtime()); + } + } else { + // calculate next run based on current time + $next_run = $app->cron->getNextRun(ISPConfigDateTime::dbtime()); + } + + print "Jobs next run is now " . $next_run . "\n"; + + $app->db->query("REPLACE INTO `sys_cron` (`name`, `last_run`, `next_run`, `running`) VALUES ('" . $app->db->quote(get_class($this)) . "', NOW(), " . ($next_run === false ? "NULL" : "'" . $app->db->quote($next_run) . "'") . ", 1)"); + return true; + } + + // child classes should override this! + protected function onRunJob() { + global $app; + + print "Called onRun() for class " . get_class($this) . "\n"; + } + + // child classes may override this! + protected function onAfterRun() { + global $app; + + print "Called onAfterRun() for class " . get_class($this) . "\n"; + } + + // child classes may NOT override this! + private function onCompleted() { + global $app; + + print "Called onCompleted() for class " . get_class($this) . "\n"; + $app->db->query("UPDATE `sys_cron` SET `running` = 0 WHERE `name` = '" . $app->db->quote(get_class($this)) . "'"); + } + +} + +?> diff --git a/server/lib/classes/functions.inc.php b/server/lib/classes/functions.inc.php new file mode 100644 index 0000000000..74f8400706 --- /dev/null +++ b/server/lib/classes/functions.inc.php @@ -0,0 +1,398 @@ +error("Mail sending disabled in demo mode."); + + $app->uses('getconf,ispcmail'); + $mail_config = $app->getconf->get_global_config('mail'); + if($mail_config['smtp_enabled'] == 'y') { + $mail_config['use_smtp'] = true; + $app->ispcmail->setOptions($mail_config); + } + $app->ispcmail->setSender($from, $from_name); + $app->ispcmail->setSubject($subject); + $app->ispcmail->setMailText($text); + + if($filepath != '') { + if(!file_exists($filepath)) $app->error("Mail attachement does not exist ".$filepath); + $app->ispcmail->readAttachFile($filepath); + } + + if($cc != '') $app->ispcmail->setHeader('Cc', $cc); + if($bcc != '') $app->ispcmail->setHeader('Bcc', $bcc); + + $app->ispcmail->send($to); + $app->ispcmail->finish(); + + /* left in here just for the case... + if($filepath != '') { + if(!file_exists($filepath)) $app->error("Mail attachement does not exist ".$filepath); + + $content = file_get_contents($filepath); + $content = chunk_split(base64_encode($content)); + $uid = strtoupper(md5(uniqid(time()))); + $subject = "=?utf-8?B?".base64_encode($subject)."?="; + + if($filename == '') { + $path_parts = pathinfo($filepath); + $filename = $path_parts["basename"]; + unset($path_parts); + } + + $header = "Return-Path: $from\nFrom: $from\nReply-To: $from\n"; + if($cc != '') $header .= "Cc: $cc\n"; + if($bcc != '') $header .= "Bcc: $bcc\n"; + $header .= "MIME-Version: 1.0\n"; + $header .= "Content-Type: multipart/mixed; boundary=$uid\n"; + + $header .= "--$uid\n"; + $header .= "Content-Type: text/plain;\n\tcharset=\"UTF-8\"\n"; + $header .= "Content-Transfer-Encoding: 8bit\n\n"; + $header .= "$text\n"; + + $header .= "--$uid\n"; + $header .= "Content-Type: $filetype; name=\"$filename\"\n"; + + $header .= "Content-Transfer-Encoding: base64\n"; + $header .= "Content-Disposition: attachment; filename=\"$filename\"\n\n"; + $header .= "$content\n"; + + $header .= "--$uid--"; + + mail($to, $subject, "", $header); + } else { + $header = "From: $from\nReply-To: $from\n"; + if($cc != '') $header .= "Cc: $cc\n"; + if($bcc != '') $header .= "Bcc: $bcc\n"; + $header .= "Content-Type: text/plain;\n\tcharset=\"UTF-8\"\n"; + $header .= "Content-Transfer-Encoding: 8bit\n\n"; + $subject = "=?utf-8?B?".base64_encode($subject)."?="; + mail($to, $subject, $text, $header); + } + */ + return true; + } + + public function array_merge($array1,$array2) { + $out = $array1; + foreach($array2 as $key => $val) { + $out[$key] = $val; + } + return $out; + } + + public function currency_format($number, $view = '') { + global $app; + if($view != '') $number_format_decimals = (int)$app->lng('number_format_decimals_'.$view); + if(!$number_format_decimals) $number_format_decimals = (int)$app->lng('number_format_decimals'); + + $number_format_dec_point = $app->lng('number_format_dec_point'); + $number_format_thousands_sep = $app->lng('number_format_thousands_sep'); + if($number_format_thousands_sep == 'number_format_thousands_sep') $number_format_thousands_sep = ''; + return number_format((double)$number, $number_format_decimals, $number_format_dec_point, $number_format_thousands_sep); + } + + public function get_ispconfig_url() { + global $app; + + $url = (stristr($_SERVER['SERVER_PROTOCOL'],'HTTPS') || stristr($_SERVER['HTTPS'],'on'))?'https':'http'; + if($_SERVER['SERVER_NAME'] != '_') { + $url .= '://'.$_SERVER['SERVER_NAME']; + if($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) { + $url .= ':'.$_SERVER['SERVER_PORT']; + } + } else { + $app->uses("getconf"); + $server_config = $app->getconf->get_server_config(1,'server'); + $url .= '://'.$server_config['hostname']; + if($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) { + $url .= ':'.$_SERVER['SERVER_PORT']; + } + } + return $url; + } + + public function json_encode($data) { + if(!function_exists('json_encode')){ + if(is_array($data) || is_object($data)){ + $islist = is_array($data) && (empty($data) || array_keys($data) === range(0,count($data)-1)); + + if($islist){ + $json = '[' . implode(',', array_map(array($this, "json_encode"), $data) ) . ']'; + } else { + $items = Array(); + foreach( $data as $key => $value ) { + $items[] = $this->json_encode("$key") . ':' . $this->json_encode($value); + } + $json = '{' . implode(',', $items) . '}'; + } + } elseif(is_string($data)){ + # Escape non-printable or Non-ASCII characters. + # I also put the \\ character first, as suggested in comments on the 'addclashes' page. + $string = '"'.addcslashes($data, "\\\"\n\r\t/".chr(8).chr(12)).'"'; + $json = ''; + $len = strlen($string); + # Convert UTF-8 to Hexadecimal Codepoints. + for($i = 0; $i < $len; $i++){ + $char = $string[$i]; + $c1 = ord($char); + + # Single byte; + if($c1 <128){ + $json .= ($c1 > 31) ? $char : sprintf("\\u%04x", $c1); + continue; + } + + # Double byte + $c2 = ord($string[++$i]); + if(($c1 & 32) === 0){ + $json .= sprintf("\\u%04x", ($c1 - 192) * 64 + $c2 - 128); + continue; + } + + # Triple + $c3 = ord($string[++$i]); + if(($c1 & 16) === 0){ + $json .= sprintf("\\u%04x", (($c1 - 224) <<12) + (($c2 - 128) << 6) + ($c3 - 128)); + continue; + } + + # Quadruple + $c4 = ord($string[++$i]); + if(($c1 & 8) === 0){ + $u = (($c1 & 15) << 2) + (($c2>>4) & 3) - 1; + + $w1 = (54<<10) + ($u<<6) + (($c2 & 15) << 2) + (($c3>>4) & 3); + $w2 = (55<<10) + (($c3 & 15)<<6) + ($c4-128); + $json .= sprintf("\\u%04x\\u%04x", $w1, $w2); + } + } + } else { + # int, floats, bools, null + $json = strtolower(var_export($data, true)); + } + return $json; + } else { + return json_encode($data); + } + } + + public function suggest_ips($type = 'IPv4'){ + global $app; + + if($type == 'IPv4'){ + $regex = "/^[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}$/"; + } else { + // IPv6 + $regex = "/^(\:\:([a-f0-9]{1,4}\:){0,6}?[a-f0-9]{0,4}|[a-f0-9]{1,4}(\:[a-f0-9]{1,4}){0,6}?\:\:|[a-f0-9]{1,4}(\:[a-f0-9]{1,4}){1,6}?\:\:([a-f0-9]{1,4}\:){1,6}?[a-f0-9]{1,4})(\/\d{1,3})?$/i"; + } + + $ips = array(); + $results = $app->db->queryAllRecords("SELECT ip_address AS ip FROM server_ip WHERE ip_type = '".$type."'"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + if(preg_match($regex, $result['ip'])) $ips[] = $result['ip']; + } + } + $results = $app->db->queryAllRecords("SELECT ip_address AS ip FROM openvz_ip"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + if(preg_match($regex, $result['ip'])) $ips[] = $result['ip']; + } + } + $results = $app->db->queryAllRecords("SELECT data AS ip FROM dns_rr WHERE type = 'A' OR type = 'AAAA'"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + if(preg_match($regex, $result['ip'])) $ips[] = $result['ip']; + } + } + $results = $app->db->queryAllRecords("SELECT ns AS ip FROM dns_slave"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + if(preg_match($regex, $result['ip'])) $ips[] = $result['ip']; + } + } + + $results = $app->db->queryAllRecords("SELECT xfer FROM dns_slave WHERE xfer != ''"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + $tmp_ips = explode(',', $result['xfer']); + foreach($tmp_ips as $tmp_ip){ + $tmp_ip = trim($tmp_ip); + if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip; + } + } + } + $results = $app->db->queryAllRecords("SELECT xfer FROM dns_soa WHERE xfer != ''"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + $tmp_ips = explode(',', $result['xfer']); + foreach($tmp_ips as $tmp_ip){ + $tmp_ip = trim($tmp_ip); + if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip; + } + } + } + $results = $app->db->queryAllRecords("SELECT also_notify FROM dns_soa WHERE also_notify != ''"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + $tmp_ips = explode(',', $result['also_notify']); + foreach($tmp_ips as $tmp_ip){ + $tmp_ip = trim($tmp_ip); + if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip; + } + } + } + $results = $app->db->queryAllRecords("SELECT remote_ips FROM web_database WHERE remote_ips != ''"); + if(!empty($results) && is_array($results)){ + foreach($results as $result){ + $tmp_ips = explode(',', $result['remote_ips']); + foreach($tmp_ips as $tmp_ip){ + $tmp_ip = trim($tmp_ip); + if(preg_match($regex, $tmp_ip)) $ips[] = $tmp_ip; + } + } + } + $ips = array_unique($ips); + sort($ips, SORT_NUMERIC); + + $result_array = array('cheader' => array(), 'cdata' => array()); + + if(!empty($ips)){ + $result_array['cheader'] = array('title' => 'IPs', + 'total' => count($ips), + 'limit' => count($ips) + ); + + foreach($ips as $ip){ + $result_array['cdata'][] = array( 'title' => $ip, + 'description' => $type, + 'onclick' => '', + 'fill_text' => $ip + ); + } + } + + return $result_array; + } + + public function intval($string, $force_numeric = false) { + if(intval($string) == 2147483647 || ($string > 0 && intval($string) < 0)) { + if($force_numeric == true) return floatval($string); + elseif(preg_match('/^([-]?)[0]*([1-9][0-9]*)([^0-9].*)*$/', $string, $match)) return $match[1].$match[2]; + else return 0; + } else { + return intval($string); + } + } + + /** IDN converter wrapper. + * all converter classes should be placed in ISPC_CLASS_PATH.'/idn/' + */ + private function _idn_encode_decode($domain, $encode = true) { + if($domain == '') return ''; + if(preg_match('/^[0-9\.]+$/', $domain)) return $domain; // may be an ip address - anyway does not need to bee encoded + + // get domain and user part if it is an email + $user_part = false; + if(strpos($domain, '@') !== false) { + $user_part = substr($domain, 0, strrpos($domain, '@')); + $domain = substr($domain, strrpos($domain, '@') + 1); + } + + if($encode == true) { + if(function_exists('idn_to_ascii')) { + $domain = idn_to_ascii($domain); + } elseif(file_exists(ISPC_CLASS_PATH.'/idn/idna_convert.class.php')) { + /* use idna class: + * @author Matthias Sommerfeld + * @copyright 2004-2011 phlyLabs Berlin, http://phlylabs.de + * @version 0.8.0 2011-03-11 + */ + + if(!is_object($this->idn_converter) || $this->idn_converter_name != 'idna_convert.class') { + include_once(ISPC_CLASS_PATH.'/idn/idna_convert.class.php'); + $this->idn_converter = new idna_convert(array('idn_version' => 2008)); + $this->idn_converter_name = 'idna_convert.class'; + } + $domain = $this->idn_converter->encode($domain); + } + } else { + if(function_exists('idn_to_utf8')) { + $domain = idn_to_utf8($domain); + } elseif(file_exists(ISPC_CLASS_PATH.'/idn/idna_convert.class.php')) { + /* use idna class: + * @author Matthias Sommerfeld + * @copyright 2004-2011 phlyLabs Berlin, http://phlylabs.de + * @version 0.8.0 2011-03-11 + */ + + if(!is_object($this->idn_converter) || $this->idn_converter_name != 'idna_convert.class') { + include_once(ISPC_CLASS_PATH.'/idn/idna_convert.class.php'); + $this->idn_converter = new idna_convert(array('idn_version' => 2008)); + $this->idn_converter_name = 'idna_convert.class'; + } + $domain = $this->idn_converter->decode($domain); + } + } + + if($user_part !== false) return $user_part . '@' . $domain; + else return $domain; + } + + public function idn_encode($domain) { + $domains = explode("\n", $domain); + for($d = 0; $d < count($domains); $d++) { + $domains[$d] = $this->_idn_encode_decode($domains[$d], true); + } + return implode("\n", $domains); + } + + public function idn_decode($domain) { + $domains = explode("\n", $domain); + for($d = 0; $d < count($domains); $d++) { + $domains[$d] = $this->_idn_encode_decode($domains[$d], false); + } + return implode("\n", $domains); + } + +} + +?> \ No newline at end of file diff --git a/server/lib/classes/libdatetime.inc.php b/server/lib/classes/libdatetime.inc.php new file mode 100644 index 0000000000..2735768c82 --- /dev/null +++ b/server/lib/classes/libdatetime.inc.php @@ -0,0 +1,479 @@ + days, 1 => hours, 2 => minutes, 3 => seconds) + */ + public static function get_parts($seconds, $get_days = false) { + $days = 0; + if($get_days == true) { + $days = floor($seconds / (3600 * 24)); + $seconds = $seconds % (3600 * 24); + } + $hours = floor($seconds / 3600); + $seconds = $seconds % 3600; + $minutes = floor($seconds / 60); + $seconds = $seconds % 60; + + return array($days, $hours, $minutes, $seconds); + } + + public static function dbtime() { + global $app; + + $time = $app->db->queryOneRecord('SELECT UNIX_TIMESTAMP() as `time`'); + return $time['time']; + } + + /** + * Get a unix timestamp for a date + * + * @access public + * @param mixed $date the date to convert. Can be + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @return int the unix timestamp + */ + public static function to_timestamp($date) { + if(!is_string($date) && !is_numeric($date)) return false; + $date = trim($date); + + if(is_numeric($date)) return $date; + + if(strpos($date, '-') !== false) { + $regex = "(\d{2,4})-(\d{1,2})-(\d{1,2})(\s+(\d{1,2}):(\d{1,2})(:(\d{1,2}))?)?"; + $ok = preg_match("'$regex'", $date, $matches); + if($ok) { + $year = $matches[1]; + $month = $matches[2]; + $day = $matches[3]; + $hour = isset($matches[5]) ? $matches[5] : 0; + $minute = isset($matches[6]) ? $matches[6] : 0; + $second = isset($matches[8]) ? $matches[8] : 0; + } + } else { + $regex = "(\d{1,2})[/.](\d{1,2})[/.](\d{2,4})(\s+(\d{1,2}):(\d{1,2})(:(\d{1,2}))?)?"; + $ok = preg_match("'$regex'", $date, $matches); + if($ok) { + $year = $matches[3]; + $month = $matches[2]; + $day = $matches[1]; + $hour = isset($matches[5]) ? $matches[5] : 0; + $minute = isset($matches[6]) ? $matches[6] : 0; + $second = isset($matches[8]) ? $matches[8] : 0; + } + } + + if(!$ok) return false; + + if(!$day || !$month || !$year) return false; + if(!$hour) $hour = 0; + if(!$minute) $minute = 0; + if(!$second) $second = 0; + if($year < 1900) $year += 1900; + + if(!checkdate($month, $day, $year)) return false; + + $date = mktime($hour, $minute, $second, $month, $day, $year); + + return $date; + } + + /** + * Get a date string + * + * Returns a formatted date string + * + * @access public + * @param mixed $date the date to convert. Can be + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @param string $format the format to get the date string in. + * - short: dd.mm.yy + * - veryshort: dd.mm. + * - medium: dd.mm.yyyy + * - long: dd. Month yyyy + * - extra: Day, dd. Month yyyy + * - day: dd + * - monthnum: mm + * - shortmonth: Short month name like Mar for March + * - month: Month name + * - shortyear: yy + * - year: yyyy + * - onlydate: dd.mm + * - onlydatelong: dd. Month + * - onlytime: HH:MM + * - rss: Rss time format for XML + * - nice: if you prepend a nice: (like nice:long) you will get results like "today" or "yesterday" if applicable + * - custom: you can give a strftime format like %d.%m.%Y %H:%M if you prepend custom: to it + * @param bool $time if true apped the time to the date string + * @param bool $seconds if true append the seconds to the time + * @return string date string + */ + public static function to_string($date, $format = 'short', $time = false, $seconds = false) { + global $portal; + + if(!$date) return ''; + + setlocale(LC_TIME, array('de_DE.UTF-8', 'de_DE', 'de_DE.ISO-8859-1', 'de_DE.ISO-8859-15')); + + if(!is_numeric($date)) { + $date = self::to_timestamp($date); + if($date === false) return $date; + } + + if($format == 'timestamp') return $date; + + $fmt = ''; + $prepend = ''; + if(substr($format, 0, 5) == 'nice:') { + if(strftime('%d.%m.%Y', $date) == strftime('%d.%m.%Y', $portal->getTime())) { + if($time == true) $format = 'onlytime'; + else $format = ''; + $prepend = 'Heute'; + } elseif(strftime('%d.%m.%Y', $date) == strftime('%d.%m.%Y', $portal->getTime() - 86400)) { + if($time == true) $format = 'onlytime'; + else $format = ''; + $prepend = 'Gestern'; + } elseif(strftime('%d.%m.%Y', $date) == strftime('%d.%m.%Y', $portal->getTime() + 86400)) { + if($time == true) $format = 'onlytime'; + else $format = ''; + $prepend = 'Morgen'; + } else { + $format = substr($format, 5); + } + } elseif(substr($format, 0, 7) == 'custom:') { + $fmt = substr($format, 7); + $format = ''; + $time = false; + } + + if($format == 'short') $fmt = '%d.%m.%y'; + elseif($format == 'veryshort') $fmt = '%d.%m.'; + elseif($format == 'medium') $fmt = '%d.%m.%Y'; + elseif($format == 'long') $fmt = '%d. %B %Y'; + elseif($format == 'extra') $fmt = '%A, %d. %B %Y'; + elseif($format == 'day') $fmt = '%d'; + elseif($format == 'monthnum') $fmt = '%m'; + elseif($format == 'shortmonth') $fmt = '%b'; + elseif($format == 'month') $fmt = '%B'; + elseif($format == 'shortyear') $fmt = '%y'; + elseif($format == 'year') $fmt = '%Y'; + elseif($format == 'onlydate') $fmt = '%d.%m.'; + elseif($format == 'onlydatelong') $fmt = '%d. %B'; + elseif($format == 'onlytime') { + $fmt = '%H:%M'; + $time = false; + } elseif($format == 'rss') { + $ret = date(DATE_RSS, $date); + if($prepend != '') $ret = $prepend . ' ' . $ret; + return $ret; + } elseif($format == 'sitemap') { + $ret = date(DATE_ATOM, $date); + if($prepend != '') $ret = $prepend . ' ' . $ret; + return $ret; + } + if($time == true) $fmt .= ' %H:%M' . ($seconds == true ? ':%S' : ''); + + if($fmt != '') $ret = strftime($fmt, $date); + else $ret = ''; + + if($prepend != '') $ret = trim($prepend . ' ' . $ret); + return $ret; + } + + /** + * Get the month difference of two dates + * + * Gets the difference in months of two given dates. + * The days are ignored, so the difference between 2010-01-21 and 2010-05-01 is 4! + * + * @access public + * @param mixed $date_from the beginning date, either + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @param mixed $date_to the ending date, either + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @param bool $return_years if set to true, the function returns an array of years and months instead of months + * @param bool $include_both if set to true, the starting AND ending month is included, so the month count is +1 + * @return mixed either int (months) or array of int (0 => years, 1 => months) or FALSE on invalid dates + */ + public static function months_between($date_from, $date_to, $return_years = false, $include_both = false) { + $date_from = self::to_string($date_from, 'custom:%Y%m'); + if($date_from === false) return $date_from; + + $date_to = self::to_string($date_to, 'custom:%Y%m'); + if($date_to === false) return $date_to; + + $date_from = intval($date_from); + $date_to = intval($date_to); + + if($date_to < $date_from) return false; + + $result = $date_to - $date_from; + if($include_both == true) $result++; + + $years = floor($result / 100); + $months = $result % 100; + if($months > 12) $months -= 88; + elseif($months == 12) { + $months = 0; + $years++; + } + if($return_years == true) return array($years, $months); + + $months += ($years * 12); + return $months; + } + + /** + * Get the day difference of two dates + * + * Gets the difference in days of two given dates. + * + * @access public + * @param mixed $date_from the beginning date, either + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @param mixed $date_to the ending date, either + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @param bool $include_both if set to true, the starting AND ending day is included, so the day count is +1 + * @return mixed either int (days) or FALSE on invalid dates + */ + public static function days_between($date_from, $date_to, $include_both = false) { + $date_from = self::to_string($date_from, 'custom:%Y-%m-%d'); + if($date_from === false) return $date_from; + list($y, $m, $d) = explode('-', $date_from); + $ts_from = mktime(0, 0, 0, $m, $d, $y); + + $date_to = self::to_string($date_to, 'custom:%Y-%m-%d'); + if($date_to === false) return $date_to; + list($y, $m, $d) = explode('-', $date_to); + $ts_to = mktime(0, 0, 0, $m, $d, $y); + + $result = $ts_to - $ts_from; + if($include_both == true) $result++; + + $days = floor($result / (3600 * 24)); + + return $days; + } + + /** + * Check if one date is before another + * + * @access public + * @param mixed $date_1 the first date, either + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @param mixed $date_2 the second date, either + * - int (unix timestamp) + * - date string yyyy-mm-dd[ hh:mm:ss] + * - date string dd.mm.yyyy[ hh:mm:ss] + * @return mixed either int (1 if the first date is earlier, -1 if the second date is earlier, 0 if both are the same) or FALSE on invalid dates + */ + public static function compare($date_1, $date_2) { + $ts_1 = self::to_timestamp($date_1); + if($ts_1 === false) return false; + $ts_2 = self::to_timestamp($date_2); + if($ts_2 === false) return false; + + if($ts_1 < $ts_2) return 1; + elseif($ts_1 > $ts_2) return -1; + else return 0; + } + + /** + * Convert date to sql format + * + * Converts a date from different formats to the sql format if possible + * + * @access public + * @param string $date date string in forms + * - dd.mm.yy + * - yyyy-mm-dd + * - yy-mm-dd + * - yyyy/mm/dd + * - dd.mm.yy + * - all formats can have time information HH:MM:SS appended + * @param bool $no_time if true, the resulting sql date is without time part even if time was part of the input + * @return mixed sql date string on success, error object otherwise + */ + public static function sql_date($date = false, $no_time = false) { + global $portal; + + $result = ''; + $time = ''; + + if($date === false) $date = $portal->getTime(true); + + if(is_numeric($date)) { + return ($no_time ? strftime('%Y-%m-%d', $date) : strftime('%Y-%m-%d %H:%M:%S', $date)); + } + + if(preg_match('/^(.*)(\d{1,2}:\d{1,2}(:\d{1,2})?)(\D|$)/', $date, $matches)) { + $date = $matches[1]; + $time = ' ' . $matches[2]; + } + if(preg_match('/(^|\D)(\d{4,4})-(\d{1,2})-(\d{1,2})(\D|$)/', $date, $result)) { + $day = $result[4]; + $month = $result[3]; + $year = $result[2]; + } elseif(preg_match('/(^|\D)(\d{4,4})\/(\d{1,2})\/(\d{1,2})(\D|$)/', $date, $result)) { + $day = $result[4]; + $month = $result[3]; + $year = $result[2]; + } elseif(preg_match('/(^|\D)(\d{2,2})-(\d{1,2})-(\d{1,2})(\D|$)/', $date, $result)) { + $day = $result[4]; + $month = $result[3]; + $year = $result[2]; + } elseif(preg_match('/(^|\D)(\d{1,2})\.(\d{1,2})\.(\d{4,4})(\D|$)/', $date, $result)) { + $day = $result[2]; + $month = $result[3]; + $year = $result[4]; + } elseif(preg_match('/(^|\D)(\d{1,2})\.(\d{1,2})\.(\d{2,2})(\D|$)/', $date, $result)) { + $day = $result[2]; + $month = $result[3]; + $year = $result[4]; + } else { + return false; + } + if($no_time == true) $time = ''; + + $day = str_pad(intval($day), 2, '0', STR_PAD_LEFT); + $month = str_pad(intval($month), 2, '0', STR_PAD_LEFT); + $year = intval($year); + + $valid = checkdate($month, $day, $year); + if(!$valid) return false; + + return $year . '-' . $month . '-' . $day . $time; + } + + /** + * Get information if given date is leap year + * + * @access public + * @param mixed $date Date to check + * @return bool true if leap year, false otherwise + */ + public static function is_leap_year($date) { + // check if only year was given + if(is_numeric($date) && $date < 10000) $date .= '-01-01'; + + $ts = self::to_timestamp($date); + if($ts === false) return false; + + if(date('L', $ts) == 1) return true; + else return false; + } + + /** + * Get the last day of the month + * + * @access public + * @param int $month the month to get the last day for + * @param int $year the corresponding year (for february in leap years) + * @return bool true if leap year, false otherwise + */ + public static function last_day($month, $year = false) { + switch($month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + break; + case 2: + return ($year !== false && self::is_leap_year($year) ? 29 : 28); + break; + default: + return 30; + break; + } + } + + /** + * Get age for given date + * + * Returns the age for a given date if possible + * + * @access public + * @param string $date see ISPConfigDateTime::sql_date() for possible values + * @return mixed int of age if successful, error object otherwise + * @see ISPConfigDateTime::sql_date + */ + public static function calc_age($date) { + global $portal; + + $date = self::sql_date($date); + if($date === false) return $date; + + list($year, $month, $day) = explode('-', $date); + list($curyear, $curmonth, $curday) = explode('-', strftime('%Y-%m-%d', $portal->getTime())); + + $year_diff = $curyear - $year; + $month_diff = $curmonth - $month; + $day_diff = $curday - $day; + + if($day_diff < 0) $month_diff--; + if($month_diff < 0) $year_diff--; + if($year_diff < 0) $year_diff = 0; + + return $year_diff; + } +} + diff --git a/server/lib/classes/monitor_tools.inc.php b/server/lib/classes/monitor_tools.inc.php index 6b93e1e6ae..42ef73ff8e 100644 --- a/server/lib/classes/monitor_tools.inc.php +++ b/server/lib/classes/monitor_tools.inc.php @@ -226,1461 +226,119 @@ class monitor_tools { return array('name' => $distname, 'version' => $distver, 'id' => $distid, 'baseid' => $distbaseid); } - //** Email Quota - public function monitorEmailQuota() { - global $conf, $app; - - //* Initialize data array - $data = array(); - - //* the id of the server as int - $server_id = intval($conf['server_id']); - - //* The type of the data - $type = 'email_quota'; - - //* The state of the email_quota. - $state = 'ok'; - - $mailboxes = $app->db->queryAllRecords("SELECT email,maildir FROM mail_user WHERE server_id = $server_id"); - if(is_array($mailboxes)) { - foreach($mailboxes as $mb) { - $email = $mb['email']; - $email_parts = explode('@',$mb['email']); - $filename = $mb['maildir'].'/.quotausage'; - if(file_exists($filename) && !is_link($filename)) { - $quotafile = file($filename); - $data[$email]['used'] = trim($quotafile['1']); - unset($quotafile); - } else { - exec('du -s '.escapeshellcmd($mb['maildir']),$out); - $parts = explode(' ',$out[0]); - $data[$email]['used'] = intval($parts[0])*1024; - unset($out); - unset($parts); - } - } - } - - unset($mailboxes); - - //* Dovecot quota check Courier in progress lathama@gmail.com - /* - if($dir = opendir("/var/vmail")){ - while (($quotafiles = readdir($dir)) !== false){ - if(preg_match('/.\_quota$/', $quotafiles)){ - $quotafile = (file("/var/vmail/" . $quotafiles)); - $emailaddress = preg_replace('/_quota/',"", $quotafiles); - $emailaddress = preg_replace('/_/',"@", $emailaddress); - $data[$emailaddress]['used'] = trim($quotafile['1']); - } - } - closedir($dir); - } - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - //** Filesystem Quota - public function monitorHDQuota() { - global $conf; - - //* Initialize data array - $data = array(); - - //* the id of the server as int - $server_id = intval($conf['server_id']); - - //* The type of the data - $type = 'harddisk_quota'; - - //* The state of the harddisk_quota. - $state = 'ok'; - - //* Fetch the data for all users - $dfData = shell_exec('repquota -au 2>/dev/null'); - - //* Split into array - $df = explode("\n", $dfData); - - //* ignore the first 5 lines, process the rest - for ($i = 5; $i <= sizeof($df); $i++) { - if ($df[$i] != '') { - //* Make a array of the data - $s = preg_split('/[\s]+/', $df[$i]); - $username = $s[0]; - if (substr($username, 0, 3) == 'web') { - if (isset($data['user'][$username])) { - $data['user'][$username]['used'] += $s[2]; - $data['user'][$username]['soft'] += $s[3]; - $data['user'][$username]['hard'] += $s[4]; - $data['user'][$username]['files'] += $s[5]; - } else { - $data['user'][$username]['used'] = $s[2]; - $data['user'][$username]['soft'] = $s[3]; - $data['user'][$username]['hard'] = $s[4]; - $data['user'][$username]['files'] = $s[5]; - } - } - } - } - - //** Fetch the data for all users - $dfData = shell_exec('repquota -ag 2>/dev/null'); - - //* split into array - $df = explode("\n", $dfData); - - //* ignore the first 5 lines, process the rest - for ($i = 5; $i <= sizeof($df); $i++) { - if ($df[$i] != '') { - //* Make a array of the data - $s = preg_split('/[\s]+/', $df[$i]); - $groupname = $s[0]; - if (substr($groupname, 0, 6) == 'client') { - if (isset($data['group'][$groupname])) { - $data['group'][$groupname]['used'] += $s[1]; - $data['group'][$groupname]['soft'] += $s[2]; - $data['group'][$groupname]['hard'] += $s[3]; - } else { - $data['group'][$groupname]['used'] = $s[1]; - $data['group'][$groupname]['soft'] = $s[2]; - $data['group'][$groupname]['hard'] = $s[3]; - } - } - } - } - - //* Return the Result - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorServer() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'server_load'; - - /* - Fetch the data into a array - */ - $procUptime = shell_exec("cat /proc/uptime | cut -f1 -d' '"); - $data['up_days'] = floor($procUptime / 86400); - $data['up_hours'] = floor(($procUptime - $data['up_days'] * 86400) / 3600); - $data['up_minutes'] = floor(($procUptime - $data['up_days'] * 86400 - $data['up_hours'] * 3600) / 60); - - $data['uptime'] = shell_exec('uptime'); - - $tmp = explode(',', $data['uptime'], 4); - $tmpUser = explode(' ', trim($tmp[2])); - $data['user_online'] = intval($tmpUser[0]); - - //* New Load Average code to fix "always zero" bug in non-english distros. NEEDS TESTING - $loadTmp = shell_exec("cat /proc/loadavg | cut -f1-3 -d' '"); - $load = explode(' ', $loadTmp); - $data['load_1'] = floatval(str_replace(',', '.', $load[0])); - $data['load_5'] = floatval(str_replace(',', '.', $load[1])); - $data['load_15'] = floatval(str_replace(',', '.', $load[2])); - - /** The state of the server-load. */ - $state = 'ok'; - if ($data['load_1'] > 20) - $state = 'info'; - if ($data['load_1'] > 50) - $state = 'warning'; - if ($data['load_1'] > 100) - $state = 'critical'; - if ($data['load_1'] > 150) - $state = 'error'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorOsVer() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'os_info'; - - /* - Fetch the data into a array - */ - $dist = $this->get_distname(); - - $data['name'] = $dist['name']; - $data['version'] = $dist['version']; - - /* the OS has no state. It is, what it is */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorIspcVer() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'ispc_info'; - - /* - Fetch the data into a array - */ - $data['name'] = ISPC_APP_TITLE; - $data['version'] = ISPC_APP_VERSION; - - /* the ISPC-Version has no state. It is, what it is */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorDiskUsage() { - global $app,$conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'disk_usage'; - - /** The state of the disk-usage */ - $state = 'ok'; - - /** Fetch the data of ALL devices into a array (needed for monitoring!) */ - //$dfData = shell_exec('df -hT 2>/dev/null'); - $app->uses('getconf'); - $web_config = $app->getconf->get_server_config($conf['server_id'], 'web'); - $dfData = shell_exec('df -hT|grep -v "'.$web_config['website_basedir'].'/" 2>/dev/null'); - - // split into array - $df = explode("\n", $dfData); - - /* - * ignore the first line, process the rest - */ - for ($i = 1; $i <= sizeof($df); $i++) { - if ($df[$i] != '') { - /* - * Make an array of the data - */ - $s = preg_split('/[\s]+/', $df[$i]); - $data[$i]['fs'] = $s[0]; - $data[$i]['type'] = $s[1]; - $data[$i]['size'] = $s[2]; - $data[$i]['used'] = $s[3]; - $data[$i]['available'] = $s[4]; - $data[$i]['percent'] = $s[5]; - $data[$i]['mounted'] = $s[6]; - /* - * calculate the state - */ - $usePercent = floatval($data[$i]['percent']); - - //* get the free memsize - if(substr($data[$i]['available'],-1) == 'G') { - $freesize = floatval($data[$i]['available'])*1024; - } elseif(substr($data[$i]['available'],-1) == 'T') { - $freesize = floatval($data[$i]['available'])*1024*1024; - } else { - $freesize = floatval($data[$i]['available']); - } - - //* We don't want to check some filesystem which have no sensible filling levels - switch ($data[$i]['type']) { - case 'iso9660': - case 'cramfs': - case 'udf': - case 'tmpfs': - case 'devtmpfs': - case 'udev': - break; - default: - if ($usePercent > 75 && $freesize < 2000) - $state = $this->_setState($state, 'info'); - if ($usePercent > 80 && $freesize < 1000) - $state = $this->_setState($state, 'warning'); - if ($usePercent > 90 && $freesize < 500) - $state = $this->_setState($state, 'critical'); - if ($usePercent > 95 && $freesize < 100) - $state = $this->_setState($state, 'error'); - break; - } - } - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorMemUsage() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'mem_usage'; - - /* - Fetch the data into a array - */ - $miData = shell_exec('cat /proc/meminfo'); - - $memInfo = explode("\n", $miData); - - foreach ($memInfo as $line) { - $part = preg_split('/:/', $line); - $key = trim($part[0]); - $tmp = explode(' ', trim($part[1])); - $value = 0; - if ($tmp[1] == 'kB') - $value = $tmp[0] * 1024; - $data[$key] = $value; - } - - /* - * actually this info has no state. - * maybe someone knows better...???... - */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorCpu() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'cpu_info'; - - /* - Fetch the data into a array - */ - if (file_exists('/proc/cpuinfo')) { - $cpuData = shell_exec('cat /proc/cpuinfo'); - $cpuInfo = explode("\n", $cpuData); - $processor = 0; - - foreach ($cpuInfo as $line) { - - $part = preg_split('/:/', $line); - $key = trim($part[0]); - $value = trim($part[1]); - if ($key == 'processor') - $processor = intval($value); - if ($key != '') - $data[$key . ' ' . $processor] = $value; - } - - /* the cpu has no state. It is, what it is */ - $state = 'no_state'; - } else { - /* - * It is not Linux, so there is no data and no state - * - * no_state, NOT unknown, because "unknown" is shown as state - * inside the GUI. no_state is hidden. - * - * We have to write NO DATA inside the DB, because the GUI - * could not know, if there is any dat, or not... - */ - $state = 'no_state'; - $data['output'] = ''; - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorServices() { - global $app; - global $conf; - - /** the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** get the "active" Services of the server from the DB */ - $services = $app->db->queryOneRecord('SELECT * FROM server WHERE server_id = ' . $server_id); - /* - * If the DB is down, we have to set the db to "yes". - * If we don't do this, then the monitor will NOT monitor, that the db is down and so the - * rescue-module can not try to rescue the db - */ - if ($services == null) { - $services['db_server'] = 1; - } - - /* The type of the Monitor-data */ - $type = 'services'; - - /** the State of the monitoring */ - /* ok, if ALL active services are running, - * error, if not - * There is no other state! - */ - $state = 'ok'; - - /* Monitor Webserver */ - $data['webserver'] = -1; // unknown - not needed - if ($services['web_server'] == 1) { - if ($this->_checkTcp('localhost', 80)) { - $data['webserver'] = 1; - } else { - $data['webserver'] = 0; - $state = 'error'; // because service is down - } - } - - /* Monitor FTP-Server */ - $data['ftpserver'] = -1; // unknown - not needed - if ($services['file_server'] == 1) { - if ($this->_checkFtp('localhost', 21)) { - $data['ftpserver'] = 1; - } else { - $data['ftpserver'] = 0; - $state = 'error'; // because service is down - } - } - - /* Monitor SMTP-Server */ - $data['smtpserver'] = -1; // unknown - not needed - if ($services['mail_server'] == 1) { - if ($this->_checkTcp('localhost', 25)) { - $data['smtpserver'] = 1; - } else { - $data['smtpserver'] = 0; - $state = 'error'; // because service is down - } - } - - /* Monitor POP3-Server */ - $data['pop3server'] = -1; // unknown - not needed - if ($services['mail_server'] == 1) { - if ($this->_checkTcp('localhost', 110)) { - $data['pop3server'] = 1; - } else { - $data['pop3server'] = 0; - $state = 'error'; // because service is down - } - } - - /* Monitor IMAP-Server */ - $data['imapserver'] = -1; // unknown - not needed - if ($services['mail_server'] == 1) { - if ($this->_checkTcp('localhost', 143)) { - $data['imapserver'] = 1; - } else { - $data['imapserver'] = 0; - $state = 'error'; // because service is down - } - } - - /* Monitor BIND-Server */ - $data['bindserver'] = -1; // unknown - not needed - if ($services['dns_server'] == 1) { - if ($this->_checkUdp('localhost', 53)) { - $data['bindserver'] = 1; - } else { - $data['bindserver'] = 0; - $state = 'error'; // because service is down - } - } - - /* Monitor MySQL Server */ - $data['mysqlserver'] = -1; // unknown - not needed - if ($services['db_server'] == 1) { - if ($this->_checkTcp('localhost', 3306)) { - $data['mysqlserver'] = 1; - } else { - $data['mysqlserver'] = 0; - $state = 'error'; // because service is down - } - - if ($this->_checkTcp('localhost', 27017)) { - $data['mongodbserver'] = 1; - } else { - $data['mongodbserver'] = 0; - $state = 'error'; // because service is down - } - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorOpenVzHost() { - global $app; - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'openvz_veinfo'; - - /* - Fetch the data into a array - */ - $app->load(openvz_tools); - $openVzTools = new openvz_tools(); - $data = $openVzTools->getOpenVzVeInfo(); - - /* the VE-Info has no state. It is, what it is */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorOpenVzUserBeancounter() { - global $app; - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'openvz_beancounter'; - - /* - Fetch the data into a array - */ - $app->load(openvz_tools); - $openVzTools = new openvz_tools(); - $data = $openVzTools->getOpenVzVeBeanCounter(); - - /* calculate the state of the beancounter */ - if ($data == '') { - $state = 'no_state'; - } else { - $state = 'ok'; - - /* transfer this output-string into a array */ - $test = explode("\n", $data); - - /* the first list of the output is not needed */ - array_shift($test); - - /* now process all items of the rest */ - foreach ($test as $item) { - /* - * eliminate all doubled spaces and spaces at the beginning and end - */ - while (strpos($item, ' ') !== false) { - $item = str_replace(' ', ' ', $item); - } - $item = trim($item); - - /* - * The failcounter is the LAST - */ - if ($item != '') { - $tmp = explode(' ', $item); - $failCounter = $tmp[sizeof($tmp) - 1]; - if ($failCounter > 0) - $state = 'info'; - if ($failCounter > 50) - $state = 'warning'; - if ($failCounter > 200) - $state = 'critical'; - if ($failCounter > 10000) - $state = 'error'; - } - } - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorSystemUpdate() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'system_update'; - - /* This monitoring is only available on Debian or Ubuntu */ - if (file_exists('/etc/debian_version')) { - - /* - * first update the "apt database" - */ - shell_exec('apt-get update'); - - /* - * Then test the upgrade. - * if there is any output, then there is a needed update - */ - $aptData = shell_exec('apt-get -s -qq dist-upgrade'); - if ($aptData == '') { - /* There is nothing to update! */ - $state = 'ok'; - } else { - /* - * There is something to update! this is in most cases not critical, so we can - * do a system-update once a month or so... - */ - $state = 'info'; - } - - /* - * Fetch the output - */ - $data['output'] = $aptData; - } elseif (file_exists('/etc/gentoo-release')) { - - /* - * first update the portage tree - */ - - // In keeping with gentoo's rsync policy, don't update to frequently (every four hours - taken from http://www.gentoo.org/doc/en/source_mirrors.xml) - $do_update = true; - if (file_exists('/usr/portage/metadata/timestamp.chk')) { - $datetime = file_get_contents('/usr/portage/metadata/timestamp.chk'); - $datetime = trim($datetime); - - $dstamp = strtotime($datetime); - if ($dstamp) { - $checkat = $dstamp + 14400; // + 4hours - if (mktime() < $checkat) { - $do_update = false; - } - } - } - - if ($do_update) { - shell_exec('emerge --sync --quiet'); - } - - /* - * Then test the upgrade. - * if there is any output, then there is a needed update - */ - $emergeData = shell_exec('glsa-check -t affected'); - if ($emergeData == '') { - /* There is nothing to update! */ - $state = 'ok'; - $data['output'] = 'No unapplied GLSA\'s found on the system.'; - } else { - /* There is something to update! */ - $state = 'info'; - $data['output'] = shell_exec('glsa-check -pv --nocolor affected 2>/dev/null'); - } - } elseif (file_exists('/etc/SuSE-release')) { - - /* - * update and find the upgrade. - * if there is any output, then there is a needed update - */ - $aptData = shell_exec('zypper -q lu'); - if ($aptData == '') { - /* There is nothing to update! */ - $state = 'ok'; - } else { - /* - * There is something to update! this is in most cases not critical, so we can - * do a system-update once a month or so... - */ - $state = 'info'; - } - - /* - * Fetch the output - */ - $data['output'] = shell_exec('zypper lu'); - } else { - /* - * It is not Debian/Ubuntu, so there is no data and no state - * - * no_state, NOT unknown, because "unknown" is shown as state - * inside the GUI. no_state is hidden. - * - * We have to write NO DATA inside the DB, because the GUI - * could not know, if there is any dat, or not... - */ - $state = 'no_state'; - $data['output'] = ''; - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorMailQueue() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'mailq'; - - /* Get the data from the mailq */ - $data['output'] = shell_exec('mailq'); - - /* - * The last line has more informations - */ - $tmp = explode("\n", $data['output']); - $more = $tmp[sizeof($tmp) - 1]; - $res = $this->_getIntArray($more); - $data['bytes'] = $res[0]; - $data['requests'] = $res[1]; - - /** The state of the mailq. */ - $state = 'ok'; - if ($data['requests'] > 2000) - $state = 'info'; - if ($data['requests'] > 5000) - $state = 'warning'; - if ($data['requests'] > 8000) - $state = 'critical'; - if ($data['requests'] > 10000) - $state = 'error'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorRaid() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'raid_state'; - - /* - * We support several RAID types, but if we can't find any of them, we have no data - */ - $state = 'no_state'; - $data['output'] = ''; - - /* - * Check, if Software-RAID is enabled - */ - if (file_exists('/proc/mdstat')) { - /* - * Fetch the output - */ - $data['output'] = shell_exec('cat /proc/mdstat'); - - /* - * Then calc the state. - */ - $tmp = explode("\n", $data['output']); - $state = 'ok'; - for ($i = 0; $i < sizeof($tmp); $i++) { - /* fetch the next line */ - $line = $tmp[$i]; - - if ((strpos($line, '[U_]') !== false) || (strpos($line, '[_U]') !== false)) { - /* One Disk is not working. - * if the next line starts with "[>" or "[=" then - * recovery (resync) is in state and the state is - * information instead of critical - */ - $nextLine = $tmp[$i + 1]; - if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) { - $state = $this->_setState($state, 'critical'); - } else { - $state = $this->_setState($state, 'info'); - } - } - if (strpos($line, '[__]') !== false) { - /* both Disk are not working */ - $state = $this->_setState($state, 'error'); - } - if (strpos($line, '[UU]') !== false) { - /* The disks are OK. - * if the next line starts with "[>" or "[=" then - * recovery (resync) is in state and the state is - * information instead of ok - */ - $nextLine = $tmp[$i + 1]; - if ((strpos($nextLine, '[>') === false) && (strpos($nextLine, '[=') === false)) { - $state = $this->_setState($state, 'ok'); - } else { - $state = $this->_setState($state, 'info'); - } - } - } - } - /* - * Check, if we have mpt-status installed (LSIsoftware-raid) - */ - if (file_exists('/proc/mpt/summary')) { - system('which mpt-status', $retval); - if ($retval === 0) { - /* - * Fetch the output - */ - $data['output'] = shell_exec('mpt-status --autoload'); - - /* - * Then calc the state. - */ - $state = 'ok'; - if(is_array($data['output'])) { - foreach ($data['output'] as $item) { - /* - * The output contains information for every RAID and every HDD. - * We only need the state of the RAID - */ - if (strpos($item, 'state ') !== false) { - /* - * We found a raid, process the state of it - */ - if (strpos($item, ' ONLINE ') !== false) { - $this->_setState($state, 'ok'); - } elseif (strpos($item, ' OPTIMAL ') !== false) { - $this->_setState($state, 'ok'); - } elseif (strpos($item, ' INITIAL ') !== false) { - $this->_setState($state, 'info'); - } elseif (strpos($item, ' INACTIVE ') !== false) { - $this->_setState($state, 'critical'); - } elseif (strpos($item, ' RESYNC ') !== false) { - $this->_setState($state, 'info'); - } elseif (strpos($item, ' DEGRADED ') !== false) { - $this->_setState($state, 'critical'); - } else { - /* we don't know the state. so we set the state to critical, that the - * admin is warned, that something is wrong - */ - $this->_setState($state, 'critical'); - } - } - } - } - } - } - - /* - * 3ware Controller - */ - system('which tw_cli', $retval); - if($retval === 0) { - - $data['output'] = shell_exec('tw_cli info c0'); - - $state = 'ok'; - if(is_array($data['output'])) { - foreach ($data['output'] as $item) { - if (strpos($item, 'RAID') !== false) { - if (strpos($item, ' VERIFYING ') !== false) { - $this->_setState($state, 'info'); - } - else if (strpos($item, ' MIGRATE-PAUSED ') !== false) { - $this->_setState($state, 'info'); - } - else if (strpos($item, ' MIGRATING ') !== false) { - $this->_setState($state, 'ok'); - } - else if (strpos($item, ' INITIALIZING ') !== false) { - $this->_setState($state, 'info'); - } - else if (strpos($item, ' INIT-PAUSED ') !== false) { - $this->_setState($state, 'info'); - } - else if (strpos($item, ' REBUILDING ') !== false) { - $this->_setState($state, 'info'); - } - else if (strpos($item, ' REBUILD-PAUSED ') !== false) { - $this->_setState($state, 'warning'); - } - else if (strpos($item, ' RECOVERY ') !== false) { - $this->_setState($state, 'warning'); - } - else if (strpos($item, ' DEGRADED ') !== false) { - $this->_setState($state, 'critical'); - } - else if (strpos($item, ' UNKNOWN ') !== false) { - $this->_setState($state, 'critical'); - } - else if (strpos($item, ' OK ') !== false) { - $this->_setState($state, 'ok'); - } - else if (strpos($item, ' OPTIMAL ') !== false) { - $this->_setState($state, 'ok'); - } - else { - $this->_setState($state, 'critical'); - } - } - } - } - } - - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorRkHunter() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'rkhunter'; - - /* This monitoring is only available if rkhunter is installed */ - system('which rkhunter', $retval); - if ($retval === 0) { - /* - * Fetch the output - */ - $data['output'] = shell_exec('rkhunter --update --checkall --nocolors --skip-keypress'); - - /* - * At this moment, there is no state (maybe later) - */ - $state = 'no_state'; - } else { - /* - * rkhunter is not installed, so there is no data and no state - * - * no_state, NOT unknown, because "unknown" is shown as state - * inside the GUI. no_state is hidden. - * - * We have to write NO DATA inside the DB, because the GUI - * could not know, if there is any dat, or not... - */ - $state = 'no_state'; - $data['output'] = ''; - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorFail2ban() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_fail2ban'; - - /* This monitoring is only available if fail2ban is installed */ - system('which fail2ban-client', $retval); // Debian, Ubuntu, Fedora - if ($retval !== 0) - system('which fail2ban', $retval); // CentOS - if ($retval === 0) { - /* Get the data of the log */ - $data = $this->_getLogData($type); - - /* - * At this moment, there is no state (maybe later) - */ - $state = 'no_state'; - } else { - /* - * fail2ban is not installed, so there is no data and no state - * - * no_state, NOT unknown, because "unknown" is shown as state - * inside the GUI. no_state is hidden. - * - * We have to write NO DATA inside the DB, because the GUI - * could not know, if there is any dat, or not... - */ - $state = 'no_state'; - $data = ''; - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorMongoDB() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_mongodb'; - - /* This monitoring is only available if MongoDB is installed */ - system('which mongod', $retval); // Debian, Ubuntu, Fedora - if ($retval !== 0) - system('which mongod', $retval); // CentOS - if ($retval === 0) { - /* Get the data of the log */ - $data = $this->_getLogData($type); - - /* - * At this moment, there is no state (maybe later) - */ - $state = 'no_state'; - } else { - /* - * MongoDB is not installed, so there is no data and no state - * - * no_state, NOT unknown, because "unknown" is shown as state - * inside the GUI. no_state is hidden. - * - * We have to write NO DATA inside the DB, because the GUI - * could not know, if there is any dat, or not... - */ - $state = 'no_state'; - $data = ''; - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorIPTables() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'iptables_rules'; - - /* This monitoring is only available if fail2ban is installed */ - system('which iptables', $retval); // Debian, Ubuntu, Fedora - if ($retval === 0) { - /* Get the data of the log */ - $data['output'] = '

iptables -S (ipv4)

'.shell_exec('iptables -S 2>/dev/null'); - - /* - * At this moment, there is no state (maybe later) - */ - $state = 'no_state'; - } else { - $state = 'no_state'; - $data = ''; - } - - - /* This monitoring is only available if fail2ban is installed */ - system('which ip6tables', $retval); // Debian, Ubuntu, Fedora - if ($retval === 0) { - /* Get the data of the log */ - $data['output'] .= '

ip6tables -S (ipv6)

'.shell_exec('ip6tables -S 2>/dev/null'); - - /* - * At this moment, there is no state (maybe later) - */ - $state = 'no_state'; - } else { - $state = 'no_state'; - $data = ''; - } - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorSysLog() { + // this function remains in the tools class, because it is used by cron AND rescue + public function monitorServices() { global $app; global $conf; - /* the id of the server as int */ + /** the id of the server as int */ $server_id = intval($conf['server_id']); - /** The type of the data */ - $type = 'sys_log'; - + /** get the "active" Services of the server from the DB */ + $services = $app->db->queryOneRecord('SELECT * FROM server WHERE server_id = ' . $server_id); /* - * is there any warning or error for this server? + * If the DB is down, we have to set the db to "yes". + * If we don't do this, then the monitor will NOT monitor, that the db is down and so the + * rescue-module can not try to rescue the db */ - $state = 'ok'; - $dbData = $app->dbmaster->queryAllRecords('SELECT loglevel FROM sys_log WHERE server_id = ' . $server_id . ' AND loglevel > 0'); - if (is_array($dbData)) { - foreach ($dbData as $item) { - if ($item['loglevel'] == 1) - $state = $this->_setState($state, 'warning'); - if ($item['loglevel'] == 2) - $state = $this->_setState($state, 'error'); - } + if ($services == null) { + $services['db_server'] = 1; } - /** There is no monitor-data because the data is in the sys_log table */ - $data['output'] = ''; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorMailLog() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_mail'; - - /* Get the data of the log */ - $data = $this->_getLogData($type); - - /* - * actually this info has no state. - * maybe someone knows better...???... - */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorMailWarnLog() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_mail_warn'; - - /* Get the data of the log */ - $data = $this->_getLogData($type); - - /* - * actually this info has no state. - * maybe someone knows better...???... - */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorMailErrLog() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_mail_err'; - - /* Get the data of the log */ - $data = $this->_getLogData($type); - - /* - * actually this info has no state. - * maybe someone knows better...???... - */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorMessagesLog() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_messages'; - - /* Get the data of the log */ - $data = $this->_getLogData($type); - - /* - * actually this info has no state. - * maybe someone knows better...???... - */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorISPCCronLog() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_ispc_cron'; - - /* Get the data of the log */ - $data = $this->_getLogData($type); - - /* - * actually this info has no state. - * maybe someone knows better...???... - */ - $state = 'no_state'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorFreshClamLog() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_freshclam'; - - /* Get the data of the log */ - $data = $this->_getLogData($type); + /* The type of the Monitor-data */ + $type = 'services'; - /* Get the data from the LAST log-Entry. - * if there can be found: - * WARNING: Your ClamAV installation is OUTDATED! - * then the clamav is outdated. This is a warning! + /** the State of the monitoring */ + /* ok, if ALL active services are running, + * error, if not + * There is no other state! */ $state = 'ok'; - $tmp = explode("\n", $data); - $lastLog = array(); - if ($tmp[sizeof($tmp) - 1] == '') { - /* the log ends with an empty line remove this */ - array_pop($tmp); - } - if (strpos($tmp[sizeof($tmp) - 1], '-------------') !== false) { - /* the log ends with "-----..." remove this */ - array_pop($tmp); - } - for ($i = sizeof($tmp) - 1; $i > 0; $i--) { - if (strpos($tmp[$i], '---------') === false) { - /* no delimiter found, so add this to the last-log */ - $lastLog[] = $tmp[$i]; + /* Monitor Webserver */ + $data['webserver'] = -1; // unknown - not needed + if ($services['web_server'] == 1) { + if ($this->_checkTcp('localhost', 80)) { + $data['webserver'] = 1; } else { - /* delimiter found, so there is no more line left! */ - break; + $data['webserver'] = 0; + $state = 'error'; // because service is down } } - /* - * Now we have the last log in the array. - * Check if the outdated-string is found... - */ - foreach ($lastLog as $line) { - if (strpos(strtolower($line), 'outdated') !== false) { - /* - * Outdatet is only info, because if we set this to warning, the server is - * as long in state warning, as there is a new version of ClamAv which takes - * sometimes weeks! - */ - $state = $this->_setState($state, 'info'); + /* Monitor FTP-Server */ + $data['ftpserver'] = -1; // unknown - not needed + if ($services['file_server'] == 1) { + if ($this->_checkFtp('localhost', 21)) { + $data['ftpserver'] = 1; + } else { + $data['ftpserver'] = 0; + $state = 'error'; // because service is down } } - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorClamAvLog() { - global $conf; - - /* the id of the server as int */ - $server_id = intval($conf['server_id']); - - /** The type of the data */ - $type = 'log_clamav'; - - /* Get the data of the log */ - $data = $this->_getLogData($type); - - // Todo: the state should be calculated. - $state = 'ok'; - - /* - * Return the Result - */ - $res['server_id'] = $server_id; - $res['type'] = $type; - $res['data'] = $data; - $res['state'] = $state; - return $res; - } - - public function monitorIspConfigLog() { - global $conf; + /* Monitor SMTP-Server */ + $data['smtpserver'] = -1; // unknown - not needed + if ($services['mail_server'] == 1) { + if ($this->_checkTcp('localhost', 25)) { + $data['smtpserver'] = 1; + } else { + $data['smtpserver'] = 0; + $state = 'error'; // because service is down + } + } - /* the id of the server as int */ - $server_id = intval($conf['server_id']); + /* Monitor POP3-Server */ + $data['pop3server'] = -1; // unknown - not needed + if ($services['mail_server'] == 1) { + if ($this->_checkTcp('localhost', 110)) { + $data['pop3server'] = 1; + } else { + $data['pop3server'] = 0; + $state = 'error'; // because service is down + } + } - /** The type of the data */ - $type = 'log_ispconfig'; + /* Monitor IMAP-Server */ + $data['imapserver'] = -1; // unknown - not needed + if ($services['mail_server'] == 1) { + if ($this->_checkTcp('localhost', 143)) { + $data['imapserver'] = 1; + } else { + $data['imapserver'] = 0; + $state = 'error'; // because service is down + } + } - /* Get the data of the log */ - $data = $this->_getLogData($type); + /* Monitor BIND-Server */ + $data['bindserver'] = -1; // unknown - not needed + if ($services['dns_server'] == 1) { + if ($this->_checkUdp('localhost', 53)) { + $data['bindserver'] = 1; + } else { + $data['bindserver'] = 0; + $state = 'error'; // because service is down + } + } - // Todo: the state should be calculated. - $state = 'ok'; + /* Monitor MySQL Server */ + $data['mysqlserver'] = -1; // unknown - not needed + if ($services['db_server'] == 1) { + if ($this->_checkTcp('localhost', 3306)) { + $data['mysqlserver'] = 1; + } else { + $data['mysqlserver'] = 0; + $state = 'error'; // because service is down + } + } + $data['mongodbserver'] = -1; + if ($this->_checkTcp('localhost', 27017)) { + $data['mongodbserver'] = 1; + } else { + $data['mongodbserver'] = 0; + //$state = 'error'; // because service is down + /* TODO!!! check if this is a mongodbserver at all, otherwise it will always throw an error state!!! */ + } /* * Return the Result @@ -1691,7 +349,7 @@ class monitor_tools { $res['state'] = $state; return $res; } - + public function _getLogData($log) { global $conf; @@ -1915,7 +573,7 @@ class monitor_tools { * * If the actual state is critical and you call the method with error, * then the state is error. */ - private function _setState($oldState, $newState) { + public function _setState($oldState, $newState) { /* * Calculate the weight of the old state */ @@ -1965,20 +623,38 @@ class monitor_tools { } } - private function _getIntArray($line) { - /** The array of float found */ - $res = array(); - /* First build a array from the line */ - $data = explode(' ', $line); - /* then check if any item is a float */ - foreach ($data as $item) { - if ($item . '' == (int) $item . '') { - $res[] = $item; - } - } - return $res; + /** + * Deletes Records older than 4 minutes. + * The monitor writes new data every 5 minutes or longer (4 hour, 1 day). + * So if i delete all Date older than 4 minutes i can be sure, that all old data + * are deleted... + */ + public function delOldRecords($type, $serverId) { + global $app; + + // $now = time(); + // $old = $now - (4 * 60); // 4 minutes + $old = 'UNIX_TIMESTAMP() - 240'; + + /* + * ATTENTION if i do NOT pay attention of the server id, i delete all data (of the type) + * of ALL servers. This means, if i have a multiserver-environment and a server has a + * time not synced with the others (for example, all server has 11:00 and ONE server has + * 10:45) then the actual data of this server (with the time-stamp 10:45) get lost + * even though it is the NEWEST data of this server. To avoid this i HAVE to include + * the server-id! + */ + $sql = 'DELETE FROM monitor_data ' . + 'WHERE ' . + ' type =' . "'" . $app->dbmaster->quote($type) . "' " . + 'AND ' . + ' created < ' . $old . ' ' . + 'AND ' . + ' server_id = ' . $serverId; + $app->dbmaster->query($sql); } + } ?> diff --git a/server/mods-available/monitor_core_module.inc.php b/server/mods-available/monitor_core_module.inc.php deleted file mode 100644 index 88e994dccf..0000000000 --- a/server/mods-available/monitor_core_module.inc.php +++ /dev/null @@ -1,870 +0,0 @@ -_run_time = time(); - - /* - * Do the monitor every n minutes and write the result to the db - */ - $min = @date('i', $this->_run_time); - if (($min % $this->interval) == 0) { - $this->_doMonitor(); - } - } - - /** - * This function is called when a change in one of the registered tables is detected. - * The function then raises the events for the plugins. - */ - public function process($tablename, $action, $data) { - // not needed - } - - /** - * This method is called every n minutes, when the module ist loaded. - * The method then does a system-monitoring - */ - // TODO: what monitoring is done should be a config-var - private function _doMonitor() { - global $app; - /* - * We need the tools in almost every method, so initialize them once... - */ - $app->load('monitor_tools'); - $this->_tools = new monitor_tools(); - - /* - * Calls the single Monitoring steps - */ - $this->_monitorEmailQuota(); - $this->_monitorHDQuota(); - $this->_monitorServer(); - $this->_monitorOsVer(); - $this->_monitorIspcVer(); - $this->_monitorDiskUsage(); - $this->_monitorMemUsage(); - $this->_monitorCpu(); - $this->_monitorServices(); - if (@file_exists('/proc/user_beancounters')) { - $this->_monitorOpenVzHost(); - $this->_monitorOpenVzUserBeancounter(); - } - $this->_monitorMailLog(); - $this->_monitorMailWarnLog(); - $this->_monitorMailErrLog(); - $this->_monitorMessagesLog(); - $this->_monitorISPCCronLog(); - $this->_monitorFreshClamLog(); - $this->_monitorClamAvLog(); - $this->_monitorIspConfigLog(); - $this->_monitorSystemUpdate(); - $this->_monitorMailQueue(); - $this->_monitorRaid(); - $this->_monitorRkHunter(); - $this->_monitorFail2ban(); - $this->_monitorMongoDB(); - $this->_monitorIPTables(); - $this->_monitorSysLog(); - } - - private function _monitorEmailQuota() { - global $app, $conf; - - /* - * This monitoring is expensive, so do it only every 15 minutes - */ - $min = @date('i', $this->_run_time); - if ($min % 15 != 0) return; - - $app->uses('getconf'); - $mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail'); - if($mail_config['mailbox_quota_stats'] == 'n') return; - - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorEmailQuota(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorHDQuota() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorHDQuota(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorServer() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorServer(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorOsVer() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorOsVer(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorIspcVer() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorIspcVer(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorDiskUsage() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorDiskUsage(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorMemUsage() { - global $app; - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorMemUsage(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorCpu() { - global $app; - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorCpu(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorServices() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorServices(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorOpenVzHost() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorOpenVzHost(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorOpenVzUserBeancounter() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorOpenVzUserBeancounter(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorSystemUpdate() { - /* - * This monitoring is expensive, so do it only once an hour - */ - $min = @date('i', $this->_run_time); - if ($min != 0) - return; - - /* - * OK - here we go... - */ - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorSystemUpdate(); - - //* Ensure that output is encoded so that it does not break the serialize - //$res['data']['output'] = htmlentities($res['data']['output']); - $res['data']['output'] = htmlentities($res['data']['output'],ENT_QUOTES,'UTF-8'); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorMailQueue() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorMailQueue(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorRaid() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorRaid(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorRkHunter() { - /* - * This monitoring is expensive, so do it only once a day - */ - $min = @date('i', $this->_run_time); - $hour = @date('H', $this->_run_time); - if (!($min == 0 && $hour == 23)) - return; - /* - * OK . here we go... - */ - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorRkHunter(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorFail2ban() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorFail2ban(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorMongoDB() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorMongoDB(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - - private function _monitorIPTables() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorIPTables(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorSysLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorSysLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorMailLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorMailLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorMailWarnLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorMailWarnLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorMailErrLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorMailErrLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorMessagesLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorMessagesLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorISPCCronLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorISPCCronLog(); - - //* Ensure that output is encoded so that it does not break the serialize - if(is_array($res) && isset($res['data'])) $res['data'] = htmlentities($res['data']); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorFreshClamLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorFreshClamLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorClamAvLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorClamAvLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - private function _monitorIspConfigLog() { - global $app; - - /* - * First we get the Monitoring-data from the tools - */ - $res = $this->_tools->monitorIspConfigLog(); - - /* - * Insert the data into the database - */ - $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . - 'VALUES (' . - $res['server_id'] . ', ' . - "'" . $app->dbmaster->quote($res['type']) . "', " . - 'UNIX_TIMESTAMP(), ' . - "'" . $app->dbmaster->quote(serialize($res['data'])) . "', " . - "'" . $res['state'] . "'" . - ')'; - $app->dbmaster->query($sql); - - /* The new data is written, now we can delete the old one */ - $this->_delOldRecords($res['type'], $res['server_id']); - } - - /** - * Deletes Records older than 4 minutes. - * The monitor writes new data every 5 minutes or longer (4 hour, 1 day). - * So if i delete all Date older than 4 minutes i can be sure, that all old data - * are deleted... - */ - private function _delOldRecords($type, $serverId) { - global $app; - - // $now = time(); - // $old = $now - (4 * 60); // 4 minutes - $old = 'UNIX_TIMESTAMP() - 240'; - - /* - * ATTENTION if i do NOT pay attention of the server id, i delete all data (of the type) - * of ALL servers. This means, if i have a multiserver-environment and a server has a - * time not synced with the others (for example, all server has 11:00 and ONE server has - * 10:45) then the actual data of this server (with the time-stamp 10:45) get lost - * even though it is the NEWEST data of this server. To avoid this i HAVE to include - * the server-id! - */ - $sql = 'DELETE FROM monitor_data ' . - 'WHERE ' . - ' type =' . "'" . $app->dbmaster->quote($type) . "' " . - 'AND ' . - ' created < ' . $old . ' ' . - 'AND ' . - ' server_id = ' . $serverId; - $app->dbmaster->query($sql); - } - -} - -?> -- GitLab