feat: netvm push/pull support, fixed run, and lots of cleanup

This commit is contained in:
Lance Vick 2025-04-27 17:45:25 -07:00
parent 18fa25b87e
commit ea07569187
Signed by: lrvick
GPG Key ID: 8E47A1EC35A1551D
1 changed files with 102 additions and 47 deletions

View File

@ -55,7 +55,7 @@ qemu_ga() {
fi fi
} }
function start(){ function cmd_start(){
[ ! -f "${LOCKFILE}" ] || { echo "Error: Netvm already running"; exit 1; } [ ! -f "${LOCKFILE}" ] || { echo "Error: Netvm already running"; exit 1; }
echo "Starting netvm"; echo "Starting netvm";
qemu-system-x86_64 -m 512M \ qemu-system-x86_64 -m 512M \
@ -72,21 +72,53 @@ function start(){
echo $! > "${LOCKFILE}" echo $! > "${LOCKFILE}"
} }
function stop(){ function cmd_stop(){
pkill -F "${LOCKFILE}" && rm "${LOCKFILE}" pkill -F "${LOCKFILE}" && rm "${LOCKFILE}"
} }
function status(){ function cmd_status(){
qemu_ga guest-get-host-name "{}" | jq -r '."host-name"' qemu_ga guest-get-host-name "{}" | jq -r '."host-name"'
pid=$(qemu_ga guest-exec '{"path": "uptime", "capture-output": true}' | jq -r '.pid') pid=$(qemu_ga guest-exec '{"path": "uptime", "capture-output": true}' | jq -r '.pid')
out=$(qemu_ga guest-exec-status "$(jq -n --argjson pid "$pid" '{pid: $pid }')" \ out=$(qemu_ga guest-exec-status "$(jq -n --argjson pid "$pid" '{pid: $pid }')" \
| jq -r '."out-data"' \ | jq -r '."out-data"' \
| base64 -d \ | base64 -d \
) )
echo $out echo $out
} }
function run(){ function cmd_push(){
local source="${COMMAND[1]}"
local dest="${COMMAND[2]}"
fo_request=$(jq -n --arg dest "$dest" '{"path": $dest, "mode": "w" }')
handle=$(qemu_ga guest-file-open "$fo_request")
bufb64=$(base64 "$source")
count=$(cat "$source" | wc -c)
fw_request=$(jq -n \
--argjson handle $handle \
--argjson count $count \
--arg bufb64 "$bufb64" \
'{handle: $handle, "buf-b64": $bufb64, count: $count }' \
)
qemu_ga guest-file-write "$fw_request"
fh_request=$(jq -n --argjson handle $handle '{handle: $handle}' )
qemu_ga guest-file-flush "$fh_request"
qemu_ga guest-file-close "$fh_request"
}
function cmd_pull(){
local source="${COMMAND[1]}"
local dest="${COMMAND[2]}"
fo_request=$(jq -n --arg source "$source" '{"path": $source}')
handle=$(qemu_ga guest-file-open "$fo_request")
fr_request=$(jq -n \
--argjson handle $handle \
'{handle: $handle, count: 48000000 }' \
)
out=$(qemu_ga guest-file-read "$fr_request")
echo $out | jq -r '."buf-b64"' | base64 -d > $dest
}
function cmd_run(){
[ -z "${COMMAND[1]}" ] && { echo "Error: missing command"; exit 1; } [ -z "${COMMAND[1]}" ] && { echo "Error: missing command"; exit 1; }
[ -f "${LOCKFILE}" ] || { echo "Error: Netvm is not running"; exit 1; } [ -f "${LOCKFILE}" ] || { echo "Error: Netvm is not running"; exit 1; }
[ -S "${QGA_SOCKET}" ] || { echo "Error: Netvm QGA socket is missing"; exit 1; } [ -S "${QGA_SOCKET}" ] || { echo "Error: Netvm QGA socket is missing"; exit 1; }
@ -107,25 +139,48 @@ function run(){
"capture-output": true "capture-output": true
}' \ }' \
) )
pid=$(qemu_ga guest-exec "$request" | jq -r '.pid')
pid=$(qemu_ga guest-exec "$request" | jq -r '.pid') local exited=false
out=$(qemu_ga guest-exec-status "$(jq -n --argjson pid "$pid" '{pid: $pid }')" \ until [ "$exited" == "true" ]; do \
| jq -r '."out-data"' \ out=$(qemu_ga guest-exec-status "$(jq -n --argjson pid "$pid" '{pid: $pid }')" )
) exited=$(echo $out | jq -r '.exited')
sleep 1 if $exited && jq -r 'has("out-data")' >/dev/null < <(echo $out); then
echo $out echo "$out" | jq -r '."out-data"' | base64 -d
echo $out | base64 -d break
fi
sleep 1
done
} }
function help(){ cmd_usage() {
echo "Valid operations: start, stop, run, help" cat <<-_EOF
netvm
Control network vm headlessly via QMP protocol
Usage:
netvm start
Start headless network vm in the background
netvm stop
Stop headless network vm
netvm status
Get hostname and uptime from running network vm
netvm push <local-path> <remote-path>
Push a local file to the network VM
netvm pull <remote-path> <local-path>
Pull a file from the network VM
netvm run "<command>"
Run a command in network vm and get stdout
_EOF
} }
case "${COMMAND[0]}" in case "$1" in
status) status ;; status) shift; cmd_status $@ ;;
start) start ;; start) shift; cmd_start $@ ;;
stop) stop ;; stop) shift; cmd_stop $@ ;;
run) run ;; push) shift; cmd_push $@ ;;
help) help ;; pull) shift; cmd_pull $@ ;;
*) help ;; run) shift; cmd_run $@ ;;
help) shift; cmd_usage $@ ;;
*) cmd_usage $@ ;;
esac esac