Skip to content

Commit

Permalink
improve error context message for failed copies
Browse files Browse the repository at this point in the history
Signed-off-by: Robert Detjens <[email protected]>
  • Loading branch information
detjensrobert committed Dec 30, 2024
1 parent e2f5b0f commit 52d4355
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 22 deletions.
20 changes: 9 additions & 11 deletions src/builder/artifacts.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::{anyhow, Context, Error, Result};
use futures::future::try_join_all;
use futures::FutureExt;
use itertools::Itertools;
use simplelog::{debug, trace};
use std::fs::File;
Expand All @@ -16,9 +17,9 @@ use crate::configparser::challenge::{ChallengeConfig, ProvideConfig};
pub async fn extract_asset(
chal: &ChallengeConfig,
provide: &ProvideConfig,
container: &str,
container: &docker::ContainerInfo,
) -> Result<Vec<PathBuf>> {
debug!("extracting assets from container {}", container);
debug!("extracting assets from container {}", &container.name);
// This needs to handle three cases:
// - single or multiple files without renaming (no as: field)
// - single file with rename (one item with as:)
Expand Down Expand Up @@ -46,7 +47,7 @@ pub async fn extract_asset(
/// Extract multiple files from container
async fn extract_files(
chal: &ChallengeConfig,
container: &str,
container: &docker::ContainerInfo,
files: &Vec<String>,
) -> Result<Vec<PathBuf>> {
debug!(
Expand All @@ -63,29 +64,27 @@ async fn extract_files(
docker::copy_file(container, from, to)
}))
.await
.context("could not copy files from container")
}

/// Extract one file from container and rename
async fn extract_rename(
chal: &ChallengeConfig,
container: &str,
container: &docker::ContainerInfo,
file: &str,
new_name: &str,
) -> Result<Vec<PathBuf>> {
debug!("extracting file {:?} renamed to {:?}", file, new_name);

let new_file = docker::copy_file(container, PathBuf::from(file), PathBuf::from(new_name))
.await
.context("could not copy file from container")?;
let new_file =
docker::copy_file(container, PathBuf::from(file), PathBuf::from(new_name)).await?;

Ok(vec![new_file])
}

/// Extract one or more file from container as archive
async fn extract_archive(
chal: &ChallengeConfig,
container: &str,
container: &docker::ContainerInfo,
files: &Vec<String>,
archive_name: &str,
) -> Result<Vec<PathBuf>> {
Expand All @@ -104,8 +103,7 @@ async fn extract_archive(

docker::copy_file(container, from, to)
}))
.await
.context("could not copy files from container")?;
.await?;

// write them all to new zip
let zipfile = File::create(chal.directory.join(archive_name))?;
Expand Down
40 changes: 31 additions & 9 deletions src/builder/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ use tokio;
use crate::configparser::challenge::BuildObject;
use crate::configparser::UserPass;

pub struct ContainerInfo {
pub name: String,
id: String,
}

#[tokio::main(flavor = "current_thread")] // make this a sync function
pub async fn build_image(context: &Path, options: &BuildObject, tag: &str) -> Result<String> {
trace!("building image in directory {context:?} to tag {tag:?}");
Expand Down Expand Up @@ -117,7 +122,7 @@ pub async fn push_image(image_tag: &str, creds: &UserPass) -> Result<String> {
}

#[tokio::main(flavor = "current_thread")] // make this a sync function
pub async fn create_container(image_tag: &str, name: &str) -> Result<String> {
pub async fn create_container(image_tag: &str, name: &str) -> Result<ContainerInfo> {
debug!("creating container {name:?} from image {image_tag:?}");
let client = client().await?;

Expand All @@ -131,25 +136,28 @@ pub async fn create_container(image_tag: &str, name: &str) -> Result<String> {
};

let container = client.create_container(Some(opts), config).await?;
Ok(container.id)
Ok(ContainerInfo {
id: container.id,
name: name.to_string(),
})
}

#[tokio::main(flavor = "current_thread")] // make this a sync function
pub async fn remove_container(name: &str) -> Result<()> {
debug!("removing container {name:?}");
pub async fn remove_container(container: ContainerInfo) -> Result<()> {
debug!("removing container {}", &container.name);
let client = client().await?;

let opts = RemoveContainerOptions {
force: true,
..Default::default()
};
client.remove_container(name, Some(opts)).await?;
client.remove_container(&container.name, Some(opts)).await?;

Ok(())
}

pub async fn copy_file(container_id: &str, from: PathBuf, to: PathBuf) -> Result<PathBuf> {
trace!("copying {container_id}:{from:?} to {to:?}");
pub async fn copy_file(container: &ContainerInfo, from: PathBuf, to: PathBuf) -> Result<PathBuf> {
trace!("copying {}:{from:?} to {to:?}", container.name);

let client = client().await?;

Expand All @@ -159,7 +167,18 @@ pub async fn copy_file(container_id: &str, from: PathBuf, to: PathBuf) -> Result
let opts = DownloadFromContainerOptions {
path: from.to_string_lossy(),
};
let mut dl_stream = client.download_from_container(container_id, Some(opts));
let mut dl_stream = client
.download_from_container(&container.id, Some(opts))
.map(|c| {
c.with_context(|| {
format!(
"could not copy file {}:{} to {}",
&container.name,
from.to_string_lossy(),
to.to_string_lossy()
)
})
});

// collect byte stream chunks into full file
let mut temptar = Builder::new().suffix(".tar").tempfile_in(".")?;
Expand All @@ -180,7 +199,10 @@ pub async fn copy_file(container_id: &str, from: PathBuf, to: PathBuf) -> Result
let mut target = File::create(&to)?;
io::copy(&mut entry, &mut target)?;
} else {
bail!("downloaded archive for {container_id}:{from:?} has no files in it!");
bail!(
"downloaded archive for {}:{from:?} has no files in it!",
container.name
);
}

Ok(to.to_path_buf())
Expand Down
5 changes: 3 additions & 2 deletions src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,14 @@ fn build_challenge(

let asset_result = extract_asset(chal, p, &container).with_context(|| {
format!(
"failed to extract build artifacts for chal {:?}",
"failed to extract build artifacts for chal {:?} container {:?}",
chal.directory,
p.from.clone().unwrap()
)
});

// clean up container even if it failed
docker::remove_container(&name)?;
docker::remove_container(container)?;

asset_result
})
Expand Down

0 comments on commit 52d4355

Please sign in to comment.