Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 66 additions & 24 deletions crates/openshell-driver-vm/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3223,6 +3223,43 @@ impl VmDriver {
)
}

fn publish_pulling_event(&self, sandbox_id: &str, image_ref: &str) {
self.publish_platform_event(
sandbox_id.to_string(),
platform_event(
"vm",
"Normal",
"Pulling",
format!("Pulling image \"{image_ref}\""),
),
);
}

/// A registry-sourced root disk found in the cache: `Pulling`, the
/// `CacheHit` progress and `Pulled`, so the image step still advances.
async fn publish_registry_cache_hit(
&self,
sandbox_id: &str,
image_ref: &str,
image_identity: &str,
image_path: &Path,
) {
self.publish_pulling_event(sandbox_id, image_ref);
self.publish_vm_progress(
sandbox_id,
"CacheHit",
format!("Using cached VM root disk for image \"{image_ref}\""),
HashMap::from([
("image_ref".to_string(), image_ref.to_string()),
("image_source".to_string(), "registry".to_string()),
("cache_hit".to_string(), "true".to_string()),
("image_identity".to_string(), image_identity.to_string()),
]),
);
self.publish_pulled_event(sandbox_id, image_ref, image_path)
.await;
}

async fn ensure_cached_registry_rootfs_image(
&self,
sandbox_id: &str,
Expand All @@ -3233,6 +3270,31 @@ impl VmDriver {
let span_status = openshell_otel::ErrorStatusGuard::current();
info!(image_ref = %image_ref, "vm driver: ensuring cached root disk image (registry)");
let reference = parse_registry_reference(image_ref)?;
// A digest pin already names the image's content, and a cached root
// disk is only published after its manifest was verified against
// that digest. On a hit the registry cannot add anything, so neither
// authenticate nor resolve: the sandbox boots from the cache without a
// network round trip, and keeps booting while the registry is down.
// Tags still resolve through the registry below.
if let Some(digest) = reference.digest() {
let image_identity = bootstrap_image_cache_identity(digest);
let image_path = image_cache_rootfs_image(&self.config.state_dir, &image_identity);
if tokio::fs::metadata(&image_path).await.is_ok() {
info!(
image_identity = %image_identity,
image_path = %image_path.display(),
"vm driver: root disk image cache hit (digest-pinned, no registry call)"
);
self.publish_registry_cache_hit(
sandbox_id,
image_ref,
&image_identity,
&image_path,
)
.await;
return span_status.finish(Ok(image_identity));
}
}
info!(image_ref = %image_ref, "vm driver: authenticating with registry");
self.publish_vm_progress(
sandbox_id,
Expand Down Expand Up @@ -3277,40 +3339,20 @@ impl VmDriver {
let image_identity = bootstrap_image_cache_identity(&source_image_identity);
let image_path = image_cache_rootfs_image(&self.config.state_dir, &image_identity);

// Emit a driver progress hint for cache hits too and immediately
// follow with `Pulled` so the image step still advances cleanly.
self.publish_platform_event(
sandbox_id.to_string(),
platform_event(
"vm",
"Normal",
"Pulling",
format!("Pulling image \"{image_ref}\""),
),
);

if tokio::fs::metadata(&image_path).await.is_ok() {
info!(
image_identity = %image_identity,
image_path = %image_path.display(),
"vm driver: root disk image cache hit (no build needed)"
);
self.publish_vm_progress(
sandbox_id,
"CacheHit",
format!("Using cached VM root disk for image \"{image_ref}\""),
HashMap::from([
("image_ref".to_string(), image_ref.to_string()),
("image_source".to_string(), "registry".to_string()),
("cache_hit".to_string(), "true".to_string()),
("image_identity".to_string(), image_identity.clone()),
]),
);
self.publish_pulled_event(sandbox_id, image_ref, &image_path)
self.publish_registry_cache_hit(sandbox_id, image_ref, &image_identity, &image_path)
.await;
return span_status.finish(Ok(image_identity));
}

// A driver progress hint before the build, so the image step advances.
self.publish_pulling_event(sandbox_id, image_ref);

info!(
image_identity = %image_identity,
"vm driver: root disk image cache miss, acquiring build lock"
Expand Down
60 changes: 60 additions & 0 deletions crates/openshell-driver-vm/src/registry_cache_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,63 @@ async fn registry_cache_preserves_caller_digest_when_head_uses_another_algorithm
.all(|request| request == "GET /v2/")
);
}

#[tokio::test]
async fn bootstrap_registry_cache_hit_for_a_digest_pin_makes_no_registry_request() {
let body = manifest("pinned");
let digest = sha256(&body);
let registry = Registry::start(
digest.clone(),
HashMap::from([("latest".to_string(), body.clone()), (digest.clone(), body)]),
None,
false,
)
.await;
let root = tempfile::tempdir().unwrap();
let driver = driver(root.path());
let client = client();

// Not cached yet: a digest pin still authenticates and fetches (and here
// fails at the blobs the fixture does not serve).
ensure_image(&driver, &registry.reference(Some(&digest)), &client, true)
.await
.unwrap_err();
assert!(
registry
.requests()
.iter()
.any(|request| request.contains(&format!("/manifests/{digest}"))),
"{:?}",
registry.requests()
);

// Cached: the same pin boots from the cache with no request at all.
let identity = bootstrap_image_cache_identity(&digest);
let path = image_cache_rootfs_image(root.path(), &identity);
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(&path, b"cached disk").unwrap();
let before = registry.requests().len();
let resolved = ensure_image(&driver, &registry.reference(Some(&digest)), &client, true)
.await
.unwrap();
assert_eq!(resolved, identity);
assert_eq!(
registry.requests().len(),
before,
"a digest-pinned cache hit reached the registry: {:?}",
&registry.requests()[before..]
);

// A tag naming the same content still resolves through the registry.
let resolved = ensure_image(&driver, &registry.reference(None), &client, true)
.await
.unwrap();
assert_eq!(resolved, identity);
assert!(
registry.requests()[before..]
.iter()
.any(|request| request == "HEAD /v2/test/image/manifests/latest"),
"{:?}",
registry.requests()
);
}
Loading