feat: initial qemu-ga based netvm command to control guest
This commit is contained in:
parent
b64d76b60d
commit
18fa25b87e
|
@ -62,13 +62,14 @@ FROM stagex/user-yq@sha256:47a39bfdeffff4344f41d60aa81671c7fd30c3e5e6d21ced21a05
|
|||
FROM stagex/user-edk2@sha256:db24be51d35117d264dccfc44f0ca331f59d738083170cd9bb86b49a5c06abff AS user-edk2
|
||||
FROM stagex/core-ca-certificates@sha256:d6fca6c0080e8e5360cd85fc1c4bd3eab71ce626f40602e38488bfd61fd3e89d AS core-ca-certificates
|
||||
FROM stagex/user-linux-guest-net@sha256:994b6fe49dd4331b32b0854055bff31b06db5eabdeafb32b2c0d55465b7ccf45 AS user-linux-guest-net
|
||||
FROM stagex/user-linux-airgap@sha256:c8575c92aa63544ee92a820a97034fcc203abf2671c0e7e21d0c4e20daef8827 AS user-linux-airgap
|
||||
FROM stagex/user-linux-airgap@sha256:4f163e5f1f09f87d8f0fcf060193345f0b4dd8dbff2a2b2aec1cd4c254a628ca AS user-linux-airgap
|
||||
FROM stagex/user-libimobiledevice-glue@sha256:3ce674285cbc04b694b7e400703868fcaac65401f2f2ca2aa2b720b3e0efee3c AS user-libimobiledevice-glue
|
||||
FROM stagex/user-libimobiledevice@sha256:fcda68bdc397213fa76bd893472a304b093522aaac28e36f458275b93bb1af34 AS user-libimobiledevice
|
||||
FROM stagex/user-libplist@sha256:2d776cb4eca3689a8bd6ac755a23f492850bf6c7b0c72e3525db6135e4d6e0bc AS user-libplist
|
||||
FROM stagex/user-libusb@sha256:53d499555164f12d9e87118a6d44e1d07f0b1cc9081a29eb66975662be818a00 AS user-libusb
|
||||
FROM stagex/user-libusbmuxd@sha256:1e97f0a2ede0ee5fac9b056d0395e12b77c9f0bf550f9d0c20734ce0617eb51f AS user-libusbmuxd
|
||||
FROM stagex/user-usbmuxd@sha256:90f687d2368328b76141badc382a21873a5b44d4ddccf851c017caf1e78af418 AS user-usbmuxd
|
||||
FROM stagex/user-socat@sha256:990a70ae13462d8ba0a925fe959dd83070cbecdb3f91ff145caca5232171f3b8 AS user-socat
|
||||
|
||||
FROM scratch AS base
|
||||
ARG VERSION development
|
||||
|
@ -124,7 +125,11 @@ COPY --from=user-libimobiledevice . initramfs
|
|||
COPY --from=user-libplist . initramfs
|
||||
COPY --from=user-libusb . initramfs
|
||||
COPY --from=user-libusbmuxd . initramfs
|
||||
COPY --from=core-gcc /usr/lib/. initramfs/usr/lib/
|
||||
COPY --from=user-usbmuxd . initramfs
|
||||
COPY --from=user-glib . initramfs
|
||||
COPY --from=user-numactl . initramfs
|
||||
COPY --from=user-qemu /usr/bin/qemu-ga initramfs/usr/bin/
|
||||
|
||||
COPY src/guest/rootfs/ initramfs
|
||||
RUN <<-EOF
|
||||
|
@ -234,6 +239,7 @@ COPY --from=user-libslirp . initramfs
|
|||
COPY --from=user-seabios . initramfs
|
||||
COPY --from=user-canokey-qemu . initramfs
|
||||
COPY --from=user-qemu . initramfs
|
||||
COPY --from=user-socat . initramfs
|
||||
COPY --from=user-libzbar . initramfs
|
||||
COPY --from=user-keyfork . initramfs
|
||||
COPY --from=user-icepick . initramfs
|
||||
|
|
3
Makefile
3
Makefile
|
@ -73,6 +73,9 @@ vm: out/dev-shell.digest out/airgap.iso out/sdcard.img
|
|||
-device intel-iommu,intremap=on \
|
||||
-netdev user,id=net0 \
|
||||
-device e1000,netdev=net0 \
|
||||
-chardev socket,path=out/qga.sock,server=on,wait=off,id=qga0 \
|
||||
-device virtio-serial \
|
||||
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \
|
||||
$(if $(filter $(EFI),true) ,\
|
||||
-bios /usr/share/ovmf/OVMF.fd \
|
||||
-drive id=boot$(,)if=virtio$(,)format=raw$(,)file=out/airgap.iso \
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: qemu-ga
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop:
|
||||
# Short-Description: Start QEMU Guest Agent
|
||||
### END INIT INFO
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting QEMU Guest Agent"
|
||||
cat /proc/cpuinfo | grep QEMU && qemu-ga &
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping QEMU Guest Agent"
|
||||
killall qemu-ga
|
||||
;;
|
||||
restart)
|
||||
"$0" stop
|
||||
"$0" start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: qemu-ga
|
||||
# Required-Start: $remote_fs $syslog
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop:
|
||||
# Short-Description: Start QEMU Guest Agent
|
||||
### END INIT INFO
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting QEMU Guest Agent"
|
||||
cat /proc/cpuinfo | grep QEMU && qemu-ga &
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping QEMU Guest Agent"
|
||||
killall qemu-ga
|
||||
;;
|
||||
restart)
|
||||
"$0" stop
|
||||
"$0" start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,131 @@
|
|||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
COMMAND=($@)
|
||||
QGA_SOCKET=/var/run/netvm_qga.sock
|
||||
LOCKFILE=/var/run/netvm.pid
|
||||
|
||||
json() {
|
||||
jq -ncM "$@"
|
||||
}
|
||||
|
||||
qemu_execute() {
|
||||
local COMMAND ARGS
|
||||
COMMAND="$1"
|
||||
ARGS="${2-}"
|
||||
|
||||
json --arg cmd "$COMMAND" --argjson args "$ARGS" '{"execute": $cmd, "arguments": $args}' >&$FD_SOCKET_OUT
|
||||
|
||||
local LINE
|
||||
read -t 5 -r -u $FD_SOCKET_IN LINE
|
||||
|
||||
local ERROR=$(jq -r '.error.desc // empty' <<< "$LINE")
|
||||
if [[ -n "$ERROR" ]]; then
|
||||
echo "$ERROR" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
GA_RETURN=$(jq -cM .return <<< "$LINE")
|
||||
}
|
||||
|
||||
qemu_ga() {
|
||||
local COMMAND ARGS
|
||||
COMMAND="$1"
|
||||
ARGS="$2"
|
||||
|
||||
coproc FDS (
|
||||
exec socat - UNIX-CONNECT:"${QGA_SOCKET}"
|
||||
)
|
||||
|
||||
FD_SOCKET_IN=${FDS[0]}
|
||||
FD_SOCKET_OUT=${FDS[1]}
|
||||
|
||||
local PID=$$
|
||||
qemu_execute guest-sync "$(json --argjson pid "$PID" '{"id": $pid}')"
|
||||
[[ "$(jq -re . <<< "$GA_RETURN")" = "$$" ]] || (echo "guest-sync mismatch" >&2 && return 1)
|
||||
|
||||
qemu_execute "$COMMAND" "$ARGS"
|
||||
echo "$GA_RETURN" 2>&1
|
||||
|
||||
local RETURN
|
||||
kill -INT "$FDS_PID" 2>/dev/null
|
||||
wait "$FDS_PID" || RETURN=$?
|
||||
if [[ $RETURN != 130 ]]; then
|
||||
return $RETURN
|
||||
fi
|
||||
}
|
||||
|
||||
function start(){
|
||||
[ ! -f "${LOCKFILE}" ] || { echo "Error: Netvm already running"; exit 1; }
|
||||
echo "Starting netvm";
|
||||
qemu-system-x86_64 -m 512M \
|
||||
--machine q35 \
|
||||
-nographic \
|
||||
-serial none \
|
||||
-monitor none \
|
||||
-net none \
|
||||
-cdrom /guest.img \
|
||||
-boot order=d \
|
||||
-chardev socket,path=/var/run/netvm_qga.sock,server=on,wait=off,id=qga0 \
|
||||
-device virtio-serial \
|
||||
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 &
|
||||
echo $! > "${LOCKFILE}"
|
||||
}
|
||||
|
||||
function stop(){
|
||||
pkill -F "${LOCKFILE}" && rm "${LOCKFILE}"
|
||||
}
|
||||
|
||||
function status(){
|
||||
qemu_ga guest-get-host-name "{}" | jq -r '."host-name"'
|
||||
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 }')" \
|
||||
| jq -r '."out-data"' \
|
||||
| base64 -d \
|
||||
)
|
||||
echo $out
|
||||
}
|
||||
|
||||
function run(){
|
||||
[ -z "${COMMAND[1]}" ] && { echo "Error: missing command"; exit 1; }
|
||||
[ -f "${LOCKFILE}" ] || { echo "Error: Netvm is not running"; exit 1; }
|
||||
[ -S "${QGA_SOCKET}" ] || { echo "Error: Netvm QGA socket is missing"; exit 1; }
|
||||
local cmd="${COMMAND[1]}"
|
||||
local args="${COMMAND[@]:2}"
|
||||
local args_json="[]"
|
||||
if [[ -n "$args" ]]; then
|
||||
args_json=$(printf '%s\n' "$args" | jq -R . | jq -s .)
|
||||
fi
|
||||
local request
|
||||
request=$( \
|
||||
jq -n \
|
||||
--arg path "$cmd" \
|
||||
--argjson args "$args_json" \
|
||||
'{
|
||||
path: $path,
|
||||
arg: $args,
|
||||
"capture-output": true
|
||||
}' \
|
||||
)
|
||||
|
||||
pid=$(qemu_ga guest-exec "$request" | jq -r '.pid')
|
||||
out=$(qemu_ga guest-exec-status "$(jq -n --argjson pid "$pid" '{pid: $pid }')" \
|
||||
| jq -r '."out-data"' \
|
||||
)
|
||||
sleep 1
|
||||
echo $out
|
||||
echo $out | base64 -d
|
||||
}
|
||||
|
||||
function help(){
|
||||
echo "Valid operations: start, stop, run, help"
|
||||
}
|
||||
|
||||
case "${COMMAND[0]}" in
|
||||
status) status ;;
|
||||
start) start ;;
|
||||
stop) stop ;;
|
||||
run) run ;;
|
||||
help) help ;;
|
||||
*) help ;;
|
||||
esac
|
Loading…
Reference in New Issue