use mimobox_core::ErrorCode;
#[non_exhaustive]
#[derive(Debug, thiserror::Error)]
pub enum SdkError {
#[error("[{code_str}] {message}", code_str = code.as_str())]
Sandbox {
code: ErrorCode,
message: String,
suggestion: Option<String>,
},
#[error("backend unavailable: {0} (enable the corresponding feature)")]
BackendUnavailable(&'static str),
#[error("config error: {0}")]
Config(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}
impl SdkError {
pub fn sandbox(
code: ErrorCode,
message: impl Into<String>,
suggestion: Option<String>,
) -> Self {
Self::Sandbox {
code,
message: message.into(),
suggestion,
}
}
pub fn from_sandbox_execute_error(err: mimobox_core::SandboxError) -> Self {
match err {
mimobox_core::SandboxError::UnsupportedOperation(message) => Self::Sandbox {
code: ErrorCode::UnsupportedPlatform,
message,
suggestion: Some("set isolation to `Os` or use default Auto".into()),
},
mimobox_core::SandboxError::Timeout => Self::Sandbox {
code: ErrorCode::CommandTimeout,
message: "command execution timed out".into(),
suggestion: Some("increase Config.timeout or per-command timeout".into()),
},
mimobox_core::SandboxError::ExecutionFailed(msg) => Self::Sandbox {
code: ErrorCode::CommandKilled,
message: msg,
suggestion: None,
},
other => Self::Sandbox {
code: ErrorCode::SandboxCreateFailed,
message: other.to_string(),
suggestion: None,
},
}
}
pub fn from_sandbox_create_error(err: mimobox_core::SandboxError) -> Self {
match err {
mimobox_core::SandboxError::UnsupportedOperation(message) => Self::Sandbox {
code: ErrorCode::UnsupportedPlatform,
message,
suggestion: Some("set isolation to `Os` or use default Auto".into()),
},
other => Self::Sandbox {
code: ErrorCode::SandboxCreateFailed,
message: other.to_string(),
suggestion: Some(
"verify KVM is available (Linux) or choose a different isolation level".into(),
),
},
}
}
pub fn from_sandbox_destroy_error(err: mimobox_core::SandboxError) -> Self {
Self::Sandbox {
code: ErrorCode::SandboxDestroyed,
message: err.to_string(),
suggestion: None,
}
}
pub fn unsupported_backend(msg: &'static str) -> Self {
Self::BackendUnavailable(msg)
}
pub fn internal(msg: impl Into<String>) -> Self {
Self::Config(msg.into())
}
}
impl From<mimobox_core::SandboxError> for SdkError {
fn from(err: mimobox_core::SandboxError) -> Self {
Self::from_sandbox_execute_error(err)
}
}
#[cfg(test)]
mod tests {
use super::SdkError;
use mimobox_core::{ErrorCode, SandboxError};
#[test]
fn execution_failed_maps_to_command_killed_and_preserves_message() {
let error = SdkError::from_sandbox_execute_error(SandboxError::ExecutionFailed(
"process killed by seccomp".to_string(),
));
match error {
SdkError::Sandbox {
code,
message,
suggestion,
} => {
assert_eq!(code, ErrorCode::CommandKilled);
assert_eq!(message, "process killed by seccomp");
assert!(suggestion.is_none());
}
other => panic!("expected sandbox error, got {other:?}"),
}
}
}