使用 qemu 监视器连接到正在运行的 qemu 实例

Cut*_*Eye 14 qemu

我有一个qemu在 Windows 7上运行的实例,在没有打开终端的情况下运行。现在我想关闭名为MyMachineName的机器或向其添加 USB 设备。我需要一个可编写脚本的解决方案。Libvirt 不是解决方案,因为它对我的系统还有其他缺点。

我正在寻找一条神奇的线,例如:

qemu-monitor -connect=MyMachineName command="shutdown"
Run Code Online (Sandbox Code Playgroud)

我该怎么做?

Boa*_*ann 21

我首选的方法是通过 UNIX 套接字连接到 QEMU“监视器”。它运行良好,尽管该方法的记录非常少。

启动QEMU时,添加-monitor如下参数:

$ qemu-system-i386 [..other params..] -monitor unix:qemu-monitor-socket,server,nowait
Run Code Online (Sandbox Code Playgroud)

qemu-monitor-socket这里不是关键字,而是您选择的主机路径和文件名来表示磁盘上的套接字。您将看到 QEMU 启动时创建的这个文件。

这些选项server,nowait告诉 QEMU 侦听连接,但不等待连接就启动 VM。

您可以使用socat实用程序(可从所有好的存储库获得)连接到套接字以在 QEMU 监视器提示符下键入命令:

$ socat -,echo=0,icanon=0 unix-connect:qemu-monitor-socket
QEMU 2.8.1 monitor - type 'help' for more information
(qemu) _
Run Code Online (Sandbox Code Playgroud)

socat 所做的是将两个任意流/套接字连接在一起。第一个参数-是 的同义词stdio,即控制台键盘和输出。这两个选项echo=0,icanon=0通过防止重新回显输入的命令并启用Tab历史记录的完成键和箭头键,使键盘交互变得更好。最后一个参数表示连接到之前创建的套接字文件。

要将一次性命令发送到 QEMU,请通过 socat 将其回显到 UNIX 套接字:

$ echo "info status" | socat - unix-connect:qemu-monitor-socket
QEMU 2.8.1 monitor - type 'help' for more information
(qemu) info status
VM status: running
(qemu)
$ _
Run Code Online (Sandbox Code Playgroud)

为了使脚本中的输出更清晰,我还添加| tail --lines=+2 | grep -v '^(qemu)'了过滤掉第一行和(qemu)提示行的内容:

$ echo "info status" | socat - unix-connect:qemu-monitor-socket | tail --lines=+2 | grep -v '^(qemu)'
VM status: running
$ _
Run Code Online (Sandbox Code Playgroud)

要根据需要关闭 VM,有用的监视器命令是system_powerdown,按下虚拟机器的开/关按钮,使其可以正常关闭,或者quit,立即退出 QEMU。

一些注意事项:

  • QEMU 还允许-qmp代替-monitor,提供基于 JSON 的接口;这对于程序控制可能更健壮,但我从未尝试过。

  • 磁盘上的套接字文件始终为空。它不存储数据;它只是程序打开通信的任意句柄。

  • 这为新手提供了一些关于 qemu 如何与套接字一起工作的更有用的信息!=) (2认同)
  • @Binarus 上面的 socat 的第一个示例为您提供了交互式 shell。 (2认同)
  • 按照这些示例,您是否得到了“设备的 ioctl 不合适”?您可能遇到了 socat 错误。尝试交换它的参数。https://bugs.launchpad.net/ubuntu/+source/socat/+bug/1883957 (2认同)

小智 10

Someone might be able to chime in with a proper command for operating on TTYs, but I'll post a solution in the meantime involving the network.

There are a couple options for redirecting the QEMU monitor. One way is to have QEMU offer access to its monitor via telnet:

$ qemu-system-i386 -monitor telnet:127.0.0.1:55555,server,nowait;
Run Code Online (Sandbox Code Playgroud)

Then, QEMU can be scripted by piping commands to telnet. This is fine as long as the output of commands can be discarded since the telnet session will probably close too quickly for visual feedback:

$ echo system_powerdown |telnet 127.0.0.1 55555
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.
$ _  # qemu sends the guest an ACPI shutdown signal
Run Code Online (Sandbox Code Playgroud)

If the output of the commands executed on the monitor need to be collected, a TCP session can be used instead:

$ qemu-system-i386 -monitor tcp:127.0.0.1:55555,server,nowait;
Run Code Online (Sandbox Code Playgroud)

Then, commands can be sent to the listening monitor via netcat or a similar utility:

$ echo info\ kvm |nc -N 127.0.0.1 55555
QEMU 2.11.0 monitor - type 'help' for more information
(qemu) info kvm
kvm support: enabled
(qemu) $ echo system_powerdown |nc -N 127.0.0.1 55555
QEMU 2.11.0 monitor - type 'help' for more information
(qemu) system_powerdown
(qemu) $  # hit return
$ _  # qemu sends the guest an ACPI shutdown signal
Run Code Online (Sandbox Code Playgroud)

Here is a link to partial documentation of QEMU monitor commands: https://en.wikibooks.org/wiki/QEMU/Monitor