From ff47024d9a081eb26591e61c9cb6472bd43bb1d1 Mon Sep 17 00:00:00 2001 From: Charles GTE Date: Fri, 21 Aug 2026 19:05:47 +0200 Subject: [PATCH] fix: mysql localhost --- src/domain/mariadb/backup.rs | 5 ++- src/domain/mariadb/connection.rs | 8 ++--- src/domain/mariadb/ping.rs | 8 ++--- src/domain/mariadb/restore.rs | 15 ++------- src/domain/mysql/backup.rs | 6 ++-- src/domain/mysql/connection.rs | 31 +++++++++++++++---- src/domain/mysql/mod.rs | 2 +- src/domain/mysql/ping.rs | 8 ++--- src/domain/mysql/restore.rs | 15 ++------- src/tests/domain/mysql.rs | 52 ++++++++++++++++++++++++++++++++ 10 files changed, 94 insertions(+), 56 deletions(-) diff --git a/src/domain/mariadb/backup.rs b/src/domain/mariadb/backup.rs index a466df6..23200ba 100644 --- a/src/domain/mariadb/backup.rs +++ b/src/domain/mariadb/backup.rs @@ -1,5 +1,6 @@ use crate::domain::mariadb::connection::{select_mariadb_path, server_version}; use crate::services::backup::logger::JobLogger; +use crate::domain::mysql::connection::connection_args; use crate::services::config::DatabaseConfig; use anyhow::{Context, Result}; use std::collections::HashMap; @@ -42,9 +43,7 @@ pub async fn run( let start = Instant::now(); let output = Command::new("mariadb-dump") - .arg("--host").arg(&cfg.host) - .arg("--port").arg(cfg.port.to_string()) - .arg("--user").arg(&cfg.username) + .args(connection_args(&cfg)) .arg("--routines") .arg("--events") .arg("--triggers") diff --git a/src/domain/mariadb/connection.rs b/src/domain/mariadb/connection.rs index 11015e0..1ce5ce6 100644 --- a/src/domain/mariadb/connection.rs +++ b/src/domain/mariadb/connection.rs @@ -1,16 +1,12 @@ use std::path::PathBuf; +use crate::domain::mysql::connection::connection_args; use crate::services::config::DatabaseConfig; use anyhow::Result; use std::process::Command; pub async fn server_version(cfg: &DatabaseConfig) -> Result { let output = Command::new("mariadb") - .arg("--host") - .arg(&cfg.host) - .arg("--port") - .arg(cfg.port.to_string()) - .arg("--user") - .arg(&cfg.username) + .args(connection_args(cfg)) .arg("-e") .arg("SELECT VERSION();") .env("MYSQL_PWD", &cfg.password) diff --git a/src/domain/mariadb/ping.rs b/src/domain/mariadb/ping.rs index eec8013..2d0dfae 100644 --- a/src/domain/mariadb/ping.rs +++ b/src/domain/mariadb/ping.rs @@ -1,3 +1,4 @@ +use crate::domain::mysql::connection::connection_args; use crate::services::config::DatabaseConfig; use std::collections::HashMap; use tokio::process::Command; @@ -5,12 +6,7 @@ use tokio::time::{Duration, timeout}; pub async fn run(cfg: DatabaseConfig, env: HashMap) -> anyhow::Result { let mut cmd = Command::new("mysqladmin"); - cmd.arg("--host") - .arg(cfg.host) - .arg("--port") - .arg(cfg.port.to_string()) - .arg("--user") - .arg(cfg.username) + cmd.args(connection_args(&cfg)) .arg("ping") .envs(env); diff --git a/src/domain/mariadb/restore.rs b/src/domain/mariadb/restore.rs index d6fc555..c03713b 100644 --- a/src/domain/mariadb/restore.rs +++ b/src/domain/mariadb/restore.rs @@ -1,4 +1,5 @@ use crate::services::backup::logger::JobLogger; +use crate::domain::mysql::connection::connection_args; use crate::services::config::DatabaseConfig; use anyhow::{Context, Result}; use std::fs::File; @@ -21,12 +22,7 @@ pub async fn run(cfg: DatabaseConfig, restore_file: PathBuf, logger: Arc Vec { + let protocol = cfg + .options + .get("protocol") + .and_then(|v| v.as_str()) + .unwrap_or("tcp"); + + let mut args = vec![ + format!("--protocol={}", protocol), + "--host".to_string(), + cfg.host.clone(), + "--port".to_string(), + cfg.port.to_string(), + "--user".to_string(), + cfg.username.clone(), + ]; + + if let Some(socket) = cfg.options.get("socket").and_then(|v| v.as_str()) { + args.push(format!("--socket={}", socket)); + } + + args +} + pub async fn server_version(cfg: &DatabaseConfig) -> Result { let output = Command::new("mysql") - .arg("--host") - .arg(&cfg.host) - .arg("--port") - .arg(cfg.port.to_string()) - .arg("--user") - .arg(&cfg.username) + .args(connection_args(cfg)) .arg("-e") .arg("SELECT VERSION();") .env("MYSQL_PWD", &cfg.password) diff --git a/src/domain/mysql/mod.rs b/src/domain/mysql/mod.rs index 33dd5f4..e604ebe 100644 --- a/src/domain/mysql/mod.rs +++ b/src/domain/mysql/mod.rs @@ -1,5 +1,5 @@ pub mod backup; -mod connection; +pub mod connection; pub mod database; mod ping; mod restore; diff --git a/src/domain/mysql/ping.rs b/src/domain/mysql/ping.rs index 3521fee..cbd74c0 100644 --- a/src/domain/mysql/ping.rs +++ b/src/domain/mysql/ping.rs @@ -1,3 +1,4 @@ +use crate::domain::mysql::connection::connection_args; use crate::services::config::DatabaseConfig; use std::collections::HashMap; use tokio::process::Command; @@ -5,12 +6,7 @@ use tokio::time::{Duration, timeout}; pub async fn run(cfg: DatabaseConfig, env: HashMap) -> anyhow::Result { let mut cmd = Command::new("mariadb-admin"); - cmd.arg("--host") - .arg(cfg.host) - .arg("--port") - .arg(cfg.port.to_string()) - .arg("--user") - .arg(cfg.username) + cmd.args(connection_args(&cfg)) .arg("ping") .envs(env); diff --git a/src/domain/mysql/restore.rs b/src/domain/mysql/restore.rs index 955b4c6..71777d1 100644 --- a/src/domain/mysql/restore.rs +++ b/src/domain/mysql/restore.rs @@ -1,4 +1,5 @@ use crate::services::backup::logger::JobLogger; +use crate::domain::mysql::connection::connection_args; use crate::services::config::DatabaseConfig; use anyhow::{Context, Result}; use std::fs::File; @@ -21,12 +22,7 @@ pub async fn run(cfg: DatabaseConfig, restore_file: PathBuf, logger: Arc DatabaseConfig { + DatabaseConfig { + name: "my-db".to_string(), + database: "my-db".to_string(), + db_type: DbType::Mysql, + username: "my-db-user".to_string(), + password: "my-db-password".to_string(), + port: 3306, + host: "localhost".to_string(), + generated_id: "16678159-ff7e-4c97-8c83-0adeff214681".to_string(), + path: "".to_string(), + max_packet_size: "512M".to_string(), + volume_name: "".to_string(), + container_name: None, + options: serde_json::from_value(options).unwrap(), + } +} + +#[test] +fn connection_args_force_tcp_for_localhost() { + // A `localhost` host makes the clients pick a Unix socket and ignore `--port`, + // which breaks databases reached through an SSH tunnel. + let cfg = tunnelled_config(serde_json::json!({})); + + assert_eq!( + connection_args(&cfg), + vec![ + "--protocol=tcp", + "--host", + "localhost", + "--port", + "3306", + "--user", + "my-db-user", + ] + ); +} + +#[test] +fn connection_args_allow_socket_opt_in() { + let cfg = tunnelled_config(serde_json::json!({ + "protocol": "socket", + "socket": "/var/run/mysqld/mysqld.sock", + })); + + let args = connection_args(&cfg); + + assert_eq!(args[0], "--protocol=socket"); + assert_eq!(args.last().unwrap(), "--socket=/var/run/mysqld/mysqld.sock"); +}