fix: rootless podman UID mapping for container data dirs
Some checks failed
Build Archipelago ISO (dev) / build-iso (push) Has been cancelled

create_data_dirs now chowns data directories to the correct mapped
UID for rootless podman (host_uid = 100000 + container_uid).

Previously only Grafana (UID 472) was handled. Now all containers
get the correct ownership:
- Bitcoin Knots: 100101 (container UID 101)
- Grafana: 100472 (UID 472)
- LND: 101000 (UID 1000)
- MariaDB: 100999 (UID 999)
- Postgres: 100070 (UID 70)
- All others: 100000 (UID 0, root)

Without this, containers fail with "Operation not permitted" on
chown during startup because rootless podman restricts UID operations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-29 14:48:37 +01:00
parent d25969e2e5
commit 20289c5bec

View File

@@ -431,11 +431,29 @@ impl RpcHandler {
}
/// Create data directories for volume mounts under /var/lib/archipelago/.
/// Get the mapped host UID for a container's internal UID.
/// Rootless podman maps container UIDs: host_uid = subuid_start + container_uid
/// Default subuid start for archipelago user is 100000.
fn mapped_uid(package_id: &str) -> u32 {
let container_uid = match package_id {
"bitcoin-knots" | "bitcoin" => 101,
"grafana" => 472,
"lnd" => 1000,
"mariadb" | "mysql" => 999,
"postgres" | "btcpay-postgres" | "immich-postgres" | "penpot-postgres" => 70,
_ => 0, // Most containers run as root (UID 0)
};
100000 + container_uid
}
async fn create_data_dirs(&self, package_id: &str, volumes: &[String]) {
let uid = Self::mapped_uid(package_id);
let uid_str = format!("{}:{}", uid, uid);
for volume in volumes {
if let Some(host_path) = volume.split(':').next() {
if host_path.starts_with("/var/lib/archipelago/") {
debug!("Creating directory: {}", host_path);
debug!("Creating directory: {} (owner: {})", host_path, uid_str);
let create_dir = tokio::process::Command::new("sudo")
.args(["mkdir", "-p", host_path])
.output()
@@ -443,13 +461,11 @@ impl RpcHandler {
if let Err(e) = create_dir {
debug!("Failed to create directory {}: {}", host_path, e);
}
// Grafana runs as UID 472 — fix permissions
if package_id == "grafana" && host_path.contains("grafana") {
let _ = tokio::process::Command::new("sudo")
.args(["chown", "-R", "472:472", host_path])
.output()
.await;
}
// Set ownership to the mapped UID for rootless podman
let _ = tokio::process::Command::new("sudo")
.args(["chown", "-R", &uid_str, host_path])
.output()
.await;
}
}
}