148 lines
3.8 KiB
Plaintext
148 lines
3.8 KiB
Plaintext
// Cloud Hypervisor diagnostic script
|
|
// Creates a VM, starts CH, verifies PID, API socket, ch-remote info, and tails logs.
|
|
|
|
print("=== CloudHV Diagnostic ===");
|
|
|
|
// Dependency check
|
|
let chs = which("cloud-hypervisor-static");
|
|
let chrs = which("ch-remote-static");
|
|
let ch_missing = (chs == () || chs == "");
|
|
let chr_missing = (chrs == () || chrs == "");
|
|
if ch_missing || chr_missing {
|
|
print("cloud-hypervisor-static and/or ch-remote-static not available - aborting.");
|
|
exit();
|
|
}
|
|
|
|
// Inputs
|
|
let firmware_path = "/tmp/virt_images/hypervisor-fw";
|
|
let disk_path = "/tmp/virt_images/noble-server-cloudimg-amd64.img";
|
|
|
|
if !exist(firmware_path) {
|
|
print(`Firmware not found: ${firmware_path}`);
|
|
exit();
|
|
}
|
|
if !exist(disk_path) {
|
|
print(`Disk image not found: ${disk_path}`);
|
|
exit();
|
|
}
|
|
|
|
// Unique ID
|
|
let rid = run_silent("date +%s%N");
|
|
let suffix = if rid.success && rid.stdout != "" { rid.stdout.trim() } else { "100000" };
|
|
let vm_id = `diagvm_${suffix}`;
|
|
|
|
// Socket path will be obtained from VM info (SAL populates spec.api_socket after start)
|
|
|
|
// Build minimal spec; let SAL decide the api_socket under the VM dir
|
|
let spec = #{
|
|
"id": vm_id,
|
|
"disk_path": disk_path,
|
|
"vcpus": 1,
|
|
"memory_mb": 512
|
|
};
|
|
spec.firmware_path = firmware_path;
|
|
|
|
fn pid_alive(p) {
|
|
if p == () { return false; }
|
|
// Use /proc to avoid noisy "kill: No such process" messages from kill -0
|
|
return exist(`/proc/${p}`);
|
|
}
|
|
|
|
fn tail_log(p, n) {
|
|
if exist(p) {
|
|
let r = run_silent(`tail -n ${n} ${p}`);
|
|
if r.success { print(r.stdout); } else { print(r.stderr); }
|
|
} else {
|
|
print(`Log file not found: ${p}`);
|
|
}
|
|
}
|
|
|
|
try {
|
|
print("--- Create VM spec ---");
|
|
let created = cloudhv_vm_create(spec);
|
|
print(`created: ${created}`);
|
|
} catch (err) {
|
|
print(`create failed: ${err}`);
|
|
exit();
|
|
}
|
|
|
|
// Read back info to get SAL-resolved log_file path
|
|
let info0 = cloudhv_vm_info(vm_id);
|
|
let log_file = info0.runtime.log_file;
|
|
|
|
// Rely on SAL to handle socket directory creation and stale-socket cleanup
|
|
|
|
print("--- Start VM ---");
|
|
try {
|
|
cloudhv_vm_start(vm_id);
|
|
print("start invoked");
|
|
} catch (err) {
|
|
print(`start failed: ${err}`);
|
|
tail_log(log_file, 200);
|
|
exit();
|
|
}
|
|
|
|
// Fetch PID and discover API socket path from updated spec
|
|
let info1 = cloudhv_vm_info(vm_id);
|
|
let pid = info1.runtime.pid;
|
|
let api_sock = info1.spec.api_socket;
|
|
print(`pid=${pid}`);
|
|
print(`api_sock_from_sal=${api_sock}`);
|
|
|
|
// Wait for socket file
|
|
let sock_ok = false;
|
|
for x in 0..50 {
|
|
if exist(api_sock) { sock_ok = true; break; }
|
|
sleep(1);
|
|
}
|
|
print(`api_sock_exists=${sock_ok} path=${api_sock}`);
|
|
|
|
// Probe ch-remote info
|
|
let info_ok = false;
|
|
let last_err = "";
|
|
if sock_ok {
|
|
for x in 0..20 {
|
|
let r = run_silent(`ch-remote-static --api-socket ${api_sock} info`);
|
|
if r.success {
|
|
info_ok = true;
|
|
print("ch-remote info OK");
|
|
break;
|
|
} else {
|
|
last_err = if r.stderr != "" { r.stderr } else { r.stdout };
|
|
sleep(1);
|
|
}
|
|
}
|
|
}
|
|
if !info_ok {
|
|
print("ch-remote info FAILED");
|
|
if last_err != "" { print(last_err); }
|
|
let alive = pid_alive(pid);
|
|
print(`pid_alive=${alive}`);
|
|
print("--- Last 200 lines of CH log ---");
|
|
tail_log(log_file, 200);
|
|
print("--- End of log ---");
|
|
} else {
|
|
print("--- Stop via SAL (force) ---");
|
|
try {
|
|
cloudhv_vm_stop(vm_id, true);
|
|
print("SAL stop invoked (force)");
|
|
} catch (err) {
|
|
print(`stop failed: ${err}`);
|
|
}
|
|
// wait for exit (check original PID)
|
|
for x in 0..30 {
|
|
if !pid_alive(pid) { break; }
|
|
sleep(1);
|
|
}
|
|
print(`pid_alive_after_stop=${pid_alive(pid)}`);
|
|
}
|
|
|
|
print("--- Cleanup ---");
|
|
try {
|
|
cloudhv_vm_delete(vm_id, false);
|
|
print("vm deleted");
|
|
} catch (err) {
|
|
print(`delete failed: ${err}`);
|
|
}
|
|
|
|
print("=== Diagnostic done ==="); |