use crate::vmm::{Vmm, VmmConfig, VmmKind};
use boxlite_shared::errors::{BoxliteError, BoxliteResult};
pub type EngineFactoryFn = fn(VmmConfig) -> BoxliteResult<Box<dyn Vmm>>;
pub struct EngineFactoryRegistration {
pub kind: VmmKind,
pub factory: EngineFactoryFn,
}
inventory::collect!(EngineFactoryRegistration);
pub fn create_engine(kind: VmmKind, options: VmmConfig) -> BoxliteResult<Box<dyn Vmm>> {
for registration in inventory::iter::<EngineFactoryRegistration> {
if registration.kind == kind {
tracing::debug!(engine = ?kind, "Creating engine instance");
return (registration.factory)(options);
}
}
let available: Vec<_> = inventory::iter::<EngineFactoryRegistration>()
.map(|r| r.kind)
.collect();
Err(BoxliteError::Engine(format!(
"Engine {:?} is not registered. Available engines: {:?}",
kind, available
)))
}
pub fn is_registered(kind: VmmKind) -> bool {
inventory::iter::<EngineFactoryRegistration>().any(|r| r.kind == kind)
}
pub fn available_engines() -> Vec<VmmKind> {
inventory::iter::<EngineFactoryRegistration>()
.map(|r| r.kind)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "krun")]
fn test_libkrun_registered() {
assert!(is_registered(VmmKind::Libkrun));
let available = available_engines();
assert!(!available.is_empty());
assert!(available.contains(&VmmKind::Libkrun));
}
#[test]
fn test_unregistered_engine() {
let options = VmmConfig::default();
if !is_registered(VmmKind::Firecracker) {
let result = create_engine(VmmKind::Firecracker, options);
assert!(result.is_err());
}
}
#[test]
#[cfg(feature = "krun")]
fn test_create_libkrun_engine() {
let options = VmmConfig::default();
let result = create_engine(VmmKind::Libkrun, options);
assert!(result.is_ok());
}
}