Skip to content

Commit f0ef63d

Browse files
committed
feat: auto-pull images in broker when creating containers
When creating a container, the broker now checks if the image exists locally and automatically pulls it if necessary. This prevents 'No such image' errors when task images haven't been pre-pulled. The ensure_image() method: 1. Checks if image exists locally via inspect 2. If not found (404), pulls the image 3. Returns any errors for proper handling
1 parent d88bfe5 commit f0ef63d

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

crates/secure-container-runtime/src/broker.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,23 @@ impl ContainerBroker {
234234
return Response::error(request_id, e);
235235
}
236236

237+
// Auto-pull image if it doesn't exist locally
238+
if let Err(e) = self.ensure_image(&config.image).await {
239+
self.audit(
240+
AuditAction::ImagePull,
241+
&config.challenge_id,
242+
&config.owner_id,
243+
None,
244+
false,
245+
Some(e.to_string()),
246+
)
247+
.await;
248+
return Response::error(
249+
request_id.clone(),
250+
ContainerError::DockerError(e.to_string()),
251+
);
252+
}
253+
237254
// Check container limits
238255
{
239256
let by_challenge = self.containers_by_challenge.read().await;
@@ -811,6 +828,50 @@ impl ContainerBroker {
811828
}
812829
}
813830

831+
/// Ensure an image exists locally, pulling it if necessary
832+
async fn ensure_image(&self, image: &str) -> anyhow::Result<()> {
833+
// Check if image exists locally
834+
match self.docker.inspect_image(image).await {
835+
Ok(_) => {
836+
debug!(image = %image, "Image already exists locally");
837+
return Ok(());
838+
}
839+
Err(bollard::errors::Error::DockerResponseServerError {
840+
status_code: 404, ..
841+
}) => {
842+
// Image not found, need to pull
843+
info!(image = %image, "Image not found locally, pulling...");
844+
}
845+
Err(e) => {
846+
return Err(anyhow::anyhow!("Failed to inspect image: {}", e));
847+
}
848+
}
849+
850+
// Pull the image
851+
let options = CreateImageOptions {
852+
from_image: image,
853+
..Default::default()
854+
};
855+
856+
let mut stream = self.docker.create_image(Some(options), None, None);
857+
858+
while let Some(result) = stream.next().await {
859+
match result {
860+
Ok(info) => {
861+
if let Some(status) = info.status {
862+
debug!(image = %image, status = %status, "Pull progress");
863+
}
864+
}
865+
Err(e) => {
866+
return Err(anyhow::anyhow!("Failed to pull image: {}", e));
867+
}
868+
}
869+
}
870+
871+
info!(image = %image, "Image pulled successfully");
872+
Ok(())
873+
}
874+
814875
/// Ensure the challenge network exists
815876
async fn ensure_network(&self) -> anyhow::Result<()> {
816877
let networks = self.docker.list_networks::<String>(None).await?;

0 commit comments

Comments
 (0)