mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-26 06:32:49 +00:00
fix(dashboard): MySQL backups with a tcp://, unix:// or pipe:// mysql_host
mysqldump was given --host=tcp --port=//host:port for the tcp:// form the servers accept, so backups failed. Read mysql_host the way the servers connect with it: tcp://host:port (a trailing /database is dropped), unix:// as --socket and pipe:// as a named pipe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -116,16 +116,33 @@ namespace BackupFiles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> MysqldumpArguments(const DumpCommand& command) {
|
std::vector<std::string> MysqldumpArguments(const DumpCommand& command) {
|
||||||
|
// mysql_host as the servers read it (MySQLDatabase::Connect): host, host:port, tcp://host:port, unix://socket or pipe://name
|
||||||
auto host = command.host;
|
auto host = command.host;
|
||||||
std::string port;
|
std::string port;
|
||||||
if (const auto colon = host.find(':'); colon != std::string::npos) {
|
std::string socket;
|
||||||
port = host.substr(colon + 1);
|
bool pipe = false;
|
||||||
host = host.substr(0, colon);
|
if (host.starts_with("unix://")) {
|
||||||
|
socket = host.substr(7);
|
||||||
|
host.clear();
|
||||||
|
} else if (host.starts_with("pipe://")) {
|
||||||
|
socket = host.substr(7);
|
||||||
|
pipe = true;
|
||||||
|
host.clear();
|
||||||
|
} else {
|
||||||
|
if (host.starts_with("tcp://")) host = host.substr(6);
|
||||||
|
// A database after the address (tcp://host:port/db) is not the host's; mysql_database names it
|
||||||
|
if (const auto slash = host.find('/'); slash != std::string::npos) host.resize(slash);
|
||||||
|
if (const auto colon = host.find(':'); colon != std::string::npos) {
|
||||||
|
port = host.substr(colon + 1);
|
||||||
|
host = host.substr(0, colon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::vector<std::string> arguments{ command.program, "--defaults-extra-file=" + command.optionsFile,
|
std::vector<std::string> arguments{ command.program, "--defaults-extra-file=" + command.optionsFile,
|
||||||
"--single-transaction", "--quick", "--routines", "--triggers", "--hex-blob", "--no-tablespaces", "--default-character-set=utf8mb4" };
|
"--single-transaction", "--quick", "--routines", "--triggers", "--hex-blob", "--no-tablespaces", "--default-character-set=utf8mb4" };
|
||||||
if (!host.empty()) arguments.push_back("--host=" + host);
|
if (!host.empty()) arguments.push_back("--host=" + host);
|
||||||
if (!port.empty()) arguments.push_back("--port=" + port);
|
if (!port.empty()) arguments.push_back("--port=" + port);
|
||||||
|
if (pipe) arguments.push_back("--protocol=PIPE");
|
||||||
|
if (!socket.empty()) arguments.push_back("--socket=" + socket);
|
||||||
arguments.push_back("--result-file=" + command.target);
|
arguments.push_back("--result-file=" + command.target);
|
||||||
if (!command.errorFile.empty()) arguments.push_back("--log-error=" + command.errorFile);
|
if (!command.errorFile.empty()) arguments.push_back("--log-error=" + command.errorFile);
|
||||||
arguments.push_back(command.database);
|
arguments.push_back(command.database);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace BackupFiles {
|
|||||||
struct DumpCommand {
|
struct DumpCommand {
|
||||||
std::string program;
|
std::string program;
|
||||||
std::string optionsFile;
|
std::string optionsFile;
|
||||||
std::string host; // host or host:port
|
std::string host; // mysql_host: host, host:port, tcp://host:port, unix://socket or pipe://name
|
||||||
std::string database;
|
std::string database;
|
||||||
std::string target;
|
std::string target;
|
||||||
std::string errorFile; // mysqldump's messages; never mixed into the dump, where they would break a restore
|
std::string errorFile; // mysqldump's messages; never mixed into the dump, where they would break a restore
|
||||||
|
|||||||
@@ -121,3 +121,32 @@ TEST(BackupFilesTests, MysqldumpArgumentsAreAVector) {
|
|||||||
// Passed as one literal argument, never interpreted
|
// Passed as one literal argument, never interpreted
|
||||||
EXPECT_EQ(arguments.back(), "dlu$(touch x)");
|
EXPECT_EQ(arguments.back(), "dlu$(touch x)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mysql_host in every form the servers connect with
|
||||||
|
TEST(BackupFilesTests, MysqldumpArgumentsReadEveryHostForm) {
|
||||||
|
const auto has = [](const std::vector<std::string>& arguments, const std::string& argument) {
|
||||||
|
return std::find(arguments.begin(), arguments.end(), argument) != arguments.end();
|
||||||
|
};
|
||||||
|
const auto dump = [](const std::string& host) { return BackupFiles::MysqldumpArguments({ "mysqldump", "/tmp/opt", host, "dlu", "/b/x", "" }); };
|
||||||
|
|
||||||
|
auto arguments = dump("tcp://10.0.0.5:3307");
|
||||||
|
EXPECT_TRUE(has(arguments, "--host=10.0.0.5"));
|
||||||
|
EXPECT_TRUE(has(arguments, "--port=3307"));
|
||||||
|
|
||||||
|
arguments = dump("tcp://db.local:3306/dlu");
|
||||||
|
EXPECT_TRUE(has(arguments, "--host=db.local"));
|
||||||
|
EXPECT_TRUE(has(arguments, "--port=3306"));
|
||||||
|
|
||||||
|
arguments = dump("db.local");
|
||||||
|
EXPECT_TRUE(has(arguments, "--host=db.local"));
|
||||||
|
EXPECT_FALSE(std::any_of(arguments.begin(), arguments.end(), [](const std::string& a) { return a.starts_with("--port="); }));
|
||||||
|
|
||||||
|
arguments = dump("unix:///run/mysqld/mysqld.sock");
|
||||||
|
EXPECT_TRUE(has(arguments, "--socket=/run/mysqld/mysqld.sock"));
|
||||||
|
EXPECT_FALSE(std::any_of(arguments.begin(), arguments.end(), [](const std::string& a) { return a.starts_with("--host=") || a.starts_with("--port="); }));
|
||||||
|
|
||||||
|
arguments = dump("pipe://MySQL");
|
||||||
|
EXPECT_TRUE(has(arguments, "--protocol=PIPE"));
|
||||||
|
EXPECT_TRUE(has(arguments, "--socket=MySQL"));
|
||||||
|
EXPECT_EQ(arguments.back(), "dlu");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user