Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow shutdown via guest agent socket #18

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

epsilon-0
Copy link

This allows shutdown events to be sent
via qemu guest agent, which works for
BSD agents which don't handle ACPI events
correctly.

Tested with OpenBSD 7.0.

Signed-off-by: Aisha Tammy [email protected]

This allows shutdown events to be sent
via qemu guest agent, which works for
BSD agents which don't handle ACPI events
correctly.

Tested with OpenBSD 7.0.

Signed-off-by: Aisha Tammy <[email protected]>
@hmrodrigues
Copy link

@jirutka any idea if this will be merged? It's super useful for BSD agents (like OP said)

@@ -125,10 +128,22 @@ stop() {

ebegin "Stopping $name"

if is_running && qemush "${guest_agent_socket}" "{'execute': 'guest-exec', 'arguments': {'path': '/sbin/halt', 'arg': ['-p']}}"; then
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will this do (print) if there’s no guest-agent running in the VM?

@arisudesu
Copy link

Is it really needed to do guest-exec? Mine works fine with {"execute":"guest-shutdown"}. I tested it with Windows 10 guest however, as I am not a BSD expert.

I think that sending guest-shutdown to guest agent and letting it decide how to shutdown the OS it runs on should be more preferred solution instead of calling binaries by their path, which is certainly not going to work in every OS. One example is Windows,

And qga already supports it: https://github.com/search?q=repo%3Aqemu%2Fqemu%20qmp_guest_shutdown&type=code.

One more remark: you forgor to include cleanup code for created socket(s).

My variant of this change is below. You can test it with BSD if you will :)

diff --git a/qemu.confd b/qemu.confd
index 9dfd1cf..6733b08 100644
--- a/qemu.confd
+++ b/qemu.confd
@@ -98,6 +98,8 @@
 # Path of the QEMU monitor socket for this VM.
 #monitor_socket="/run/qemu/${VM_NAME}/monitor.sock"
 
+# Path of the QEMU Guest Agent socket for this VM.
+#qemu_ga_socket="/run/qemu/${VM_NAME}/qemu_ga.sock"
 
 ##
 # Network interfaces
diff --git a/qemu.initd b/qemu.initd
index 9cfb3c7..ee87243 100644
--- a/qemu.initd
+++ b/qemu.initd
@@ -26,6 +26,7 @@ VM_NAME="${RC_SVCNAME#qemu.}"
 : ${vnc_listen:=0.0.0.0}
 : ${hugepages_path:=/dev/hugepages}
 : ${monitor_socket:=/run/qemu/${VM_NAME}/monitor.sock}
+: ${qemu_ga_socket:=/run/qemu/${VM_NAME}/qemu-ga.sock}
 : ${extra_args:=}
 
 name="VM $VM_NAME"
@@ -54,7 +55,10 @@ command_args="
 	-vga $vga
 	-device virtio-rng-pci
 	-device virtio-scsi-pci,id=scsi
-	-monitor unix:$monitor_socket,server,nowait"
+	-monitor unix:$monitor_socket,server,nowait
+	-chardev socket,path=$qemu_ga_socket,server,nowait,id=qga0
+	-device virtio-serial
+	-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0"
 command_background='yes'
 command_user="$user"
 command_group="$group"
@@ -102,7 +106,7 @@ start_pre() {
 		einfo "Command: $command $(printf '%s ' $command_args)"
 	fi
 
-	local path; for path in "$pidfile" "$monitor_socket" "$logfile"; do
+	local path; for path in "$pidfile" "$monitor_socket" "$qemu_ga_socket" "$logfile"; do
 		# checkpath doesn't create intermediate directories
 		mkdir -p "$(dirname "$path")"
 		checkpath -d -m 0750 -o $user:$group "$(dirname "$path")"
@@ -112,8 +116,8 @@ start_pre() {
 }
 
 start_post() {
-	ewaitfile 5 "$monitor_socket" || {
-		eerror 'Monitor socket has not been created!'; return 1
+	ewaitfile 5 "$monitor_socket" "$qemu_ga_socket" || {
+		eerror 'Monitor socket or guest agent socket have not been created!'; return 1
 	}
 	if [ -n "$vnc_password" ]; then
 		qemush "set_password vnc $vnc_password" || eerror 'Failed to set VNC password!'
@@ -126,7 +130,7 @@ stop() {
 
 	ebegin "Stopping $name"
 
-	if is_running && qemush 'system_powerdown'; then
+	if is_running && guestcmd '{"execute":"guest-shutdown"}' && qemush 'system_powerdown'; then
 		count="$shutdown_timeout"
 
 		printf "   Waiting $count seconds for VM shutdown "
@@ -152,6 +156,7 @@ stop() {
 
 stop_post() {
 	[ -S "$monitor_socket" ] && rm -f "$monitor_socket"
+	[ -S "$qemu_ga_socket" ] && rm -f "$qemu_ga_socket"
 	[ -f "$pidfile" ] && rm -f "$pidfile"
 	return 0
 }
@@ -290,6 +295,11 @@ qemush_show() {
 	printf "%b\n" "$*" | socat - "UNIX-CONNECT:${monitor_socket}" | tail -n +3 | head -n -1
 }
 
+guestcmd() {
+	local IFS=$'\n'
+	printf "%b\n" "$*" | socat - "UNIX-CONNECT:${qemu_ga_socket}" 1>/dev/null
+}
+
 gen_macaddr() {
 	printf "$1" | md5sum | sed -E 's/^(..)(..)(..)(..).*$/52:54:\1:\2:\3:\4/'
 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants