use crate::err::*;
use ruc::{err::*, *};
use std::{
collections::{HashMap, HashSet},
fmt::Debug,
fs, mem,
path::{Path, PathBuf},
sync::Arc,
};
pub type Id = u64;
pub type EnvId = Id;
pub type VmId = Id;
pub type UserId = String;
pub type SockPort = u16;
pub type PubSockPort = SockPort;
pub type InnerSockPort = SockPort;
pub type NetAddr = String;
pub type IpAddr = [u8; 4];
pub type MacAddr = [u8; 6];
#[derive(Debug)]
#[non_exhaustive]
pub enum VmFeature {
Snapshot,
StartStop,
NatNetwork,
FlatNetwork,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum NetKind {
Flatten,
Forward,
Nat,
}
impl Default for NetKind {
fn default() -> Self {
Self::Nat
}
}
pub struct User {
pub id: UserId,
pub passwd: Option<String>,
pub env_set: HashSet<EnvId>,
}
#[derive(Debug, Default)]
pub struct Env {
pub id: Id,
pub name: Option<String>,
pub start_timestamp: u64,
pub end_timestamp: u64,
pub vm_set: HashSet<Id>,
pub state: EnvState,
}
#[derive(Debug, Default)]
pub struct EnvState {
pub is_stopped: bool,
pub deny_outgoing: bool,
pub last_mgmt_timestamp: u64,
}
#[derive(Debug)]
pub struct Vm {
pub id: Id,
pub name: Option<String>,
pub engine: Arc<dyn VmEngine>,
pub template: Arc<VmTemplate>,
pub runtime_image: String,
pub net_kind: NetKind,
pub snapshots: HashMap<String, Snapshot>,
pub latest_meta: Option<PathBuf>,
pub state: VmState,
pub resource: VmResource,
pub addr: NetAddr,
pub features: HashSet<VmFeature>,
}
#[derive(Debug, Default)]
pub struct VmTemplate {
pub name: String,
pub path: String,
pub memo: Option<String>,
pub compatible_engines: HashSet<String>,
}
#[derive(Debug, Default)]
pub struct VmState {
pub during_stop: bool,
pub keep_image: bool,
pub rand_uuid: bool,
pub net_blacklist: HashSet<IpAddr>,
}
#[derive(Debug, Default)]
pub struct VmResource {
pub cpu_num: u16,
pub mem_size: u32,
pub disk_size: u32,
pub ip_addr: IpAddr,
pub mac_addr: MacAddr,
pub port_map: HashMap<InnerSockPort, PubSockPort>,
}
#[derive(Debug, Default)]
pub struct Snapshot {
pub name: String,
pub path: String,
pub meta_path: PathBuf,
pub life_time: Option<u64>,
}
impl Snapshot {
pub fn new(name: String, meta_path: PathBuf) -> Self {
Self::newx(name, None, meta_path)
}
pub fn newx(name: String, life_time: Option<u64>, meta_path: PathBuf) -> Self {
Snapshot {
name,
life_time,
path: String::new(),
meta_path,
}
}
}
pub trait VmEngine: Send + Sync + Debug + Network + Storage {
fn init() -> Result<Arc<dyn VmEngine>>
where
Self: Sized;
fn name(&self) -> &str;
fn ok_features(&self, vm: &Vm) -> bool;
fn get_features(&self) -> &'static [VmFeature];
fn create_vm(&self, vm: &mut Vm) -> Result<()> {
self.create_image(vm)
.c(e!(ERR_KK_STORAGE_CREATE_IMAGE))
.and_then(|_| self.set_net(vm).c(e!(ERR_KK_NET_SET_NET)))
}
fn destroy_vm(&self, vm: &mut Vm) -> Result<()> {
self.destroy_image(vm)
.c(e!(ERR_KK_STORAGE_DESTROY_IMAGE))
.and_then(|_| self.unset_net(vm).c(e!(ERR_KK_NET_UNSET_NET)))
}
fn start_vm(&self, vm: &mut Vm) -> Result<()>;
fn stop_vm(&self, vm: &mut Vm) -> Result<()>;
fn update_vm(&mut self, vm: Vm) -> Result<()>;
fn cache_meta(&self, vm: &Vm) -> Result<PathBuf>;
fn clean_meta(&self, vm: &mut Vm, path: &Path) -> Result<()> {
fs::remove_file(path).c(e!(ERR_KK_SYS_IO)).map(|_| {
if let Some(ref p) = vm.latest_meta {
if p == path {
vm.latest_meta = None;
}
}
})
}
fn restore_from_meta(&self, path: &Path) -> Result<Vm>;
fn create_snapshot(
&self,
vm: &mut Vm,
name: &str,
life_time: Option<u64>,
) -> Result<()> {
self.stop_vm(vm)
.c(e!(ERR_KK_STOP_VM))
.and_then(|_| {
self.cache_meta(vm)
.c(e!(ERR_KK_META_CREATE_CACHE))
.and_then(|meta| {
let mut snapshot =
Snapshot::newx(name.to_owned(), life_time, meta);
<Self as Storage>::create_snapshot(self, vm, &snapshot)
.c(e!(ERR_KK_SNAPSHOT_CREATE))
.map(|path| {
snapshot.path = path;
vm.snapshots.insert(name.to_owned(), snapshot);
})
})
})
.and_then(|_| self.start_vm(vm).c(e!(ERR_KK_START_VM)))
}
fn destroy_snapshot(&self, vm: &mut Vm, name: &str) -> Result<()> {
vm.snapshots.remove(name).ok_or(eg!()).and_then(|snapshot| {
<Self as Storage>::destroy_snapshot(self, vm, &snapshot.path)
.c(e!(ERR_KK_SNAPSHOT_DESTROY))
.and_then(|_| {
self.clean_meta(vm, &snapshot.meta_path)
.c(e!(ERR_KK_META_REMOVE_CACHE))
})
})
}
fn apply_snapshot(&mut self, vm: &mut Vm, name: &str) -> Result<()> {
self.stop_vm(vm)
.and_then(|_| {
let snapshot = vm.snapshots.get(name).ok_or(eg!())?;
let mut cached_vm = self
.restore_from_meta(&snapshot.meta_path)
.c(e!(ERR_KK_META_RESTORE_CACHE))?;
<Self as Storage>::apply_snapshot(self, &cached_vm, &snapshot)
.c(e!(ERR_KK_SNAPSHOT_APPLY))?;
cached_vm.snapshots = mem::take(&mut vm.snapshots);
self.update_vm(cached_vm).c(e!(ERR_KK_UPDATE_VM))
})
.and_then(|_| self.start_vm(vm).c(e!(ERR_KK_START_VM)))
}
}
pub trait Network {
fn set_net(&self, vm: &mut Vm) -> Result<()>;
fn unset_net(&self, vm: &mut Vm) -> Result<()>;
fn deny_outgoing(&self, vm: &mut Vm) -> Result<()>;
fn allow_outgoing(&self, vm: &mut Vm) -> Result<()>;
fn set_blacklist(&self, vm: &mut Vm) -> Result<()>;
}
pub trait Storage {
fn create_image(&self, vm: &mut Vm) -> Result<()>;
fn destroy_image(&self, vm: &mut Vm) -> Result<()>;
fn create_snapshot(&self, vm: &mut Vm, snapshot: &Snapshot) -> Result<String>;
fn destroy_snapshot(&self, vm: &Vm, snapshot_path: &str) -> Result<()>;
fn apply_snapshot(&self, vm: &Vm, snapshot: &Snapshot) -> Result<()>;
}