Enhance development workflow and deployment practices for Archipelago

- Updated the Development-Workflow documentation to clarify deployment strategy, emphasizing direct deployment to the live system for testing.
- Added detailed instructions for the deployment command, including syncing code, building frontend and backend, and restarting services.
- Improved SSH key management section to assist with authentication issues.
- Expanded the testing workflow to include steps for checking logs and syncing changes back to the ISO build.
- Updated the ISO build integration section to ensure system-level changes are captured for future builds.
- Refactored various sections for clarity and completeness, including deployment paths and system configuration files.
This commit is contained in:
Dorian
2026-02-01 13:24:03 +00:00
parent 00d1af12f0
commit 34fc06726e
28 changed files with 1248 additions and 285 deletions
+92 -12
View File
@@ -55,9 +55,13 @@ pub struct PodmanClient {
impl PodmanClient {
pub fn new(user: String) -> Self {
// If running as root, use root podman context
let is_root = std::env::var("USER").unwrap_or_default() == "root" ||
std::env::var("HOME").unwrap_or_default() == "/root";
Self {
_user: user,
rootless: true,
rootless: !is_root,
}
}
@@ -315,25 +319,101 @@ impl PodmanClient {
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
log::error!("Podman list failed: {}", stderr);
return Err(anyhow::anyhow!("Failed to list containers: {}", stderr));
}
let json = String::from_utf8_lossy(&output.stdout);
let containers: Vec<serde_json::Value> = serde_json::from_str(&json)
.context("Failed to parse container list")?;
log::debug!("Podman JSON output ({} bytes): {}", json.len(),
if json.len() > 200 { &json[..200] } else { &json });
// Podman can return either a JSON array or NDJSON (newline-delimited JSON)
let mut result = Vec::new();
for container in containers {
result.push(ContainerStatus {
id: container["Id"].as_str().unwrap_or("").to_string(),
name: container["Names"][0].as_str().unwrap_or("").to_string(),
state: ContainerState::from(container["State"].as_str().unwrap_or("unknown")),
image: container["Image"].as_str().unwrap_or("").to_string(),
created: container["Created"].as_str().unwrap_or("").to_string(),
ports: vec![],
});
// Try parsing as a JSON array first
if let Ok(containers) = serde_json::from_str::<Vec<serde_json::Value>>(&json) {
log::debug!("Parsed as JSON array with {} items", containers.len());
for container in containers {
// Handle both Names as array and Names as string
let name = if let Some(names_array) = container["Names"].as_array() {
names_array.get(0).and_then(|v| v.as_str()).unwrap_or("").to_string()
} else {
container["Names"].as_str().unwrap_or("").to_string()
};
// Parse ports from the Ports array
let ports = if let Some(ports_array) = container["Ports"].as_array() {
ports_array.iter().filter_map(|port| {
// Podman format: {"host_ip":"","container_port":8123,"host_port":8123,"range":1,"protocol":"tcp"}
if let (Some(host_port), Some(container_port), Some(protocol)) = (
port["host_port"].as_u64(),
port["container_port"].as_u64(),
port["protocol"].as_str()
) {
Some(format!("0.0.0.0:{}->{}/{}", host_port, container_port, protocol))
} else {
None
}
}).collect()
} else {
vec![]
};
result.push(ContainerStatus {
id: container["Id"].as_str().unwrap_or("").to_string(),
name,
state: ContainerState::from(container["State"].as_str().unwrap_or("unknown")),
image: container["Image"].as_str().unwrap_or("").to_string(),
created: container["Created"].as_str().unwrap_or("").to_string(),
ports,
});
}
} else {
log::debug!("Failed to parse as JSON array, trying NDJSON");
// Try parsing as NDJSON (newline-delimited JSON)
for line in json.lines() {
if line.trim().is_empty() {
continue;
}
if let Ok(container) = serde_json::from_str::<serde_json::Value>(line) {
// Handle both Names as array and Names as string
let name = if let Some(names_array) = container["Names"].as_array() {
names_array.get(0).and_then(|v| v.as_str()).unwrap_or("").to_string()
} else {
container["Names"].as_str().unwrap_or("").to_string()
};
// Parse ports from the Ports array
let ports = if let Some(ports_array) = container["Ports"].as_array() {
ports_array.iter().filter_map(|port| {
if let (Some(host_port), Some(container_port), Some(protocol)) = (
port["host_port"].as_u64(),
port["container_port"].as_u64(),
port["protocol"].as_str()
) {
Some(format!("0.0.0.0:{}->{}/{}", host_port, container_port, protocol))
} else {
None
}
}).collect()
} else {
vec![]
};
result.push(ContainerStatus {
id: container["Id"].as_str().unwrap_or("").to_string(),
name,
state: ContainerState::from(container["State"].as_str().unwrap_or("unknown")),
image: container["Image"].as_str().unwrap_or("").to_string(),
created: container["Created"].as_str().unwrap_or("").to_string(),
ports,
});
}
}
}
log::debug!("Returning {} containers", result.len());
Ok(result)
}
}