Skip to content

Commit 9cb48c6

Browse files
committed
refactor(installers): 修改安装路径为当前目录下的server目录
修改nginx、redis、pgsql、mysql和docker安装器的安装路径,从绝对路径"/www/server"改为相对当前工作目录的"server"子目录 重构docker安装逻辑,改为使用静态二进制文件安装方式
1 parent d3e7b5a commit 9cb48c6

File tree

5 files changed

+169
-170
lines changed

5 files changed

+169
-170
lines changed

src/models/system/installers/docker.rs

Lines changed: 137 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -6,197 +6,172 @@ use super::manager::{OsManager, PackageManager};
66
pub struct DockerInstaller;
77

88
impl DockerInstaller {
9-
pub async fn install(_version: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
9+
pub async fn install(version: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
1010
println!("Starting Docker installation...");
11-
// Note: Docker version argument is often ignored in standard repo installs unless specifically requested.
12-
// For simplicity, we install the latest stable version from official repos.
11+
12+
// 1. Install System Dependencies
13+
Self::install_system_dependencies().await?;
14+
15+
// 2. Download Static Binaries
16+
// If version is "latest" or empty, we default to a known stable version to ensure URL validity
17+
// Or we could try to resolve "latest", but for static builds, explicit versions are safer.
18+
let docker_version = if version.is_empty() || version == "latest" {
19+
"27.3.1" // Hardcoded recent stable version
20+
} else {
21+
version
22+
};
1323

14-
let pm = OsManager::detect_package_manager();
15-
match pm {
16-
PackageManager::Yum => Self::install_yum().await?,
17-
PackageManager::Apt => Self::install_apt().await?,
18-
PackageManager::Unknown => return Err("Unsupported OS for Docker installation".into()),
24+
println!("Downloading Docker {} static binaries...", docker_version);
25+
let download_url = format!("https://download.docker.com/linux/static/stable/x86_64/docker-{}.tgz", docker_version);
26+
27+
let temp_dir = std::env::temp_dir().join("rustpanel_docker");
28+
if temp_dir.exists() {
29+
fs::remove_dir_all(&temp_dir).await?;
30+
}
31+
fs::create_dir_all(&temp_dir).await?;
32+
33+
let tarball_path = temp_dir.join(format!("docker-{}.tgz", docker_version));
34+
OsManager::download_file(&download_url, &tarball_path).await?;
35+
36+
// 3. Extract
37+
OsManager::extract_tarball(&tarball_path, &temp_dir).await?;
38+
// Structure is temp_dir/docker/{dockerd, docker, ...}
39+
40+
// 4. Install to Server Directory
41+
let current_dir = std::env::current_dir()?;
42+
let install_base = current_dir.join("server").join("docker"); // e.g., /rust/RustPanel/server/docker
43+
let bin_dir = install_base.join("bin");
44+
let data_dir = install_base.join("data");
45+
let config_dir = install_base.join("config");
46+
47+
// Clean old if exists
48+
if install_base.exists() {
49+
// Stop service first just in case
50+
let _ = Command::new("systemctl").arg("stop").arg("docker").status().await;
51+
fs::remove_dir_all(&install_base).await?;
1952
}
2053

21-
// Enable and Start Docker
22-
println!("Starting Docker service...");
23-
let _ = Command::new("systemctl").arg("enable").arg("docker").status().await;
24-
let status = Command::new("systemctl").arg("start").arg("docker").status().await?;
25-
26-
if !status.success() {
27-
return Err("Failed to start Docker service".into());
54+
fs::create_dir_all(&bin_dir).await?;
55+
fs::create_dir_all(&data_dir).await?;
56+
fs::create_dir_all(&config_dir).await?;
57+
58+
// Move binaries
59+
let extracted_docker_dir = temp_dir.join("docker");
60+
let mut entries = fs::read_dir(&extracted_docker_dir).await?;
61+
while let Some(entry) = entries.next_entry().await? {
62+
let path = entry.path();
63+
if path.is_file() {
64+
let file_name = path.file_name().unwrap();
65+
fs::rename(&path, bin_dir.join(file_name)).await?;
66+
}
2867
}
2968

30-
println!("Docker installed successfully!");
69+
// 5. Configure daemon.json
70+
println!("Configuring Docker...");
71+
let daemon_json_path = config_dir.join("daemon.json");
72+
let daemon_config = format!(r#"
73+
{{
74+
"data-root": "{}"
75+
}}
76+
"#, data_dir.display().to_string().replace("\\", "/")); // JSON needs forward slashes or escaped backslashes
77+
78+
fs::write(&daemon_json_path, daemon_config).await?;
79+
80+
// 6. Setup Service
81+
Self::setup_service(&bin_dir, &daemon_json_path).await?;
82+
83+
// 7. Cleanup
84+
let _ = fs::remove_dir_all(&temp_dir).await;
85+
86+
println!("Docker installed successfully to {}!", install_base.display());
3187
Ok(())
3288
}
3389

3490
pub async fn uninstall() -> Result<(), Box<dyn Error + Send + Sync>> {
3591
println!("Uninstalling Docker...");
3692

37-
let pm = OsManager::detect_package_manager();
38-
3993
// Stop service
4094
let _ = Command::new("systemctl").arg("stop").arg("docker").status().await;
4195
let _ = Command::new("systemctl").arg("disable").arg("docker").status().await;
42-
43-
match pm {
44-
PackageManager::Yum => {
45-
let pkgs = vec![
46-
"docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin",
47-
"docker", "docker-client", "docker-client-latest", "docker-common", "docker-latest", "docker-latest-logrotate", "docker-logrotate", "docker-engine"
48-
];
49-
Command::new("yum").arg("remove").arg("-y").args(&pkgs).status().await?;
50-
}
51-
PackageManager::Apt => {
52-
let pkgs = vec![
53-
"docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin",
54-
"docker.io", "docker-doc", "docker-compose", "podman-docker", "containerd", "runc"
55-
];
56-
Command::new("apt-get").arg("purge").arg("-y").args(&pkgs).status().await?;
57-
}
58-
PackageManager::Unknown => return Err("Unsupported OS".into()),
96+
97+
let service_file = std::path::Path::new("/etc/systemd/system/docker.service");
98+
if service_file.exists() {
99+
fs::remove_file(service_file).await?;
100+
let _ = Command::new("systemctl").arg("daemon-reload").status().await;
59101
}
60102

61-
// Cleanup directories
62-
let paths = vec!["/var/lib/docker", "/var/lib/containerd", "/etc/docker"];
63-
for path in paths {
64-
let p = std::path::Path::new(path);
65-
if p.exists() {
66-
let _ = fs::remove_dir_all(p).await;
67-
}
103+
// Remove files
104+
let current_dir = std::env::current_dir()?;
105+
let install_base = current_dir.join("server").join("docker");
106+
if install_base.exists() {
107+
fs::remove_dir_all(install_base).await?;
68108
}
69109

70110
println!("Docker uninstalled.");
71111
Ok(())
72112
}
73113

74-
async fn install_yum() -> Result<(), Box<dyn Error + Send + Sync>> {
75-
// 1. Remove old versions
76-
let old_pkgs = vec![
77-
"docker", "docker-client", "docker-client-latest", "docker-common", "docker-latest", "docker-latest-logrotate", "docker-logrotate", "docker-engine"
78-
];
79-
let _ = Command::new("yum").arg("remove").arg("-y").args(&old_pkgs).status().await;
80-
81-
// 2. Install utils
82-
OsManager::install_dependencies(&["yum-utils"]).await?;
83-
84-
// 3. Add Repo
85-
println!("Adding Docker repo...");
86-
let status = Command::new("yum-config-manager")
87-
.arg("--add-repo")
88-
.arg("https://download.docker.com/linux/centos/docker-ce.repo")
89-
.status()
90-
.await?;
91-
92-
if !status.success() {
93-
// Try to handle RedHat/Fedora if CentOS repo fails, or just proceed hoping it worked or user has repo.
94-
// But let's assume standard CentOS/RHEL/Alinux/etc compatibility.
95-
return Err("Failed to add Docker repository".into());
96-
}
97-
98-
// 4. Install Docker
99-
println!("Installing Docker packages...");
100-
let pkgs = vec!["docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin"];
101-
OsManager::install_dependencies(&pkgs).await?;
102-
103-
Ok(())
114+
async fn install_system_dependencies() -> Result<(), Box<dyn Error + Send + Sync>> {
115+
let pm = OsManager::detect_package_manager();
116+
let pkgs = match pm {
117+
PackageManager::Yum => vec![
118+
"iptables", "git", "xz", "procps" // Basic requirements
119+
],
120+
PackageManager::Apt => vec![
121+
"iptables", "git", "xz-utils", "procps", "iproute2"
122+
],
123+
PackageManager::Unknown => return Err("Unsupported OS".into()),
124+
};
125+
OsManager::install_dependencies(&pkgs).await
104126
}
105127

106-
async fn install_apt() -> Result<(), Box<dyn Error + Send + Sync>> {
107-
// 1. Remove old versions
108-
let old_pkgs = vec![
109-
"docker.io", "docker-doc", "docker-compose", "podman-docker", "containerd", "runc"
110-
];
111-
let _ = Command::new("apt-get").arg("remove").arg("-y").args(&old_pkgs).status().await;
112-
113-
// 2. Install utils
114-
OsManager::install_dependencies(&["ca-certificates", "curl", "gnupg"]).await?;
115-
116-
// 3. Add GPG Key
117-
println!("Adding Docker GPG key...");
118-
fs::create_dir_all("/etc/apt/keyrings").await?;
119-
let keyring_path = "/etc/apt/keyrings/docker.gpg";
120-
// Remove old if exists
121-
if std::path::Path::new(keyring_path).exists() {
122-
let _ = fs::remove_file(keyring_path).await;
123-
}
124-
125-
// Curl pipe to gpg --dearmor
126-
// Since we are in Rust, let's use Command chain or just download and shell out for simplicity of pipe
127-
let status = Command::new("bash")
128-
.arg("-c")
129-
.arg("curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg")
130-
.status()
131-
.await?;
128+
async fn setup_service(bin_dir: &std::path::Path, config_path: &std::path::Path) -> Result<(), Box<dyn Error + Send + Sync>> {
129+
let dockerd_path = bin_dir.join("dockerd");
132130

133-
if !status.success() {
134-
// Fallback for Debian if ubuntu fails?
135-
// Ideally we should detect distro codename.
136-
// But let's try generic approach or check /etc/os-release
137-
// For now, assume Ubuntu/Debian compatible.
138-
return Err("Failed to add Docker GPG key".into());
139-
}
140-
let _ = Command::new("chmod").arg("a+r").arg(keyring_path).status().await;
141-
142-
// 4. Add Repo
143-
println!("Adding Docker repository...");
144-
// Get codename
145-
let output = Command::new("lsb_release").arg("-cs").output().await;
146-
let codename = if let Ok(out) = output {
147-
String::from_utf8_lossy(&out.stdout).trim().to_string()
148-
} else {
149-
// Fallback: cat /etc/os-release
150-
"jammy".to_string() // unsafe assumption, but standard on many. Ideally parse /etc/os-release.
151-
};
131+
// Add bin_dir to PATH in environment or just absolute path
132+
// We need to make sure 'containerd' and 'runc' are found.
133+
// Docker static bundle puts them all in same dir.
134+
// dockerd needs them in PATH.
152135

153-
// Better codename detection
154-
let codename = Self::get_distro_codename().await.unwrap_or("jammy".to_string());
155-
156-
// Determine if ubuntu or debian
157-
let os_release = fs::read_to_string("/etc/os-release").await.unwrap_or_default().to_lowercase();
158-
let repo_url = if os_release.contains("debian") {
159-
"https://download.docker.com/linux/debian"
160-
} else {
161-
"https://download.docker.com/linux/ubuntu"
162-
};
163-
164-
let repo_line = format!(
165-
"deb [arch=\"amd64\" signed-by={}] {} {} stable",
166-
keyring_path, repo_url, codename
167-
);
136+
let service_content = format!(r#"
137+
[Unit]
138+
Description=Docker Application Container Engine
139+
Documentation=https://docs.docker.com
140+
After=network-online.target firewalld.service
141+
Wants=network-online.target
142+
143+
[Service]
144+
Type=notify
145+
Environment="PATH={}:/usr/bin:/usr/local/bin"
146+
ExecStart={} --config-file {}
147+
ExecReload=/bin/kill -s HUP $MAINPID
148+
TimeoutSec=0
149+
RestartSec=2
150+
Restart=always
151+
StartLimitBurst=3
152+
StartLimitInterval=60s
153+
LimitNOFILE=infinity
154+
LimitNPROC=infinity
155+
LimitCORE=infinity
156+
TasksMax=infinity
157+
Delegate=yes
158+
KillMode=process
159+
OOMScoreAdjust=-500
160+
161+
[Install]
162+
WantedBy=multi-user.target
163+
"#, bin_dir.display(), dockerd_path.display(), config_path.display());
164+
165+
fs::write("/etc/systemd/system/docker.service", service_content).await?;
168166

169-
fs::write("/etc/apt/sources.list.d/docker.list", repo_line).await?;
170-
171-
// 5. Update and Install
172-
println!("Updating apt cache...");
173-
let _ = Command::new("apt-get").arg("update").status().await;
174-
175-
println!("Installing Docker packages...");
176-
let pkgs = vec!["docker-ce", "docker-ce-cli", "containerd.io", "docker-buildx-plugin", "docker-compose-plugin"];
177-
OsManager::install_dependencies(&pkgs).await?;
178-
179-
Ok(())
180-
}
181-
182-
async fn get_distro_codename() -> Option<String> {
183-
// Try lsb_release
184-
if let Ok(output) = Command::new("lsb_release").arg("-cs").output().await {
185-
if output.status.success() {
186-
return Some(String::from_utf8_lossy(&output.stdout).trim().to_string());
187-
}
188-
}
167+
let _ = Command::new("systemctl").arg("daemon-reload").status().await;
168+
let _ = Command::new("systemctl").arg("enable").arg("docker").status().await;
169+
let status = Command::new("systemctl").arg("start").arg("docker").status().await?;
189170

190-
// Try parsing /etc/os-release
191-
if let Ok(content) = fs::read_to_string("/etc/os-release").await {
192-
for line in content.lines() {
193-
if line.starts_with("VERSION_CODENAME=") {
194-
return Some(line.trim_start_matches("VERSION_CODENAME=").trim_matches('"').to_string());
195-
}
196-
}
197-
// Fallback for systems without VERSION_CODENAME (like older CentOS, though we are in apt block)
198-
// Debian usually has VERSION_CODENAME
171+
if !status.success() {
172+
return Err("Failed to start Docker service".into());
199173
}
200-
None
174+
175+
Ok(())
201176
}
202177
}

src/models/system/installers/mysql.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ impl MysqlInstaller {
3535
OsManager::extract_tarball(&tarball_path, &temp_dir).await?;
3636

3737
// 5. Move to install path
38-
let install_path = Path::new("/www/server/mysql");
38+
let current_dir = std::env::current_dir()?;
39+
let install_path_buf = current_dir.join("server").join("mysql");
40+
let install_path = install_path_buf.as_path();
41+
3942
if install_path.exists() {
4043
// Backup or fail? For now, we assume fresh install or overwrite.
4144
// But mv will fail if dir exists.
@@ -121,7 +124,10 @@ bind-address = 127.0.0.1
121124
let _ = Command::new("systemctl").arg("daemon-reload").status().await;
122125
}
123126

124-
let install_path = Path::new("/www/server/mysql");
127+
let current_dir = std::env::current_dir()?;
128+
let install_path_buf = current_dir.join("server").join("mysql");
129+
let install_path = install_path_buf.as_path();
130+
125131
if install_path.exists() {
126132
fs::remove_dir_all(install_path).await?;
127133
}

src/models/system/installers/nginx.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ impl NginxInstaller {
3535

3636
// 5. Configure
3737
println!("Configuring...");
38-
let install_path = Path::new("/www/server/nginx");
38+
let current_dir = std::env::current_dir()?;
39+
let install_path_buf = current_dir.join("server").join("nginx");
40+
let install_path = install_path_buf.as_path();
41+
3942
if !install_path.exists() {
4043
fs::create_dir_all(install_path).await?;
4144
}
@@ -115,7 +118,10 @@ impl NginxInstaller {
115118
}
116119

117120
// Remove files
118-
let install_path = Path::new("/www/server/nginx");
121+
let current_dir = std::env::current_dir()?;
122+
let install_path_buf = current_dir.join("server").join("nginx");
123+
let install_path = install_path_buf.as_path();
124+
119125
if install_path.exists() {
120126
fs::remove_dir_all(install_path).await?;
121127
}

0 commit comments

Comments
 (0)