cloud-hypervisor SAL + rhai test script for it
This commit is contained in:
173
packages/system/virt/src/rhai/cloudhv.rs
Normal file
173
packages/system/virt/src/rhai/cloudhv.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
use crate::cloudhv;
|
||||
use crate::cloudhv::{VmRecord, VmRuntime, VmSpec};
|
||||
use rhai::{Array, Dynamic, Engine, EvalAltResult, Map};
|
||||
|
||||
// Error adapter
|
||||
fn hv_to_rhai<T>(r: Result<T, cloudhv::CloudHvError>) -> Result<T, Box<EvalAltResult>> {
|
||||
r.map_err(|e| {
|
||||
Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("cloudhv error: {}", e).into(),
|
||||
rhai::Position::NONE,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
// Map conversions
|
||||
|
||||
fn map_to_vmspec(spec: Map) -> Result<VmSpec, Box<EvalAltResult>> {
|
||||
let id = must_get_string(&spec, "id")?;
|
||||
let kernel_path = get_string(&spec, "kernel_path");
|
||||
let firmware_path = get_string(&spec, "firmware_path");
|
||||
let disk_path = must_get_string(&spec, "disk_path")?;
|
||||
let api_socket = get_string(&spec, "api_socket").unwrap_or_else(|| "".to_string());
|
||||
let vcpus = get_int(&spec, "vcpus").unwrap_or(1) as u32;
|
||||
let memory_mb = get_int(&spec, "memory_mb").unwrap_or(512) as u32;
|
||||
let cmdline = get_string(&spec, "cmdline");
|
||||
let extra_args = get_string_array(&spec, "extra_args");
|
||||
|
||||
Ok(VmSpec {
|
||||
id,
|
||||
kernel_path,
|
||||
firmware_path,
|
||||
disk_path,
|
||||
api_socket,
|
||||
vcpus,
|
||||
memory_mb,
|
||||
cmdline,
|
||||
extra_args,
|
||||
})
|
||||
}
|
||||
|
||||
fn vmspec_to_map(s: &VmSpec) -> Map {
|
||||
let mut m = Map::new();
|
||||
m.insert("id".into(), s.id.clone().into());
|
||||
if let Some(k) = &s.kernel_path {
|
||||
m.insert("kernel_path".into(), k.clone().into());
|
||||
} else {
|
||||
m.insert("kernel_path".into(), Dynamic::UNIT);
|
||||
}
|
||||
if let Some(fw) = &s.firmware_path {
|
||||
m.insert("firmware_path".into(), fw.clone().into());
|
||||
} else {
|
||||
m.insert("firmware_path".into(), Dynamic::UNIT);
|
||||
}
|
||||
m.insert("disk_path".into(), s.disk_path.clone().into());
|
||||
m.insert("api_socket".into(), s.api_socket.clone().into());
|
||||
m.insert("vcpus".into(), (s.vcpus as i64).into());
|
||||
m.insert("memory_mb".into(), (s.memory_mb as i64).into());
|
||||
if let Some(c) = &s.cmdline {
|
||||
m.insert("cmdline".into(), c.clone().into());
|
||||
} else {
|
||||
m.insert("cmdline".into(), Dynamic::UNIT);
|
||||
}
|
||||
if let Some(arr) = &s.extra_args {
|
||||
let mut a = Array::new();
|
||||
for s in arr {
|
||||
a.push(s.clone().into());
|
||||
}
|
||||
m.insert("extra_args".into(), a.into());
|
||||
} else {
|
||||
m.insert("extra_args".into(), Dynamic::UNIT);
|
||||
}
|
||||
m
|
||||
}
|
||||
|
||||
fn vmruntime_to_map(r: &VmRuntime) -> Map {
|
||||
let mut m = Map::new();
|
||||
match r.pid {
|
||||
Some(p) => m.insert("pid".into(), (p as i64).into()),
|
||||
None => m.insert("pid".into(), Dynamic::UNIT),
|
||||
};
|
||||
m.insert("status".into(), r.status.clone().into());
|
||||
m.insert("log_file".into(), r.log_file.clone().into());
|
||||
m
|
||||
}
|
||||
|
||||
fn vmrecord_to_map(rec: &VmRecord) -> Map {
|
||||
let mut m = Map::new();
|
||||
m.insert("spec".into(), vmspec_to_map(&rec.spec).into());
|
||||
m.insert("runtime".into(), vmruntime_to_map(&rec.runtime).into());
|
||||
m
|
||||
}
|
||||
|
||||
// Helpers for reading Rhai Map fields
|
||||
|
||||
fn must_get_string(m: &Map, k: &str) -> Result<String, Box<EvalAltResult>> {
|
||||
match m.get(k) {
|
||||
Some(v) if v.is_string() => Ok(v.clone().cast::<String>()),
|
||||
_ => Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("missing or non-string field '{}'", k).into(),
|
||||
rhai::Position::NONE,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_string(m: &Map, k: &str) -> Option<String> {
|
||||
m.get(k).and_then(|v| if v.is_string() { Some(v.clone().cast::<String>()) } else { None })
|
||||
}
|
||||
|
||||
fn get_int(m: &Map, k: &str) -> Option<i64> {
|
||||
m.get(k).and_then(|v| v.as_int().ok())
|
||||
}
|
||||
|
||||
fn get_string_array(m: &Map, k: &str) -> Option<Vec<String>> {
|
||||
m.get(k).and_then(|v| {
|
||||
if v.is_array() {
|
||||
let arr = v.clone().cast::<Array>();
|
||||
let mut out = vec![];
|
||||
for it in arr {
|
||||
if it.is_string() {
|
||||
out.push(it.cast::<String>());
|
||||
}
|
||||
}
|
||||
Some(out)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Rhai-exposed functions
|
||||
|
||||
pub fn cloudhv_vm_create(spec: Map) -> Result<String, Box<EvalAltResult>> {
|
||||
let s = map_to_vmspec(spec)?;
|
||||
hv_to_rhai(cloudhv::vm_create(&s))
|
||||
}
|
||||
|
||||
pub fn cloudhv_vm_start(id: &str) -> Result<(), Box<EvalAltResult>> {
|
||||
hv_to_rhai(cloudhv::vm_start(id))
|
||||
}
|
||||
|
||||
pub fn cloudhv_vm_stop(id: &str, force: bool) -> Result<(), Box<EvalAltResult>> {
|
||||
hv_to_rhai(cloudhv::vm_stop(id, force))
|
||||
}
|
||||
|
||||
pub fn cloudhv_vm_delete(id: &str, delete_disks: bool) -> Result<(), Box<EvalAltResult>> {
|
||||
hv_to_rhai(cloudhv::vm_delete(id, delete_disks))
|
||||
}
|
||||
|
||||
pub fn cloudhv_vm_list() -> Result<Array, Box<EvalAltResult>> {
|
||||
let vms = hv_to_rhai(cloudhv::vm_list())?;
|
||||
let mut arr = Array::new();
|
||||
for rec in vms {
|
||||
arr.push(vmrecord_to_map(&rec).into());
|
||||
}
|
||||
Ok(arr)
|
||||
}
|
||||
|
||||
pub fn cloudhv_vm_info(id: &str) -> Result<Map, Box<EvalAltResult>> {
|
||||
let rec = hv_to_rhai(cloudhv::vm_info(id))?;
|
||||
Ok(vmrecord_to_map(&rec))
|
||||
}
|
||||
|
||||
// Module registration
|
||||
|
||||
pub fn register_cloudhv_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
engine.register_fn("cloudhv_vm_create", cloudhv_vm_create);
|
||||
engine.register_fn("cloudhv_vm_start", cloudhv_vm_start);
|
||||
engine.register_fn("cloudhv_vm_stop", cloudhv_vm_stop);
|
||||
engine.register_fn("cloudhv_vm_delete", cloudhv_vm_delete);
|
||||
engine.register_fn("cloudhv_vm_list", cloudhv_vm_list);
|
||||
engine.register_fn("cloudhv_vm_info", cloudhv_vm_info);
|
||||
Ok(())
|
||||
}
|
Reference in New Issue
Block a user