hypha: convert to using anyhow for error handling

This commit is contained in:
Alex Zenla 2024-01-30 02:15:03 -08:00
parent a1081ea79c
commit eec213c712
No known key found for this signature in database
GPG Key ID: 067B238899B51269
13 changed files with 42 additions and 190 deletions

View File

@ -13,6 +13,7 @@ resolver = "2"
version = "0.0.1"
[workspace.dependencies]
anyhow = "1.0"
thiserror = "1.0"
log = "0.4.20"
libc = "0.2"

View File

@ -5,6 +5,7 @@ edition = "2021"
resolver = "2"
[dependencies]
anyhow = { workspace = true }
log = { workspace = true }
env_logger = { workspace = true }
zstd = { workspace = true }

View File

@ -1,5 +1,5 @@
use anyhow::Result;
use hypha::container::init::ContainerInit;
use hypha::error::Result;
fn main() -> Result<()> {
env_logger::init();

View File

@ -1,6 +1,6 @@
use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
use hypha::ctl::Controller;
use hypha::error::{HyphaError, Result};
use std::path::PathBuf;
#[derive(Parser, Debug)]
@ -48,8 +48,7 @@ fn main() -> Result<()> {
let args = ControllerArgs::parse();
let store_path = if args.store == "auto" {
default_store_path()
.ok_or_else(|| HyphaError::new("unable to determine default store path"))
default_store_path().ok_or_else(|| anyhow!("unable to determine default store path"))
} else {
Ok(PathBuf::from(args.store))
}?;
@ -57,7 +56,7 @@ fn main() -> Result<()> {
let store_path = store_path
.to_str()
.map(|x| x.to_string())
.ok_or_else(|| HyphaError::new("unable to convert store path to string"))?;
.ok_or_else(|| anyhow!("unable to convert store path to string"))?;
let mut controller = Controller::new(store_path.clone())?;

View File

@ -1,4 +1,4 @@
use crate::error::{HyphaError, Result};
use anyhow::{anyhow, Result};
use loopdev::{LoopControl, LoopDevice};
use xenclient::BlockDeviceRef;
@ -16,11 +16,9 @@ impl AutoLoop {
device.with().read_only(true).attach(file)?;
let path = device
.path()
.ok_or(HyphaError::new("unable to get loop device path"))?
.ok_or(anyhow!("unable to get loop device path"))?
.to_str()
.ok_or(HyphaError::new(
"unable to convert loop device path to string",
))?
.ok_or(anyhow!("unable to convert loop device path to string",))?
.to_string();
let major = device.major()?;
let minor = device.minor()?;

View File

@ -1,6 +1,5 @@
use crate::error::Result;
use crate::hypha_err;
use crate::shared::LaunchInfo;
use anyhow::{anyhow, Result};
use log::trace;
use nix::libc::dup2;
use nix::unistd::execve;
@ -69,7 +68,9 @@ impl ContainerInit {
if let Some(cfg) = config.config() {
self.run(cfg, &launch)?;
} else {
return hypha_err!("unable to determine what to execute, image config doesn't tell us");
return Err(anyhow!(
"unable to determine what to execute, image config doesn't tell us"
));
}
Ok(())
}

View File

@ -1,6 +1,6 @@
use crate::error::Result;
use crate::image::ImageInfo;
use crate::shared::LaunchInfo;
use anyhow::Result;
use backhand::{FilesystemWriter, NodeHeader};
use log::trace;
use std::fs;

View File

@ -2,11 +2,11 @@ pub mod cfgblk;
use crate::autoloop::AutoLoop;
use crate::ctl::cfgblk::ConfigBlock;
use crate::error::{HyphaError, Result};
use crate::image::cache::ImageCache;
use crate::image::name::ImageName;
use crate::image::{ImageCompiler, ImageInfo};
use crate::shared::LaunchInfo;
use anyhow::{anyhow, Result};
use loopdev::LoopControl;
use std::io::{Read, Write};
use std::path::PathBuf;
@ -82,16 +82,16 @@ impl Controller {
let image_squashfs_path = image_info
.image_squashfs
.to_str()
.ok_or_else(|| HyphaError::new("failed to convert image squashfs path to string"))?;
.ok_or_else(|| anyhow!("failed to convert image squashfs path to string"))?;
let cfgblk_dir_path = cfgblk
.dir
.to_str()
.ok_or_else(|| HyphaError::new("failed to convert cfgblk directory path to string"))?;
.ok_or_else(|| anyhow!("failed to convert cfgblk directory path to string"))?;
let cfgblk_squashfs_path = cfgblk
.file
.to_str()
.ok_or_else(|| HyphaError::new("failed to convert cfgblk squashfs path to string"))?;
.ok_or_else(|| anyhow!("failed to convert cfgblk squashfs path to string"))?;
let image_squashfs_loop = self.autoloop.loopify(image_squashfs_path)?;
let cfgblk_squashfs_loop = self.autoloop.loopify(cfgblk_squashfs_path)?;
@ -149,17 +149,15 @@ impl Controller {
let dom_path = store.get_domain_path(domid)?;
let uuid = match store.read_string_optional(format!("{}/hypha/uuid", dom_path).as_str())? {
None => {
return Err(HyphaError::new(&format!(
return Err(anyhow!(
"domain {} was not found or not created by hypha",
domid
)))
))
}
Some(value) => value,
};
if uuid.is_empty() {
return Err(HyphaError::new(
"unable to find hypha uuid based on the domain",
));
return Err(anyhow!("unable to find hypha uuid based on the domain",));
}
let uuid = Uuid::parse_str(&uuid)?;
let loops = store.read_string(format!("{}/hypha/loops", dom_path).as_str())?;
@ -235,8 +233,8 @@ impl Controller {
None => continue,
Some(value) => value,
};
let domid = u32::from_str(&domid_candidate)
.map_err(|_| HyphaError::new("failed to parse domid"))?;
let domid =
u32::from_str(&domid_candidate).map_err(|_| anyhow!("failed to parse domid"))?;
let uuid = Uuid::from_str(&uuid_string)?;
let image = self
.client

View File

@ -1,141 +0,0 @@
use backhand::BackhandError;
use cli_tables::TableError;
use oci_spec::OciSpecError;
use std::error::Error;
use std::ffi::NulError;
use std::fmt::{Display, Formatter};
use std::num::ParseIntError;
use std::path::StripPrefixError;
use xenclient::XenClientError;
pub type Result<T> = std::result::Result<T, HyphaError>;
#[derive(Debug)]
pub struct HyphaError {
message: String,
}
impl HyphaError {
pub fn new(msg: &str) -> HyphaError {
HyphaError {
message: msg.to_string(),
}
}
}
impl Display for HyphaError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl Error for HyphaError {
fn description(&self) -> &str {
&self.message
}
}
#[macro_export]
macro_rules! hypha_err {
($($arg:tt)*) => {{
use $crate::error::HyphaError;
let text = std::fmt::format(format_args!($($arg)*));
Err(HyphaError::new(text.as_str()))
}}
}
impl From<std::io::Error> for HyphaError {
fn from(value: std::io::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<XenClientError> for HyphaError {
fn from(value: XenClientError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<walkdir::Error> for HyphaError {
fn from(value: walkdir::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<StripPrefixError> for HyphaError {
fn from(value: StripPrefixError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<BackhandError> for HyphaError {
fn from(value: BackhandError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<serde_json::Error> for HyphaError {
fn from(value: serde_json::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<ureq::Error> for HyphaError {
fn from(value: ureq::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<ParseIntError> for HyphaError {
fn from(value: ParseIntError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<OciSpecError> for HyphaError {
fn from(value: OciSpecError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<url::ParseError> for HyphaError {
fn from(value: url::ParseError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<std::fmt::Error> for HyphaError {
fn from(value: std::fmt::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<uuid::Error> for HyphaError {
fn from(value: uuid::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<xenstore::error::Error> for HyphaError {
fn from(value: xenstore::error::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<TableError> for HyphaError {
fn from(value: TableError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<NulError> for HyphaError {
fn from(value: NulError) -> Self {
HyphaError::new(value.to_string().as_str())
}
}
impl From<nix::Error> for HyphaError {
fn from(value: nix::Error) -> Self {
HyphaError::new(value.to_string().as_str())
}
}

View File

@ -1,4 +1,4 @@
use crate::error::{HyphaError, Result};
use anyhow::{anyhow, Result};
use oci_spec::image::{Arch, Descriptor, ImageIndex, ImageManifest, MediaType, Os, ToDockerV2S2};
use std::io::copy;
use std::io::{Read, Write};
@ -63,21 +63,21 @@ impl RegistryClient {
MediaType::ImageIndex.to_docker_v2s2()?,
);
let response = self.call(self.agent.get(url.as_str()).set("Accept", &accept))?;
let content_type = response.header("Content-Type").ok_or_else(|| {
HyphaError::new("registry response did not have a Content-Type header")
})?;
let content_type = response
.header("Content-Type")
.ok_or_else(|| anyhow!("registry response did not have a Content-Type header"))?;
if content_type == MediaType::ImageIndex.to_string()
|| content_type == MediaType::ImageIndex.to_docker_v2s2()?
{
let index = ImageIndex::from_reader(response.into_reader())?;
let descriptor = self
.pick_manifest(index)
.ok_or_else(|| HyphaError::new("unable to pick manifest from index"))?;
.ok_or_else(|| anyhow!("unable to pick manifest from index"))?;
return self.get_manifest_with_digest(name, descriptor.digest());
}
let digest = response
.header("Docker-Content-Digest")
.ok_or_else(|| HyphaError::new("fetching manifest did not yield a content digest"))?
.ok_or_else(|| anyhow!("fetching manifest did not yield a content digest"))?
.to_string();
let manifest = ImageManifest::from_reader(response.into_reader())?;
Ok((manifest, digest))

View File

@ -2,10 +2,10 @@ pub mod cache;
pub mod fetch;
pub mod name;
use crate::error::{HyphaError, Result};
use crate::image::cache::ImageCache;
use crate::image::fetch::RegistryClient;
use crate::image::name::ImageName;
use anyhow::{anyhow, Result};
use backhand::compression::Compressor;
use backhand::{FilesystemCompressor, FilesystemWriter, NodeHeader};
use flate2::read::GzDecoder;
@ -160,10 +160,10 @@ impl ImageCompiler<'_> {
let mut entry = entry?;
let path = entry.path()?;
let Some(name) = path.file_name() else {
return Err(HyphaError::new("unable to get file name"));
return Err(anyhow!("unable to get file name"));
};
let Some(name) = name.to_str() else {
return Err(HyphaError::new("unable to get file name as string"));
return Err(anyhow!("unable to get file name as string"));
};
if name.starts_with(".wh.") {
@ -214,7 +214,7 @@ impl ImageCompiler<'_> {
} else if path.is_dir() {
fs::remove_dir_all(&path)?;
} else {
return Err(HyphaError::new("opaque whiteout entry did not exist"));
return Err(anyhow!("opaque whiteout entry did not exist"));
}
}
} else {
@ -280,7 +280,7 @@ impl ImageCompiler<'_> {
fn check_safe_path(&self, dst: &PathBuf, image_dir: &PathBuf) -> Result<()> {
let resolved = path_clean::clean(dst);
if !resolved.starts_with(image_dir) {
return Err(HyphaError::new("layer attempts to work outside image dir"));
return Err(anyhow!("layer attempts to work outside image dir"));
}
Ok(())
}
@ -306,7 +306,7 @@ impl ImageCompiler<'_> {
let mut file = File::create(&layer_path)?;
let size = client.write_blob(&image.name, layer, &mut file)?;
if layer.size() as u64 != size {
return Err(HyphaError::new(
return Err(anyhow!(
"downloaded layer size differs from size in manifest",
));
}
@ -323,11 +323,7 @@ impl ImageCompiler<'_> {
MediaType::ImageLayer => LayerCompressionType::None,
MediaType::ImageLayerGzip => LayerCompressionType::Gzip,
MediaType::ImageLayerZstd => LayerCompressionType::Zstd,
other => {
return Err(HyphaError::new(
format!("found layer with unknown media type: {}", other).as_str(),
))
}
other => return Err(anyhow!("found layer with unknown media type: {}", other)),
};
Ok(LayerFile {
digest: layer.digest().clone(),
@ -346,7 +342,7 @@ impl ImageCompiler<'_> {
.path()
.strip_prefix(image_dir)?
.to_str()
.ok_or_else(|| HyphaError::new("failed to strip prefix of tmpdir"))?;
.ok_or_else(|| anyhow!("failed to strip prefix of tmpdir"))?;
let rel = format!("/{}", rel);
trace!("ImageCompiler squash write {}", rel);
let typ = entry.file_type();
@ -373,7 +369,7 @@ impl ImageCompiler<'_> {
let symlink = fs::read_link(entry.path())?;
let symlink = symlink
.to_str()
.ok_or_else(|| HyphaError::new("failed to read symlink"))?;
.ok_or_else(|| anyhow!("failed to read symlink"))?;
writer.push_symlink(symlink, rel, header)?;
} else if typ.is_dir() {
writer.push_dir(rel, header)?;
@ -393,7 +389,7 @@ impl ImageCompiler<'_> {
let device = metadata.dev();
writer.push_char_device(device as u32, rel, header)?;
} else {
return Err(HyphaError::new("invalid file type"));
return Err(anyhow!("invalid file type"));
}
}
@ -401,7 +397,7 @@ impl ImageCompiler<'_> {
let squash_file_path = squash_file
.to_str()
.ok_or_else(|| HyphaError::new("failed to convert squashfs string"))?;
.ok_or_else(|| anyhow!("failed to convert squashfs string"))?;
let mut file = File::create(squash_file)?;
trace!("ImageCompiler squash generate: {}", squash_file_path);

View File

@ -1,4 +1,4 @@
use crate::error::Result;
use anyhow::Result;
use std::fmt;
use url::Url;

View File

@ -1,6 +1,5 @@
pub mod autoloop;
pub mod container;
pub mod ctl;
pub mod error;
pub mod image;
mod shared;
pub mod shared;