use microsandbox_utils::MicrosandboxUtilsError;
use sqlx::migrate::MigrateError;
use std::{
error::Error,
fmt::{self, Display},
path::{PathBuf, StripPrefixError},
time::SystemTimeError,
};
use thiserror::Error;
use crate::oci::DockerRegistryResponseError;
pub type MicrosandboxResult<T> = Result<T, MicrosandboxError>;
#[derive(pretty_error_debug::Debug, Error)]
pub enum MicrosandboxError {
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error(transparent)]
Custom(#[from] AnyError),
#[error("oci distribution error: {0}")]
OciDistribution(#[from] anyhow::Error),
#[error("http request error: {0}")]
HttpRequest(#[from] reqwest::Error),
#[error("http middleware error: {0}")]
HttpMiddleware(#[from] reqwest_middleware::Error),
#[error("database error: {0}")]
Database(#[from] sqlx::Error),
#[error("manifest not found")]
ManifestNotFound,
#[error("join error: {0}")]
JoinError(#[from] tokio::task::JoinError),
#[error("unsupported image hash algorithm: {0}")]
UnsupportedImageHashAlgorithm(String),
#[error("image layer download failed: {0}")]
ImageLayerDownloadFailed(String),
#[error("invalid path pair: {0}")]
InvalidPathPair(String),
#[error("invalid port pair: {0}")]
InvalidPortPair(String),
#[error("invalid environment variable pair: {0}")]
InvalidEnvPair(String),
#[error("invalid MicroVm configuration: {0}")]
InvalidMicroVMConfig(InvalidMicroVMConfigError),
#[error("invalid resource limit format: {0}")]
InvalidRLimitFormat(String),
#[error("invalid resource limit value: {0}")]
InvalidRLimitValue(String),
#[error("invalid resource limit resource: {0}")]
InvalidRLimitResource(String),
#[error("serde json error: {0}")]
SerdeJson(#[from] serde_json::Error),
#[error("serde yaml error: {0}")]
SerdeYaml(#[from] serde_yaml::Error),
#[error("toml error: {0}")]
Toml(#[from] toml::de::Error),
#[error("configuration validation error: {0}")]
ConfigValidation(String),
#[error("configuration validation errors: {0:?}")]
ConfigValidationErrors(Vec<String>),
#[error("service '{0}' belongs to no group")]
ServiceBelongsToNoGroup(String),
#[error("service '{0}' belongs to wrong group: '{1}'")]
ServiceBelongsToWrongGroup(String, String),
#[error("failed to get shutdown eventfd: {0}")]
FailedToGetShutdownEventFd(i32),
#[error("failed to write to shutdown eventfd: {0}")]
FailedToShutdown(String),
#[error("failed to start VM: {0}")]
FailedToStartVM(i32),
#[error("path does not exist: {0}")]
PathNotFound(String),
#[error("rootfs path does not exist: {0}")]
RootFsPathNotFound(String),
#[error("supervisor binary not found: {0}")]
SupervisorBinaryNotFound(String),
#[error("failed to start VM: {0}")]
StartVmFailed(i32),
#[error("process wait error: {0}")]
ProcessWaitError(String),
#[error("supervisor error: {0}")]
SupervisorError(String),
#[error("failed to kill process: {0}")]
ProcessKillError(String),
#[error("configuration merge error: {0}")]
ConfigMerge(String),
#[error("no available IP addresses in the pool")]
NoAvailableIPs,
#[error("walkdir error: {0}")]
WalkDir(#[from] walkdir::Error),
#[error("strip prefix error: {0}")]
StripPrefix(#[from] StripPrefixError),
#[error("nix error: {0}")]
NixError(#[from] nix::Error),
#[error("system time error: {0}")]
SystemTime(#[from] SystemTimeError),
#[error("layer extraction error: {0}")]
LayerExtraction(String),
#[error("layer handling error: {source}")]
LayerHandling {
source: std::io::Error,
layer: String,
},
#[error("configuration file not found: {0}")]
ConfigNotFound(String),
#[error("Service rootfs not found: {0}")]
RootfsNotFound(String),
#[error("invalid image reference: {0}")]
ImageReferenceError(String),
#[error("Cannot remove running services: {0}")]
ServiceStillRunning(String),
#[error("{0}")]
InvalidArgument(String),
#[error("path validation error: {0}")]
PathValidation(String),
#[error("microsandbox config file not found at: {0}")]
MicrosandboxConfigNotFound(String),
#[error("failed to parse configuration file: {0}")]
ConfigParseError(String),
#[error("log not found: {0}")]
LogNotFound(String),
#[error("pager error: {0}")]
PagerError(String),
#[error("microsandbox-utils error: {0}")]
MicrosandboxUtilsError(#[from] MicrosandboxUtilsError),
#[error("migration error: {0}")]
MigrationError(#[from] MigrateError),
#[error("docker registry response error: {0}")]
DockerRegistryResponseError(#[from] DockerRegistryResponseError),
#[error("invalid image reference selector format: {0}")]
InvalidReferenceSelectorFormat(String),
#[error("invalid image reference selector digest: {0}")]
InvalidReferenceSelectorDigest(String),
#[error("feature not yet implemented: {0}")]
NotImplemented(String),
#[error("cannot find sandbox: '{0}' in '{1}'")]
SandboxNotFoundInConfig(String, PathBuf),
#[error("invalid log level: {0}")]
InvalidLogLevel(u8),
#[error("empty path segment")]
EmptyPathSegment,
#[error("invalid path component: {0}")]
InvalidPathComponent(String),
#[error("script '{0}' not found in sandbox configuration '{1}'")]
ScriptNotFoundInSandbox(String, String),
#[error("sandbox server error: {0}")]
SandboxServerError(String),
#[error("invalid network scope: {0}")]
InvalidNetworkScope(String),
#[error("missing start script or exec command or shell")]
MissingStartOrExecOrShell,
#[error("command already exists: {0}")]
CommandExists(String),
#[error("command not found: {0}")]
CommandNotFound(String),
}
#[derive(Debug, Error)]
pub enum InvalidMicroVMConfigError {
#[error("root path does not exist: {0}")]
RootPathDoesNotExist(String),
#[error("host path does not exist: {0}")]
HostPathDoesNotExist(String),
#[error("number of vCPUs is zero")]
NumVCPUsIsZero,
#[error("amount of memory is zero")]
MemoryIsZero,
#[error("command line contains invalid characters (only ASCII characters between space and tilde are allowed): {0}")]
InvalidCommandLineString(String),
#[error("Conflicting guest paths: '{0}' and '{1}' overlap")]
ConflictingGuestPaths(String, String),
}
#[derive(Debug)]
pub struct AnyError {
error: anyhow::Error,
}
impl MicrosandboxError {
pub fn custom(error: impl Into<anyhow::Error>) -> MicrosandboxError {
MicrosandboxError::Custom(AnyError {
error: error.into(),
})
}
}
impl AnyError {
pub fn downcast<T>(&self) -> Option<&T>
where
T: Display + fmt::Debug + Send + Sync + 'static,
{
self.error.downcast_ref::<T>()
}
}
#[allow(non_snake_case)]
pub fn Ok<T>(value: T) -> MicrosandboxResult<T> {
Result::Ok(value)
}
impl PartialEq for AnyError {
fn eq(&self, other: &Self) -> bool {
self.error.to_string() == other.error.to_string()
}
}
impl Display for AnyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.error)
}
}
impl Error for AnyError {}