add default image docker fallback #8
@@ -84,18 +84,20 @@ impl DevContainer {
|
|||||||
workspace_dir: &Path,
|
workspace_dir: &Path,
|
||||||
) -> Result<Container, ContainerError> {
|
) -> Result<Container, ContainerError> {
|
||||||
let id = unique_id();
|
let id = unique_id();
|
||||||
|
|
||||||
let image = self
|
let image = self
|
||||||
.image
|
.image
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| self.local_image_tag(&id));
|
.unwrap_or_else(|| self.local_image_tag(&id));
|
||||||
|
|
||||||
let owns_image = self.image.is_none();
|
let owns_image = self.image.is_none();
|
||||||
|
let container_name = self.container_name(&id);
|
||||||
|
let network = format!("{container_name}-net");
|
||||||
|
let workspace_folder = self.workspace_folder();
|
||||||
|
|
||||||
info!(image = %image, "Starting sandbox container");
|
info!(image = %image, "Starting sandbox container");
|
||||||
|
|
||||||
match owns_image {
|
let setup = async {
|
||||||
true => {
|
if owns_image {
|
||||||
let container_file_path = self.container_file_path.as_ref().ok_or_else(|| {
|
let container_file_path = self.container_file_path.as_ref().ok_or_else(|| {
|
||||||
ContainerError::Unexpected(String::from(
|
ContainerError::Unexpected(String::from(
|
||||||
"the devcontainer has neither an image nor a container file",
|
"the devcontainer has neither an image nor a container file",
|
||||||
@@ -103,74 +105,78 @@ impl DevContainer {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.build(runtime, container_file_path, &image).await?;
|
self.build(runtime, container_file_path, &image).await?;
|
||||||
}
|
} else {
|
||||||
false => {
|
|
||||||
runtime.pull_image(&image).await?;
|
runtime.pull_image(&image).await?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let name = self.container_name(&id);
|
runtime.create_network(&network).await?;
|
||||||
let network = format!("{name}-net");
|
|
||||||
|
|
||||||
runtime.create_network(&network).await?;
|
let body = ContainerCreateBody {
|
||||||
|
image: Some(image.clone()),
|
||||||
let workspace_folder = self.workspace_folder();
|
cmd: Some(vec![String::from("sleep"), String::from("infinity")]),
|
||||||
let body = ContainerCreateBody {
|
user: self.remote_user.clone(),
|
||||||
image: Some(image.clone()),
|
env: Some(
|
||||||
cmd: Some(vec![String::from("sleep"), String::from("infinity")]),
|
self.container_env
|
||||||
user: self.remote_user.clone(),
|
.iter()
|
||||||
env: Some(
|
.map(|(key, value)| format!("{key}={value}"))
|
||||||
self.container_env
|
.collect(),
|
||||||
.iter()
|
),
|
||||||
.map(|(key, value)| format!("{key}={value}"))
|
working_dir: Some(workspace_folder.clone()),
|
||||||
.collect(),
|
host_config: Some(HostConfig {
|
||||||
),
|
network_mode: Some(network.clone()),
|
||||||
working_dir: Some(workspace_folder.clone()),
|
..Default::default()
|
||||||
host_config: Some(HostConfig {
|
}),
|
||||||
network_mode: Some(network.clone()),
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
};
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(err) = runtime.create_container(&name, body).await {
|
runtime.create_container(&container_name, body).await?;
|
||||||
let _ = runtime.remove_network(&network).await;
|
runtime.start_container(&container_name).await?;
|
||||||
return Err(err);
|
runtime
|
||||||
|
.upload_directory(&container_name, &workspace_folder, workspace_dir)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok::<(), ContainerError>(())
|
||||||
}
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
if let Err(err) = runtime.start_container(&name).await {
|
if let Err(err) = setup {
|
||||||
let _ = runtime.remove_container(&name).await;
|
cleanup_failed_startup(
|
||||||
let _ = runtime.remove_network(&network).await;
|
runtime,
|
||||||
return Err(err);
|
&container_name,
|
||||||
}
|
&network,
|
||||||
|
owns_image.then_some(image.as_str()),
|
||||||
if let Err(err) = runtime
|
)
|
||||||
.upload_directory(&name, &workspace_folder, workspace_dir)
|
.await;
|
||||||
.await
|
|
||||||
{
|
|
||||||
let _ = runtime.remove_container(&name).await;
|
|
||||||
let _ = runtime.remove_network(&network).await;
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let container = Container::new(
|
let container = Container::new(
|
||||||
runtime.clone(),
|
runtime.clone(),
|
||||||
name,
|
container_name.clone(),
|
||||||
self.workspace_folder(),
|
workspace_folder,
|
||||||
self.remote_user.clone(),
|
self.remote_user.clone(),
|
||||||
Some(network.clone()),
|
Some(network.clone()),
|
||||||
owns_image.then_some(image),
|
owns_image.then_some(image.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Les hooks s'exécutent avec accès au réseau (installation de dépendances, etc.).
|
let post_setup = async {
|
||||||
if let Err(err) = self.run_hooks(&container, runtime.timeout()).await {
|
self.run_hooks(&container, runtime.timeout()).await?;
|
||||||
let _ = container.remove().await;
|
runtime
|
||||||
return Err(err);
|
.disconnect_network(&network, &container_name)
|
||||||
}
|
.await?;
|
||||||
|
|
||||||
// Coupe l'accès réseau pour le reste de la durée de vie de la sandbox.
|
Ok::<(), ContainerError>(())
|
||||||
if let Err(err) = runtime.disconnect_network(&network, container.name()).await {
|
}
|
||||||
let _ = container.remove().await;
|
.await;
|
||||||
|
|
||||||
|
if let Err(err) = post_setup {
|
||||||
|
cleanup_failed_startup(
|
||||||
|
runtime,
|
||||||
|
&container_name,
|
||||||
|
&network,
|
||||||
|
owns_image.then_some(image.as_str()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +209,20 @@ impl DevContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn cleanup_failed_startup(
|
||||||
|
runtime: &ContainerRuntime,
|
||||||
|
container: &str,
|
||||||
|
network: &str,
|
||||||
|
owned_image: Option<&str>,
|
||||||
|
) {
|
||||||
|
let _ = runtime.remove_container(container).await;
|
||||||
|
let _ = runtime.remove_network(network).await;
|
||||||
|
|
||||||
|
if let Some(image) = owned_image {
|
||||||
|
let _ = runtime.remove_image(image).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for DevContainer {
|
impl Default for DevContainer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Reference in new issue
Block a user