mirror of
https://github.com/marcoallegretti/karapace.git
synced 2026-03-26 21:43:09 +00:00
- RuntimeBackend trait: resolve, build, enter, exec, destroy, status - Namespace backend: unshare + fuse-overlayfs + chroot (unprivileged) - OCI backend: crun/runc/youki support - Mock backend: deterministic test backend with configurable resolution - Image downloading from images.linuxcontainers.org with blake3 verification - Sandbox script generation with POSIX shell-quote injection prevention - Host integration: Wayland, X11, PipeWire, PulseAudio, D-Bus, GPU, audio, SSH agent - Desktop app export as .desktop files on the host - SecurityPolicy: mount whitelist, device policy, env var allow/deny, resource limits - Prerequisite detection with distro-specific install instructions - OSC 777 terminal markers for container-aware terminals
82 lines
2.4 KiB
Rust
82 lines
2.4 KiB
Rust
use crate::RuntimeError;
|
|
use karapace_schema::{NormalizedManifest, ResolutionResult};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct RuntimeSpec {
|
|
pub env_id: String,
|
|
pub root_path: String,
|
|
pub overlay_path: String,
|
|
pub store_root: String,
|
|
pub manifest: NormalizedManifest,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
pub struct RuntimeStatus {
|
|
pub env_id: String,
|
|
pub running: bool,
|
|
pub pid: Option<u32>,
|
|
}
|
|
|
|
pub trait RuntimeBackend: Send + Sync {
|
|
fn name(&self) -> &str;
|
|
|
|
fn available(&self) -> bool;
|
|
|
|
/// Resolve dependencies: download/identify the base image and query the
|
|
/// package manager for exact versions of each requested package.
|
|
/// Returns a ResolutionResult with content digest and pinned versions.
|
|
fn resolve(&self, spec: &RuntimeSpec) -> Result<ResolutionResult, RuntimeError>;
|
|
|
|
fn build(&self, spec: &RuntimeSpec) -> Result<(), RuntimeError>;
|
|
|
|
fn enter(&self, spec: &RuntimeSpec) -> Result<(), RuntimeError>;
|
|
|
|
fn exec(
|
|
&self,
|
|
_spec: &RuntimeSpec,
|
|
_command: &[String],
|
|
) -> Result<std::process::Output, RuntimeError> {
|
|
Err(RuntimeError::ExecFailed(format!(
|
|
"exec not supported by {} backend",
|
|
self.name()
|
|
)))
|
|
}
|
|
|
|
fn destroy(&self, spec: &RuntimeSpec) -> Result<(), RuntimeError>;
|
|
|
|
fn status(&self, env_id: &str) -> Result<RuntimeStatus, RuntimeError>;
|
|
}
|
|
|
|
pub fn select_backend(
|
|
name: &str,
|
|
store_root: &str,
|
|
) -> Result<Box<dyn RuntimeBackend>, RuntimeError> {
|
|
match name {
|
|
"namespace" => Ok(Box::new(
|
|
crate::namespace::NamespaceBackend::with_store_root(store_root),
|
|
)),
|
|
"oci" => Ok(Box::new(crate::oci::OciBackend::with_store_root(
|
|
store_root,
|
|
))),
|
|
"mock" => Ok(Box::new(crate::mock::MockBackend::new())),
|
|
other => Err(RuntimeError::BackendUnavailable(other.to_owned())),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn select_valid_backends() {
|
|
assert!(select_backend("namespace", "/tmp/test-store").is_ok());
|
|
assert!(select_backend("oci", "/tmp/test-store").is_ok());
|
|
assert!(select_backend("mock", "/tmp/test-store").is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn select_invalid_backend_fails() {
|
|
assert!(select_backend("nonexistent", "/tmp/test-store").is_err());
|
|
}
|
|
}
|