Commit 0543b213 authored by Florian Schaal's avatar Florian Schaal
parent 18b51953
......@@ -214,6 +214,7 @@ CREATE TABLE `client` (
`default_dbserver` int(11) NOT NULL DEFAULT '1',
`dns_servers` blob NOT NULL DEFAULT '',
`limit_database` int(11) NOT NULL DEFAULT '-1',
`limit_database_quota` int(11) NOT NULL default '-1',
`limit_cron` int(11) NOT NULL DEFAULT '0',
`limit_cron_type` enum('url','chrooted','full') NOT NULL DEFAULT 'url',
`limit_cron_frequency` int(11) NOT NULL DEFAULT '5',
......@@ -317,6 +318,7 @@ CREATE TABLE `client_template` (
`limit_dns_slave_zone` int(11) NOT NULL default '-1',
`limit_dns_record` int(11) NOT NULL default '-1',
`limit_database` int(11) NOT NULL default '-1',
`limit_database_quota` int(11) NOT NULL default '-1',
`limit_cron` int(11) NOT NULL default '0',
`limit_cron_type` enum('url','chrooted','full') NOT NULL default 'url',
`limit_cron_frequency` int(11) NOT NULL default '5',
......@@ -1757,6 +1759,7 @@ CREATE TABLE `web_database` (
`type` varchar(16) NOT NULL DEFAULT 'y',
`database_name` varchar(64) DEFAULT NULL,
`database_name_prefix` varchar(50) NOT NULL default '',
`database_quota` int(11) unsigned DEFAULT NULL,
`database_user_id` int(11) unsigned DEFAULT NULL,
`database_ro_user_id` int(11) unsigned DEFAULT NULL,
`database_charset` varchar(64) DEFAULT NULL,
......
......@@ -101,6 +101,8 @@ php_ini_check_minutes=1
overquota_notify_admin=y
overquota_notify_client=y
overquota_notify_freq=7
overquota_db_notify_admin=y
overquota_db_notify_client=y
overquota_notify_onok=n
[dns]
......
......@@ -124,32 +124,35 @@ class tools_monitor {
$record = $app->db->queryOneRecord("SELECT data, state FROM monitor_data WHERE type = 'database_size' and server_id = " . $_SESSION['monitor']['server_id'] . " order by created desc");
if(isset($record['data'])) {
$data = unserialize($record['data']);
/*
Format the data
*/
//* format the data
$html =
'<div class="systemmonitor-state state-'.$record['state'].'">
<div class="systemmonitor-content icons32 ico-'.$record['state'].'">
<table>
<thead>
<tr>
<table><thead><tr>
<td>'.$app->lng("monitor_database_name_txt").'</td>
<td>'.$app->lng("monitor_database_size_txt").'</td>
<td>'.$app->lng("monitor_database_client_txt").'</td>
<td>'.$app->lng("monitor_database_domain_txt").'</td>
</tr>';
foreach($data as $line) {
$html .= '<tr>';
if ($line['size'] > 0) $line['size'] = $app->functions->formatBytes($line['size']);
$t=$app->db->queryOneRecord("SELECT username FROM client WHERE sys_groupid = ".$line['client_id']);
$line['client_id']=$t['username'];
unset($t);
//* get the client
$line['client']=$app->db->queryOneRecord("SELECT client.username FROM web_database, sys_group, client WHERE web_database.sys_groupid = sys_group.groupid AND sys_group.client_id = client.client_id AND web_database.database_name='".$line['database_name']."'")['username'];
//* get the domain
$line['domain']=$app->db->queryOneRecord("SELECT domain FROM web_domain WHERE domain_id=(SELECT parent_domain_id FROM web_database WHERE database_name='".$line['database_name']."')")['domain'];
//* remove the sys_groupid from output
unset($line['sys_groupid']);
foreach ($line as $item) {
$html .= '<td>' . $item . '</td>';
}
$html .= '</tr></tmpl loop>';
}
$html .= '</tbody></table>';
$html .= '</div></div>';
$html .= '</tbody></table></div></div>';
} else {
$html = '<p>'.$app->lng("no_data_database_size_txt").'</p>';
}
......
......@@ -688,6 +688,18 @@ $form["tabs"]['web'] = array(
'default' => 'y',
'value' => array(0 => 'n', 1 => 'y')
),
'overquota_db_notify_admin' => array(
'datatype' => 'VARCHAR',
'formtype' => 'CHECKBOX',
'default' => 'y',
'value' => array(0 => 'n', 1 => 'y')
),
'overquota_db_notify_client' => array(
'datatype' => 'VARCHAR',
'formtype' => 'CHECKBOX',
'default' => 'y',
'value' => array(0 => 'n', 1 => 'y')
),
'overquota_notify_freq' => array(
'datatype' => 'INTEGER',
'formtype' => 'TEXT',
......
......@@ -197,4 +197,6 @@ $wb["v6_prefix_length"] = 'Prefix too long according to defined IPv6 ';
$wb['backup_dir_is_mount_txt'] = 'Backup directory is a mount?';
$wb['backup_dir_mount_cmd_txt'] = 'Mount command, if backup directory not mounted';
$wb['backup_delete_txt'] = 'Delete backups on domain/website delete';
$wb["overquota_db_notify_admin_txt"] = 'Send DB quota warnings to admin';
$wb["overquota_db_notify_client_txt"] = 'Send DB quota warnings to client';
?>
......@@ -125,6 +125,18 @@
{tmpl_var name='overquota_notify_client'}
</div>
</div>
<div class="ctrlHolder">
<p class="label">{tmpl_var name='overquota_db_notify_admin_txt'}</p>
<div class="multiField">
{tmpl_var name='overquota_db_notify_admin'}
</div>
</div>
<div class="ctrlHolder">
<p class="label">{tmpl_var name='overquota_db_notify_client_txt'}</p>
<div class="multiField">
{tmpl_var name='overquota_db_notify_client'}
</div>
</div>
<div class="ctrlHolder">
<label for="overquota_notify_freq">{tmpl_var name='overquota_notify_freq_txt'}</label>
<input name="overquota_notify_freq" id="overquota_notify_freq" value="{tmpl_var name='overquota_notify_freq'}" size="40" maxlength="255" type="text" class="textInput" />&nbsp;{tmpl_var name='overquota_notify_freq_note_txt'}
......
......@@ -1093,6 +1093,20 @@ $form["tabs"]['limits'] = array (
'rows' => '',
'cols' => ''
),
'limit_database_quota' => array (
'datatype' => 'INTEGER',
'formtype' => 'TEXT',
'validators' => array ( 0 => array ( 'type' => 'ISINT',
'errmsg'=> 'limit_database_quota_error_notint'),
),
'default' => '-1',
'value' => '',
'separator' => '',
'width' => '10',
'maxlength' => '10',
'rows' => '',
'cols' => ''
),
'limit_cron' => array (
'datatype' => 'INTEGER',
'formtype' => 'TEXT',
......
......@@ -557,6 +557,20 @@ $form["tabs"]['limits'] = array (
'rows' => '',
'cols' => ''
),
'limit_database_quota' => array (
'datatype' => 'INTEGER',
'formtype' => 'TEXT',
'validators' => array ( 0 => array ( 'type' => 'ISINT',
'errmsg'=> 'limit_database_quota_error_notint'),
),
'default' => '-1',
'value' => '',
'separator' => '',
'width' => '10',
'maxlength' => '10',
'rows' => '',
'cols' => ''
),
'limit_cron' => array (
'datatype' => 'INTEGER',
'formtype' => 'TEXT',
......
......@@ -172,4 +172,6 @@ $wb['added_by_txt'] = 'Added by';
$wb['added_date_txt'] = 'Added date';
$wb['parent_client_id_txt'] = 'Client of reseller';
$wb['none_txt'] = 'none';
$wb['limit_database_quota_txt'] = 'Database quota';
$wb['limit_database_quota_error_notint'] = 'The database quota limit must be a number.';
?>
......@@ -89,5 +89,7 @@ $wb['aps_limits_txt'] = 'APS Installer Limits';
$wb['limit_aps_txt'] = 'Max. number of APS instances';
$wb['limit_aps_error_notint'] = 'The APS instances limit must be a number.';
$wb['limit_domainmodule_txt'] = 'Domainmodule Limit';
$wb['client_limits_txt'] = 'Client Limits'
?>
\ No newline at end of file
$wb['client_limits_txt'] = 'Client Limits';
$wb['limit_database_quota_txt'] = 'Database quota';
$wb['limit_database_quota_error_notint'] = 'The database quota limit must be a number.';
?>
......@@ -229,6 +229,10 @@
<label for="limit_database">{tmpl_var name='limit_database_txt'}</label>
<input name="limit_database" id="limit_database" value="{tmpl_var name='limit_database'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
</div>
<div class="ctrlHolder">
<label for="limit_database_quota">{tmpl_var name='limit_database_quota_txt'}</label>
<input name="limit_database_quota" id="limit_database_quota" value="{tmpl_var name='limit_database_quota'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />&nbsp;MB
</div>
</div>
<div class="subsectiontoggle"><span></span>{tmpl_var name='cron_job_limits_txt'}<em></em></div>
<div style="display:none;">
......
......@@ -171,6 +171,10 @@
<label for="limit_database">{tmpl_var name='limit_database_txt'}</label>
<input name="limit_database" id="limit_database" value="{tmpl_var name='limit_database'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
</div>
<div class="ctrlHolder">
<label for="limit_database_quota">{tmpl_var name='limit_database_quota_txt'}</label>
<input name="limit_database_quota" id="limit_database_quota" value="{tmpl_var name='limit_database_quota'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />&nbsp;MB
</div>
</div>
<div class="subsectiontoggle"><span></span>{tmpl_var name='cron_job_limits_txt'}<em></em></div>
<div style="display:none;">
......@@ -247,4 +251,4 @@
</div>
</div>
</div>
\ No newline at end of file
</div>
......@@ -166,7 +166,7 @@ class page_action extends tform_actions {
if($_SESSION["s"]["user"]["typ"] != 'admin') {
// Get the limits of the client
$client_group_id = $_SESSION["s"]["user"]["default_group"];
$client = $app->db->queryOneRecord("SELECT db_servers, limit_database FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
$client = $app->db->queryOneRecord("SELECT db_servers, limit_database, limit_database_quota FROM sys_group, client WHERE sys_group.client_id = client.client_id AND sys_group.groupid = $client_group_id");
// When the record is updated
if($this->id > 0) {
......@@ -191,6 +191,20 @@ class page_action extends tform_actions {
}
}
// Check client quota
if ($client['limit_database_quota'] >= 0) {
$tmp = $app->db->queryOneRecord("SELECT sum(database_quota) as db_quota FROM web_database WHERE sys_groupid = $client_group_id");
$db_quota = $tmp['db_quota'];
$new_db_quota = $app->functions->intval($this->dataRecord["database_quota"]);
if(($db_quota + $new_db_quota > $client['limit_database_quota']) || ($new_db_quota < 0 && $client['limit_database_quota'] >= 0)) {
$max_free_quota = floor($client['limit_database_quota'] - $db_quota);
if($max_free_quota < 0) $max_free_quota = 0;
$app->tform->errorMessage .= $app->tform->lng("limit_database_quota_free_txt").": ".$max_free_quota." MB<br>";
$this->dataRecord['database_quota'] = $max_free_quota;
}
unset($tmp);
}
}
} else {
// check if client of database parent domain is client of db user!
......
......@@ -79,7 +79,7 @@ $form["tabs"]['database'] = array (
'formtype' => 'SELECT',
'default' => '',
'datasource' => array ( 'type' => 'SQL',
'querystring' => "SELECT web_domain.domain_id, CONCAT(web_domain.domain, ' :: ', server.server_name) AS parent_domain FROM web_domain, server WHERE web_domain.type = 'vhost' AND web_domain.server_id = server.server_id AND {AUTHSQL::web_domain} ORDER BY web_domain.domain",
'querystring' => "SELECT web_domain.domain_id, CONCAT(web_domain.domain, ' :: ', server.server_name) AS parent_domain FROM web_domain, server WHERE web_domain.type = 'vhost' AND web_domain.server_id = server.server_id AND {AUTHSQL} ORDER BY web_domain.domain",
'keyfield'=> 'domain_id',
'valuefield'=> 'parent_domain'
),
......@@ -117,6 +117,20 @@ $form["tabs"]['database'] = array (
'width' => '30',
'maxlength' => '25'
),
'database_quota' => array (
'datatype' => 'INTEGER',
'formtype' => 'TEXT',
'validators' => array ( 0 => array ( 'type' => 'ISINT',
'errmsg'=> 'limit_database_quota_error_notint'),
),
'default' => '-1',
'value' => '',
'separator' => '',
'width' => '10',
'maxlength' => '10',
'rows' => '',
'cols' => ''
),
'database_user_id' => array (
'datatype' => 'INTEGER',
'formtype' => 'SELECT',
......
......@@ -43,4 +43,7 @@ $wb['globalsearch_noresults_text_txt'] = "No results.";
$wb['globalsearch_noresults_limit_txt'] = "0 results";
$wb['globalsearch_searchfield_watermark_txt'] = "Search";
$wb['globalsearch_suggestions_text_txt'] = "Suggestions";
$wb['limit_database_quota_txt'] = 'Database quota';
$wb['limit_database_quota_error_notint'] = 'The database quota limit must be a number.';
$wb['limit_database_quota_free_txt']='Max. available DB quota ';
?>
......@@ -62,6 +62,10 @@
<input name="database_name" id="database_name" value="{tmpl_var name='database_name'}" size="30" maxlength="255" type="text" class="textInput formLengthHalf" />
</tmpl_if>
</div>
<div class="ctrlHolder">
<label for="database_quota">{tmpl_var name='limit_database_quota_txt'}</label>
<input name="database_quota" id="database_quota" value="{tmpl_var name='limit_database_quota'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />&nbsp;MB
</div>
<div class="ctrlHolder">
<label for="database_user_id">{tmpl_var name='database_user_txt'}</label>
<select name="database_user_id" id="database_user_id" class="selectInput">
......@@ -149,4 +153,4 @@
searchFieldWatermark: '',
resultBoxPosition: 'e'
});
</script>
\ No newline at end of file
</script>
ME-Version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
From: {admin_mail}
Reply-To: {admin_mail}
Subject: Datenbank-Speicherhinweis
Ihre Datenbank {database_name} hat den verfuegbaren Speicherplatz (nahezu) ausgeschoepft.
Datenbank: {databbase_name}
Belegter Speicherplatz: {used}
Verfuegbarer Speicherplatz: {quota}
Belegter Speicherplatz in %: {ratio}
ME-Version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
From: {admin_mail}
Reply-To: {admin_mail}
Subject: Database quota notification
The database {database_name} is near or over quota.
Database: {databbase_name}
Used space: {used}
Quota: {quota}
Usage ratio: {ratio}
ME-Version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
From: {admin_mail}
Reply-To: {admin_mail}
Subject: Datenbank-Speicherhinweis
Der belegte Speicherplatz Ihrer Datenbank {database_name} ist wieder ok.
Datenbank: {databbase_name}
Belegter Speicherplatz: {used}
Verfuegbarer Speicherplatz: {quota}
Belegter Speicherplatz in %: {ratio}
MIME-Version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
From: {admin_mail}
Reply-To: {admin_mail}
Subject: Database quota ok
The database {database_name} is no longer near or over quota.
Database: {database_name}
Used space: {used}
Quota: {quota}
Usage ratio: {ratio}
......@@ -77,38 +77,39 @@ class cronjob_monitor_database_size extends cronjob {
/** The state of the database-usage */
$state = 'ok';
/** Fetch the data of all active databases into an array */
$records = $app->db->queryAllRecords("SELECT database_name, sys_groupid FROM web_database WHERE server_id = $server_id AND active='y' GROUP BY sys_groupid, database_name ASC");
if(is_array($records) && !empty($records)) {
/** Fetch the data of all databases into an array */
$databases = $app->db->queryAllRecords("SELECT database_name, sys_groupid FROM web_database WHERE server_id = $server_id GROUP BY sys_groupid, database_name ASC");
if(is_array($databases) && !empty($databases)) {
$data = array();
for ($i = 0; $i < sizeof($records); $i++) {
$data[$i]['name'] = $records[$i]['database_name'];
$data[$i]['size'] = $app->db->getDatabaseSize($data[$i]['name']);
$data[$i]['client_id'] = $records[$i]['sys_groupid'];
for ($i = 0; $i < sizeof($databases); $i++) {
$data[$i]['database_name']= $databases[$i]['database_name'];
$data[$i]['size'] = $app->db->getDatabaseSize($databases[$i]['database_name']);
$data[$i]['sys_groupid'] = $databases[$i]['sys_groupid'];
}
}
$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']);
$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();
}
......
......@@ -463,7 +463,125 @@ class cronjob_quota_notify extends cronjob {
}
}
//######################################################################################################
// send database quota warnings by email
//######################################################################################################
if ($app->dbmaster == $app->db) {
$global_config = $app->getconf->get_global_config('mail');
//* get monitor-data
$tmp_rec = $app->db->queryAllRecords("SELECT data from monitor_data WHERE type = 'database_size' ORDER BY created DESC");
if(is_array($tmp_rec)) {
$monitor_data = array();
foreach ($tmp_rec as $tmp_mon) {
$tmp_array = unserialize($app->db->unquote($tmp_mon['data']));
if(is_array($tmp_array))
foreach($tmp_array as $sys_groupid => $data)
$monitor_data[$data['sys_groupid']][] = $data;
}
//* remove duplicates from monitor-data
foreach($monitor_data as $_monitor_data)
$monitor_data[$_monitor_data[0]['sys_groupid']]=array_map("unserialize", array_unique(array_map("serialize", $_monitor_data)));
}
//* get databases
$database_records = $app->db->queryAllRecords("SELECT database_id,sys_groupid,database_name,database_quota,last_quota_notification,DATEDIFF(CURDATE(), last_quota_notification) as `notified_before` FROM web_database;");
if(is_array($database_records) && !empty($database_records) && is_array($monitor_data) && !empty($monitor_data)) {
//* check database-quota
foreach($database_records as $rec) {
$database = $rec['database_name'];
$quota = $rec['database_quota'] * 1024 * 1024;
if (!is_numeric($quota)) break;
foreach ($monitor_data as $cid) {
foreach($cid_data as $monitor) {
if ($monitor['database_name'] == $database) {
//* get the client
$client = $app->db->queryOneRecord("SELECT client.username, client.email FROM web_database, sys_group, client WHERE web_database.sys_groupid = sys_group.groupid AND sys_group.client_id = client.client_id AND web_database.database_name='".$database."'");
//* check quota
if ($quota > 0) $used_ratio = $monitor['size'] / $quota;
else $used_ratio = 0;
//* 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_database', "last_quota_notification = NULL", 'database_id', $rec['database_id']);
$app->dbmaster->datalogUpdate('web_database', "last_quota_notification = CURDATE()", 'database_id', $rec['database_id']);
// send notification - everything ok again
if($rec['last_quota_notification'] && $web_config['overquota_notify_onok'] == 'y' && ($web_config['overquota_db_notify_admin'] == 'y' || $web_config['overquota_db_notify_client'] == 'y')) {
$placeholders = array(
'{database_name}' => $rec['database_name'],
'{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
'{used}' => $app->functions->formatBytes($monitor['size']),
'{quota}' => $quota.' MB',
'{ratio}' => number_format($used_ratio * 100, 2, '.', '').'%'
);
$recipients = array();
//* send email to admin
if($global_config['admin_mail'] != '' && $web_config['overquota_db_notify_admin'] == 'y')
$recipients[] = $global_config['admin_mail'];
//* Send email to client
if($web_config['overquota_db_notify_client'] == 'y' && $client['email'] != '')
$recipients[] = $client['email'];
send_notification_email('db_quota_ok_notification', $placeholders, $recipients);
}
}
//* 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_db_notify_admin'] == 'y' || $web_config['overquota_db_notify_client'] == 'y') && $send_notification == true) {
$app->dbmaster->datalogUpdate('web_database', "last_quota_notification = CURDATE()", 'database_id', $rec['database_id']);
$placeholders = array(
'{database_name}' => $rec['database_name'],
'{admin_mail}' => ($global_config['admin_mail'] != ''? $global_config['admin_mail'] : 'root'),
'{used}' => $app->functions->formatBytes($monitor['size']),
'{quota}' => $quota.' MB',
'{ratio}' => number_format($used_ratio * 100, 2, '.', '').'%'
);
$recipients = array();
//* send email to admin
if($global_config['admin_mail'] != '' && $web_config['overquota_db_notify_admin'] == 'y')
$recipients[] = $global_config['admin_mail'];
//* Send email to client
if($web_config['overquota_db_notify_client'] == 'y' && $client['email'] != '')
$recipients[] = $client['email'];
send_notification_email('db_quota_notification', $placeholders, $recipients);
}
}
}
}
}
}
}
parent::onRunJob();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment