mysql-remote-server fixes

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann 2023-01-08 23:20:31 +01:00
parent 12da117cab
commit 9c2f12ecb1
No known key found for this signature in database
GPG Key ID: C121F97338D7A352
14 changed files with 34 additions and 29 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ install/update.log
install/*.json
lib/userdata.inc.php
lib/userdata.inc.php.bak
lib/config.inc.php
logs/*
!logs/index.html
.buildpath

View File

@ -43,12 +43,6 @@ use PHPMailer\PHPMailer\PHPMailer;
const AREA = 'admin';
require __DIR__ . '/lib/init.php';
// get sql-root access data
Database::needRoot(true);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);
if ($page == 'overview' && $userinfo['change_serversettings'] == '1') {
$settings_data = PhpHelper::loadConfigArrayDir('./actions/admin/settings/');
Settings::loadSettingsInto($settings_data);

View File

@ -92,7 +92,7 @@ if ($page == 'overview' || $page == 'mysqls') {
$result = json_decode($json_result, true)['data'];
if (isset($result['databasename']) && $result['databasename'] != '') {
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);

View File

@ -225,7 +225,7 @@ CREATE TABLE `panel_customers` (
`allowed_mysqlserver` text NOT NULL,
PRIMARY KEY (`customerid`),
UNIQUE KEY `loginname` (`loginname`)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC;
DROP TABLE IF EXISTS `panel_databases`;

View File

@ -66,8 +66,8 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
KEY customerid (customerid)
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;";
Database::query($sql);
Database::query("SET SESSION innodb_strict_mode=OFF;");
// new customer allowed_mysqlserver field
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ROW_FORMAT=DYNAMIC;");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `customernumber` `customernumber` varchar(100) NOT NULL default '';");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` CHANGE COLUMN `allowed_phpconfigs` `allowed_phpconfigs` text NOT NULL;");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `allowed_mysqlserver` text NOT NULL;");

View File

@ -90,7 +90,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
// validate whether the dbserver exists
$dbserver = Validate::validate($dbserver, html_entity_decode(lng('mysql.mysql_server')), '/^[0-9]+$/', '', 0, true);
Database::needRoot(true, $dbserver);
Database::needRoot(true, $dbserver, false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);
@ -150,7 +150,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
$pma = Settings::Get('panel.phpmyadmin_url');
}
Database::needRoot(true, $dbserver);
Database::needRoot(true, $dbserver, false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);
@ -287,7 +287,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
}
$result = Database::pexecute_first($result_stmt, $params, true, true);
if ($result) {
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
$mbdata_stmt = Database::prepare("
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
WHERE table_schema = :table_schema
@ -364,7 +364,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
}
// Begin root-session
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
$dbmgr = new DbManager($this->logger());
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$dbmgr->getManager()->grantPrivilegesTo($result['databasename'], $password, $mysql_access_host, false, true);
@ -449,7 +449,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
'dbserver' => $_dbserver['dbserver']
], $query_fields), true, true);
// Begin root-session
Database::needRoot(true, $_dbserver['dbserver']);
Database::needRoot(true, $_dbserver['dbserver'], false);
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$mbdata_stmt = Database::prepare("
SELECT SUM(data_length + index_length) as MB FROM information_schema.TABLES
@ -536,7 +536,7 @@ class Mysqls extends ApiCommand implements ResourceEntity
$id = $result['id'];
// Begin root-session
Database::needRoot(true, $result['dbserver']);
Database::needRoot(true, $result['dbserver'], false);
$dbm = new DbManager($this->logger());
$dbm->getManager()->deleteDatabase($result['databasename']);
Database::needRoot(false);

View File

@ -146,6 +146,7 @@ class BackupCron extends FroxlorCron
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
// get all customer database-names
// @fixme respect multiple dbservers
$sel_stmt = Database::prepare("SELECT `databasename` FROM `" . TABLE_PANEL_DATABASES . "` WHERE `customerid` = :cid");
Database::pexecute($sel_stmt, [
'cid' => $data['customerid']

View File

@ -127,7 +127,7 @@ class TrafficCron extends FroxlorCron
while ($row_database = $databases_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($last_dbserver != $row_database['dbserver']) {
Database::needRoot(true, $row_database['dbserver']);
Database::needRoot(true, $row_database['dbserver'], true);
$last_dbserver = $row_database['dbserver'];
$databases_list = [];

View File

@ -79,6 +79,8 @@ class Database
private static $sqldata = null;
private static $need_dbname = true;
/**
* Wrapper for PDOStatement::execute so we can catch the PDOException
* and display the error nicely on the panel - also fetches the
@ -341,12 +343,13 @@ class Database
* @param int $dbserver
* optional
*/
public static function needRoot($needroot = false, $dbserver = 0)
public static function needRoot(bool $needroot = false, int $dbserver = 0, bool $need_db = true)
{
// force re-connecting to the db with corresponding user
// and set the $dbserver (mostly to 0 = default)
self::setServer($dbserver);
self::$needroot = $needroot;
self::$need_dbname = $need_db;
}
/**
@ -465,10 +468,11 @@ class Database
'ATTR_ERRMODE' => 'ERRMODE_EXCEPTION'
];
$dbconf["dsn"] = [
'dbname' => $sql["db"],
'charset' => 'utf8'
];
$dbconf["dsn"] = ['charset' => 'utf8'];
if (self::$need_dbname) {
$dbconf["dsn"]['dbname'] = $sql["db"];
}
if ($socket != null) {
$dbconf["dsn"]['unix_socket'] = FileDir::makeCorrectFile($socket);

View File

@ -96,7 +96,7 @@ class DbManager
$dbservers_stmt = Database::query("SELECT DISTINCT `dbserver` FROM `" . TABLE_PANEL_DATABASES . "`");
while ($dbserver = $dbservers_stmt->fetch(PDO::FETCH_ASSOC)) {
// require privileged access for target db-server
Database::needRoot(true, $dbserver['dbserver']);
Database::needRoot(true, $dbserver['dbserver'], false);
$dbm = new DbManager(FroxlorLogger::getInstanceOf());
$users = $dbm->getManager()->getAllSqlUsers(false);
@ -144,7 +144,7 @@ class DbManager
*/
public function createDatabase($loginname = null, $password = null, int $dbserver = 0, $last_accnumber = 0)
{
Database::needRoot(true, $dbserver);
Database::needRoot(true, $dbserver, false);
// check whether we shall create a random username
if (strtoupper(Settings::Get('customer.mysqlprefix')) == 'RANDOM') {
@ -169,18 +169,17 @@ class DbManager
// now create the database itself
$this->getManager()->createDatabase($username);
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "created database '" . $username . "'");
// and give permission to the user on every access-host we have
foreach (array_map('trim', explode(',', Settings::Get('system.mysql_access_host'))) as $mysql_access_host) {
$this->getManager()->grantPrivilegesTo($username, $password, $mysql_access_host);
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "grant all privileges for '" . $username . "'@'" . $mysql_access_host . "'");
}
$this->getManager()->flushPrivileges();
Database::needRoot(false);
$this->log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "created database '" . $username . "'");
return $username;
}

View File

@ -32,7 +32,7 @@ class Mysql
public static function dbserver(array $attributes): string
{
// get sql-root access data
Database::needRoot(true, (int)$attributes['data']);
Database::needRoot(true, (int)$attributes['data'], false);
Database::needSqlData();
$sql_root = Database::getSqlData();
Database::needRoot(false);

View File

@ -33,10 +33,16 @@ return [
'value' => $result['databasename']
],
'mysql_server' => [
'visible' => count($mysql_servers) > 1,
'type' => 'hidden',
'value' => $result['dbserver'] ?? 0,
],
'mysql_server_info' => [
'visible' => count($mysql_servers) > 1,
'label' => lng('mysql.mysql_server'),
'type' => 'label',
'value' => $mysql_servers[$result['dbserver']] ?? 'unknown db server'
'disabled' => true,
'value' => $mysql_servers[$result['dbserver']] ?? 'unknown db server',
],
'description' => [
'label' => lng('mysql.databasedescription'),

View File

@ -197,7 +197,7 @@
{% if field.next_to is defined %}
<div class="input-group">
{% endif %}
<select {% if field.visible is defined and field.visible == false %} disabled {% endif %} class="form-select {% if field.valid is defined and field.valid == false %}is-invalid{% endif %}" name="{{ id }}{% if field.select_mode is defined and field.select_mode == 'multiple' %}[]{% endif %}" id="{{ id }}" {% if field.mandatory is defined and field.mandatory %} required {% endif %} {% if field.select_mode is defined and field.select_mode == 'multiple' %} multiple="multiple" {% endif %}>
<select {% if field.visible is defined and field.visible == false %} disabled {% endif %} class="form-select {% if field.valid is defined and field.valid == false %}is-invalid{% endif %}" name="{{ id }}{% if field.select_mode is defined and field.select_mode == 'multiple' %}[]{% endif %}" id="{{ id }}" {% if field.mandatory is defined and field.mandatory %} required {% endif %} {% if field.select_mode is defined and field.select_mode == 'multiple' %} multiple="multiple" {% endif %}{% if field.readonly is defined and field.readonly %} readonly {% endif %}>
{% for val,txt in field.select_var %}
<option value="{{ val }}" {% if field.selected is defined and ((field.selected is not iterable and field.selected == val) or (field.selected is iterable and val in field.selected|keys)) %} selected="selected" {% endif %}>{{ txt|raw }}</option>
{% endfor %}