fix(rootfs): give fresh rootfs files the host's resolver

The engine proxies guest sockets to the host's stack, so the host's
resolv.conf works in the machine as-is, loopback stub included. The
images ship no usable resolver, so without this every fetch inside
the guest fails to resolve.
This commit is contained in:
Valentin Haudiquet committed 2026-10-28 00:43:56 +01:00
1 parent a91c1b6b51
commit 7d9dc6650e
1 file changed
+37
+37
View File
@@ -288,6 +288,7 @@ fn extract_prepared(
log::debug!("Extracting to: {}", rootfs.display()); log::debug!("Extracting to: {}", rootfs.display());
extract_tarball(&cache_path, &rootfs, progress)?; extract_tarball(&cache_path, &rootfs, progress)?;
provision_resolver(&rootfs);
Ok(PreparedRootfs { Ok(PreparedRootfs {
rootfs: temp, rootfs: temp,
@@ -296,6 +297,42 @@ fn extract_prepared(
}) })
} }
/// Give the guest the host's resolver: the engine proxies guest
/// sockets to the host's stack, so a nameserver line that works on the
/// host works in the machine, loopback stub included. Without it the
/// guest has whatever the image shipped, which is usually nothing.
/// Best effort: a rootfs with its own resolver config keeps it.
fn provision_resolver(rootfs: &Path) {
let host = match std::fs::read_to_string("/etc/resolv.conf") {
Ok(s) if !s.trim().is_empty() => s,
Ok(_) => {
log::debug!("host /etc/resolv.conf is empty; leaving the image's in place");
return;
}
Err(e) => {
log::debug!(
"no host /etc/resolv.conf ({}); leaving the image's in place",
e
);
return;
}
};
let target = rootfs.join("etc/resolv.conf");
if let Err(e) = std::fs::remove_file(&target) {
if e.kind() != std::io::ErrorKind::NotFound {
log::debug!("could not clear {}: {}", target.display(), e);
return;
}
}
if let Some(parent) = target.parent() {
let _ = std::fs::create_dir_all(parent);
}
match std::fs::write(&target, host) {
Ok(()) => log::debug!("provisioned the host resolver into {}", target.display()),
Err(e) => log::debug!("could not write {}: {}", target.display(), e),
}
}
/// Write a tarball of `rootfs` at `dest`, compressed according to dest's /// Write a tarball of `rootfs` at `dest`, compressed according to dest's
/// extension (.tar.gz, .tar.xz, .tar.zst, plain .tar), atomically via a /// extension (.tar.gz, .tar.xz, .tar.zst, plain .tar), atomically via a
/// `.partial` file. /// `.partial` file.