Skip to content

fix(spur-net): honor requested image architecture - #438

Open
hnotshe wants to merge 1 commit into
ROCm:mainfrom
hnotshe:fix/image-import-arch
Open

fix(spur-net): honor requested image architecture#438
hnotshe wants to merge 1 commit into
ROCm:mainfrom
hnotshe:fix/image-import-arch

Conversation

@hnotshe

@hnotshe hnotshe commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Closes #343.

Thread the requested image architecture through the native OCI pull path and use it when resolving multi-architecture manifest lists. Host architecture names are normalized to their OCI equivalents, and missing variants now report the requested architecture.

Imported squashfs artifacts record their architecture so an existing image for another architecture is rebuilt instead of silently reused. Replacement is staged so a failed pull does not destroy the existing artifact.

Tested with workspace Clippy and the full locked test suite on Linux.

@hnotshe
hnotshe marked this pull request as ready for review July 14, 2026 21:59

@shiv-tyagi shiv-tyagi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hnotshe

hnotshe commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@shiv-tyagi Thanks for the review! All checks are green -- could I please get some help merging?

@yansun1996

Copy link
Copy Markdown
Member

Solid change. The staged-replacement design is careful — same-filesystem rename, the existing artifact is left intact on a failed pull, and sidecar-less artifacts are safely rebuilt once — and the new pure functions are well-tested and network-free. No blocking issues; notes inline.

Two items are pre-existing (not regressions from this PR), flagged just for context: the layer-extraction gate media_type.contains("gzip") || digest.starts_with("sha256:") effectively forces gzip on every layer, so a non-gzip/zstd layer would silently produce a partial rootfs; and arm v6/v7 variants aren't disambiguated since Platform doesn't deserialize variant.

// Clean up temp dir
let finalize_result = (|| -> anyhow::Result<()> {
std::fs::write(&staged_arch_path, oci_architecture(arch))?;
std::fs::rename(&staged_sqsh_path, &sqsh_path)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The install is two separate renames (.sqsh then .sqsh.arch). A crash between them leaves the new payload with a stale-or-missing arch sidecar. It is self-healing (the next pull rebuilds), but since the sidecar is the source of truth for the "rebuild on arch change" decision, writing the metadata first and renaming the payload in last (payload as the commit point) would make "sqsh present implies arch recorded" hold.


// Clean up temp dir
let finalize_result = (|| -> anyhow::Result<()> {
std::fs::write(&staged_arch_path, oci_architecture(arch))?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sidecar is written as the requested arch unconditionally. On the single-manifest path (a registry returning an image manifest directly rather than an index), no platform verification runs, so the recorded arch could be wrong and defeat the rebuild-on-arch-change guard. Verifying the fetched manifest's platform (or documenting the limitation) would close this.

pub async fn import_image(uri: &str) -> anyhow::Result<PathBuf> {
let dir = image_dir();
spur_net::pull_image(uri, &dir).await
spur_net::pull_image(uri, &dir, std::env::consts::ARCH).await

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requested arch is honored on the pull path, but import_image here hardcodes host arch and resolve_image matches purely by filename (never reading the .sqsh.arch sidecar) — so a cross-arch artifact could be launched on the wrong host unchecked. Likely out of scope for this PR's title, but worth a follow-up; the sidecar added here is the enabling primitive for that check.


// Create temp directory for rootfs assembly
let tmp_dir = output_dir.join(format!(".pulling_{}", sanitized));
if tmp_dir.exists() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the .pulling_<name> temp dir is deterministic per image, so two concurrent pulls of the same image race — and this unconditional remove_dir_all can wipe an in-flight pull's working tree. A PID/uuid suffix would make it safe. Low likelihood for interactive imports.

"x86_64" => "amd64",
"aarch64" => "arm64",
"x86" => "386",
arch => arch,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the normalization fallthrough passes unknown arches through unchanged; combined with Platform not deserializing variant, 32-bit arm (v6/v7) cannot be disambiguated and the first arm entry wins. Fine for the amd64/arm64 common case — flagging for completeness.

.args([
rootfs_dir.to_str().unwrap(),
sqsh_path.to_str().unwrap(),
staged_sqsh_path.to_str().unwrap(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: to_str().unwrap() in a library crate trips the no-unwrap-in-lib guideline (AGENTS.md). Pre-existing, but since this line is in the diff, a .context("non-UTF-8 image path")? would be a cheap tidy-up.

@shiv-tyagi

Copy link
Copy Markdown
Member

@hnotshe Can you please address Yan's comments?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(spur-net): --arch flag accepted but silently ignored during registry image import

3 participants