<?php
error_reporting(E_ERROR | E_PARSE);
// Create connection to ProxySQL DB
// Modify the username / password / port as required for connecting to the local ProxySQL DB
$proxy_conn = mysqli_connect('127.0.0.1', 'admin', 'admin_password', '', 6032);
// Check connection
if (!$proxy_conn) {
die("Connection failed to ProxySQL: " . mysqli_connect_error() . PHP_EOL);
}
// Create connection to ProxySQL DB
// Modify the username / password / port as required for connecting to the backend MySQL DB (Recommend connecting through ProxySQL)
$db_conn = mysqli_connect('127.0.0.1', 'import_user', 'import_user_password', 'mysql');
// Check connection
if (!$db_conn) {
die("Connection failed to Percona via ProxySQL: " . mysqli_connect_error() . PHP_EOL);
}
// Defaults - DO NOT MODIFY
$changes = 0;
$failed = 0;
$debug = false;
$silent = false;
$action = 'help';
if (isset($argv[1])) {
if ($argv[1] == 'load') {
$action = 'load';
} elseif ($argv[1] == 'sync') {
$action = 'sync';
} elseif ($argv[1] == 'import_only') {
$action = 'import_only';
} elseif ($argv[1] == 'test_sync') {
$action = 'test_sync';
}
}
if (isset($argv[2])) {
if ($argv[2] == 'debug') {
$debug = true;
error_reporting(E_ALL);
} elseif ($argv[2] == 'silent') {
$silent = true;
}
}
if ($action == 'help') {
echo PHP_EOL;
echo PHP_EOL;
echo 'ProxySQL User Sync' . PHP_EOL;
echo '------------------' . PHP_EOL;
echo 'This script synchronises users from the backend MySQL DB with ProxySQL' . PHP_EOL . PHP_EOL;
echo 'USAGE:' . PHP_EOL;
echo 'php proxysql_user_sync.php help - This help menu' . PHP_EOL;
echo 'php proxysql_user_sync.php test_sync - Outputs all the changes the script would make but doesnt actually do them' . PHP_EOL;
echo 'php proxysql_user_sync.php import_only - Synchronise users to ProxySQL but do NOT load them into memory or save to disk' . PHP_EOL;
echo 'php proxysql_user_sync.php sync - Synchronise users to ProxySQL, load them into memory and save to disk' . PHP_EOL;
echo 'php proxysql_user_sync.php load - Load existing users in ProxySQL mysql_users table to memory and save to disk' . PHP_EOL;
echo 'php proxysql_user_sync.php <command> debug - Display PHP and MySQL errors for the requested task' . PHP_EOL;
echo 'php proxysql_user_sync.php <command> silent - No output' . PHP_EOL;
} elseif ($action == 'sync' || $action == 'test_sync' || $action == 'import_only') {
$db_sql = "SELECT DISTINCT User, Password FROM user WHERE Password <> '' ORDER BY User";
$db_result = mysqli_query($db_conn, $db_sql);
if (!$db_result && $debug) { echo mysqli_error($db_conn) . PHP_EOL; }
if (mysqli_num_rows($db_result) > 0) {
$prev_username = "";
while($db_row = mysqli_fetch_assoc($db_result)) {
// Ensure this is not a duplicate user
if ($prev_username != $db_row["User"]) {
// Lookup Percona user in ProxySQL
$proxy_result = mysqli_query($proxy_conn, "SELECT username, password FROM main.mysql_users WHERE username='" . $db_row["User"] . "'");
if (!$proxy_result && $debug) { echo mysqli_error($proxy_conn) . PHP_EOL; }
// User doesn't exist in ProxySQL .. Add it
if (mysqli_num_rows($proxy_result) == 0) {
if ($action == 'sync' || $action == 'import_only') {
if (mysqli_query($proxy_conn, "INSERT INTO main.mysql_users (username,password,default_hostgroup) VALUES ('" . $db_row["User"] . "','" . $db_row["Password"] . "', 10)")) {
if (!$silent) { echo $db_row["User"] . ' - Added to ProxySQL' . PHP_EOL; }
$changes++;
} else {
if (!$silent) { echo $db_row["User"] . ' - Failed to add user to ProxySQL, users out of sync' . PHP_EOL; }
if ($debug) { echo mysqli_error($proxy_conn) . PHP_EOL; }
$failed++;
}
} else {
if (!$silent) { echo $db_row["User"] . ' - needs to be ADDED to ProxySQL' . PHP_EOL; }
$changes++;
}
// User exists in ProxySQL .. check passwords match
} elseif (mysqli_num_rows($proxy_result) == 1) {
// Get returned row from ProxySQL DB
$proxy_row = mysqli_fetch_assoc($proxy_result);
// If Passwords don't match .. Update ProxySQL
if ($proxy_row["password"] != $db_row["Password"]) {
if ($action == 'sync' || $action == 'import_only') {
if (mysqli_query($proxy_conn, "UPDATE main.mysql_users SET password='" . $db_row["Password"] . "' WHERE username='" . $db_row["User"] . "'")) {
if (!$silent) { echo $db_row["User"] . ' - Password Updated ' . PHP_EOL; }
$changes++;
} else {
if (!$silent) { echo $db_row["User"] . ' - Failed to update password, passwords out of sync' . PHP_EOL; }
if ($debug) { echo mysqli_error($proxy_conn) . PHP_EOL; }
$failed++;
}
} else {
if (!$silent) { echo $db_row["User"] . ' - PASSWORD needs to be UPDATED in ProxySQL' . PHP_EOL; }
$changes++;
}
}
}
}
$prev_username = $db_row["User"]; // Take note of the last username processed to prevent duplicates
}
} else {
if (!$silent) { echo "No users found in Percona" . PHP_EOL; }
}
// Lookup users in ProxySQL to check they exist in Percona
$proxy_sql = "SELECT username, password FROM main.mysql_users ORDER BY username";
$proxy_result = mysqli_query($proxy_conn, $proxy_sql);
if (!$proxy_result && $debug) { echo mysqli_error($proxy_conn) . PHP_EOL; }
if (mysqli_num_rows($proxy_result) > 0) {
while($proxy_row = mysqli_fetch_assoc($proxy_result)) {
// Lookup ProxySQL user in Percona
$db_result = mysqli_query($db_conn, "SELECT DISTINCT User, Password FROM user WHERE User='" . $proxy_row["username"] . "' ORDER BY User LIMIT 1");
if (!$db_result && $debug) { echo mysqli_error($db_conn) . PHP_EOL; }
// If user doesn't exist in Percona .. Remove them from ProxySQL
if (mysqli_num_rows($db_result) == 0) {
if ($action == 'sync' || $action == 'import_only') {
if (mysqli_query($proxy_conn, "DELETE FROM main.mysql_users WHERE username='" . $proxy_row["username"] . "'")) {
if (!$silent) { echo $proxy_row["username"] . ' - Removed from ProxySQL' . PHP_EOL; }
$changes++;
} else {
if (!$silent) { echo $proxy_row["username"] . ' - Failed to remove user from ProxySQL, users out of sync' . PHP_EOL; }
if ($debug) { echo mysqli_error($proxy_conn) . PHP_EOL; }
$failed++;
}
} else {
if (!$silent) { echo $proxy_row["username"] . ' - Needs to be REMOVED from ProxySQL' . PHP_EOL; }
$changes++;
}
}
}
}
if (!$silent) {
if ($action == 'test_sync') {
echo $changes . ' change(s) required' . PHP_EOL;
} else {
echo $changes . ' User(s) modified.' . PHP_EOL;
echo $failed . ' Failed' . PHP_EOL;
}
}
}
if (($changes > 0 && $action == 'sync') || $action == 'load') {
if (mysqli_query($proxy_conn, "LOAD MYSQL USERS TO RUNTIME")) {
if (!$silent) { echo 'LOAD MYSQL USERS TO RUNTIME - SUCCESS' . PHP_EOL; }
} else {
if (!$silent) { echo 'LOAD MYSQL USERS TO RUNTIME - FAILED!!!' . PHP_EOL; }
if ($debug) { echo mysqli_error($proxy_conn) . PHP_EOL; }
}
if (mysqli_query($proxy_conn, "SAVE MYSQL USERS TO DISK")) {
if (!$silent) { echo 'SAVE MYSQL USERS TO DISK - SUCCESS' . PHP_EOL; }
} else {
if (!$silent) { echo 'SAVE MYSQL USERS TO DISK - FAILED!!!' . PHP_EOL; }
if ($debug) { echo mysqli_error($proxy_conn) . PHP_EOL; }
}
}
mysqli_close($proxy_conn);
mysqli_close($db_conn);