183 lines
5.7 KiB
Rust
183 lines
5.7 KiB
Rust
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 initramfs_path = get_string(&spec, "initramfs_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,
|
|
initramfs_path,
|
|
firmware_path,
|
|
disk_path,
|
|
api_socket,
|
|
vcpus,
|
|
memory_mb,
|
|
cmdline,
|
|
extra_args,
|
|
net_profile: None,
|
|
})
|
|
}
|
|
|
|
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(ir) = &s.initramfs_path {
|
|
m.insert("initramfs_path".into(), ir.clone().into());
|
|
} else {
|
|
m.insert("initramfs_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);
|
|
}
|
|
// net_profile not exposed in Rhai yet; return UNIT for now
|
|
m.insert("net_profile".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(())
|
|
} |