https://cloud.tencent.com/developer/article/1468105
qemu) "ctrl+]" to return to telnet, (qemu)"quit" to exit qemu applicatoin.
http://smilejay.com/2014/01/access-qemu-monitor-accross-network/
qemu-system-aarch64 -name vm2 -daemonize \ -enable-kvm -M virt -cpu host -smp 2 -m 4096 \ -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on \ -numa node,memdev=mem -mem-prealloc \ -global virtio-blk-device.scsi=off \ -device virtio-scsi-device,id=scsi \ -kernel vmlinuz-4.18 --append "console=ttyAMA0 root=UUID=6a09973e-e8fd-4a6d-a8c0-1deb9556f477 iommu=pt intel_iommu=on iommu.passthrough=1" \ -initrd initramfs-4.18 \ -drive file=vhuser-test1.qcow2 \ -device vfio-pci,host=0000:05:00.0 \ -net nic,macaddr=00:00:00:99:99:01 \ -monitor telnet:localhost:4321,server,nowait\ -vnc :10
system_powerdown不能关机,quit可以关机
[root@localhost cloud_images]# telnet localhost 4321 Trying ::1... Connected to localhost. Escape character is '^]'. QEMU 5.1.90 monitor - type 'help' for more information (qemu) system_powerdown (qemu) quit Connection closed by foreign host. [root@localhost cloud_images]#
关机命令
{ "execute": "stop" }
[root@localhost cloud_images]# telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
{"QMP": {"version": {"qemu": {"micro": 90, "minor": 1, "major": 5}, "package": "v5.2.0-rc0-dirty"}, "capabilities": ["oob"]}}
ifo^H^H
{"error": {"class": "GenericError", "desc": "JSON parse error, invalid keyword 'ifo'"}}
{"error": {"class": "GenericError", "desc": "JSON parse error, stray '\b'"}}
{"error": {"class": "GenericError", "desc": "JSON parse error, stray '\b'"}}
info
{"error": {"class": "GenericError", "desc": "JSON parse error, invalid keyword 'info'"}}
qmp_system_powerdown
{"error": {"class": "GenericError", "desc": "JSON parse error, invalid keyword 'qmp'"}}
{"error": {"class": "GenericError", "desc": "JSON parse error, stray '_'"}}
^]
telnet>
^]
telnet> qmp_system_powerdown
?Invalid command
telnet> ^[[A^H^H
?Invalid command
telnet> shutdown
?Invalid command
telnet> powerwo^H^H
?Invalid command
telnet> powerdown
?Invalid command
telnet> quit
Connection closed.
[root@localhost cloud_images]# telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
{"QMP": {"version": {"qemu": {"micro": 90, "minor": 1, "major": 5}, "package": "v5.2.0-rc0-dirty"}, "capabilities": ["oob"]}}
{ "execute": "stop" }
Connection closed by foreign host.
[root@localhost cloud_images]#
[root@localhost binary]# nc -U qmp.sock
{"QMP": {"version": {"qemu": {"micro": 90, "minor": 1, "major": 5}, "package": "v5.2.0-rc0-dirty"}, "capabilities": ["oob"]}}
{ "execute": "stop" }
Ncat: Connection reset by peer.
[root@localhost binary]#
1. QEMU monitor支持远程telnet访问:
|
1
|
# qemu-system-x86_64 -enable-kvm -smp 2 -m 1024 vm2.img -monitor telnet:10.1.77.82:4444,server,nowait
|
关于这里-monitor的选项,做如下说明:
|
1
2
3
4
5
6
|
#下面第2点,我的举例是RAW TCP socket
option
.
.
mode
.
|
通过telnet连接到远程的QEMU monitor上:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
4444
10.1.77.82...
10.1.77.82.
.
information
kvm
enabled
status
running
migrate
)
disk
)
telnet连接)
telnet)
.
|
2. QEMU monitor支持RAW socket的远程访问:
|
1
|
# qemu-system-x86_64 -enable-kvm -smp 2 -m 1024 vm2.img -monitor tcp:10.1.77.82:4444,server,nowait
|
可以使用netcat去连接这个socket:
|
1
2
3
4
5
6
|
4444
information
kvm
kvm
enabled
C
|
QMP介绍
qemu对外提供了一个socket接口,称为qemu monitor,通过该接口,可以对虚拟机实例的整个生命周期进行管理,主要有如下功能
▷ 状态查看、变更
▷ 设备查看、变更
▷ 性能查看、限制
▷ 在线迁移
▷ 数据备份
▷ 访问内部操作系统
通过该socket接口传递交互的协议是qmp,全称是qemu monitor protocol,这是基于json格式的协议
在继续往下讲之前,需要先了解qemu、kvm、libvirt之间的区别(因为有很多童鞋对这三者的理解是混乱的)
▷ qemu:虚拟机仿真器。通过软件模拟出cpu、内存、磁盘、主板、网卡等设备
▷ kvm:高性能的cpu仿真器。由于软件模拟的cpu性能很差,因此出现了kvm,这是通过硬件与内核的支持实现接近native性能的cpu仿真器,可以理解为虚拟机里的cpu任务直接交给物理机cpu完成。
▷ libvirt:虚拟机管理平台。能纳管qemu、lxc、esx等虚拟化软件,通过编写xml实现对虚拟机、存储、网络等进行配置和管理
单独使用qemu,启用QMP
启动qemu虚拟机
# qemu monitor采用tcp方式,监听在127.0.0.1上,端口为4444
/usr/libexec/qemu-kvm -qmp tcp:127.0.0.1:4444,server,nowait
# qemu monitor采用unix socket,socket文件生成于/opt/qmp.socket
/usr/libexec/qemu-kvm -qmp unix:/opt/qmp.socket,server,nowait
连接qemu monitor
# tcp可以通过telnet进行连接,方法如下
> telnet 127.0.0.1 4444
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
{"QMP": {"version": {"qemu": {"micro": 0, "minor": 12, "major": 2}, "package": "qemu-kvm-ev-2.12.0-18.el7_6.1.1"}, "capabilities": []}}
# unix socket可以通过nc -U进行连接,方法如下
> nc -U qmp.socket
{"QMP": {"version": {"qemu": {"micro": 0, "minor": 12, "major": 2}, "package": "qemu-kvm-ev-2.12.0-18.el7_6.1.1"}, "capabilities": []}}
按照上面执行完命令后,不会退出而是继续等待输入,但这个时候还无法使用,接着,需要输入一条qmp指令才可以
{ "execute" : "qmp_capabilities" }
此时屏幕会输出以下内容,表示从"capabilities negotiation模式"进入了"command"模式
{"return": {}}
接下来,就可以执行qmp的指令了,qmp指令非常多,由于篇幅有限,这里仅举几个例子(更多内容请参考官方文档,本文最后附上网址)
# 查看支持哪些qmp指令
{ "execute": "query-commands" }
# 虚拟机状态
{ "execute": "query-status" }
# 虚拟机暂停
{ "execute": "stop" }
# 磁盘查看
{ "execute": "query-block" }
# 磁盘在线插入
{ "execute": "blockdev-add", "arguments": { "driver": "qcow2", "node-name": "drive-virtio-disk1", "file": { "driver": "file", "filename": "/opt/data.qcow2" } } }
{ "execute": "device_add", "arguments": { "driver": "virtio-blk-pci", "drive": "drive-virtio-disk1" } }
# 磁盘完整备份
{ "execute" : "drive-backup" , "arguments" : { "device" : "drive-virtio-disk0" , "sync" : "full" , "target" : "/opt/backuptest/fullbackup.img" } }
进入command模式后,不仅能够执行命令,还同时成为了事件的输出端口,比如执行磁盘备份命令后,应该就会陆续接收到一些关于备份成功或失败的事件,比如:
{ "execute" : "drive-backup" , "arguments" : { "device" : "drive-virtio-disk0" , "sync" : "top" ,"target" : "/opt/ccvm/A" } }
{"timestamp": {"seconds": 1551061368, "microseconds": 725212}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "drive-virtio-disk0"}}
{"timestamp": {"seconds": 1551061368, "microseconds": 725330}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "drive-virtio-disk0"}}
{"return": {}}
{"timestamp": {"seconds": 1551061373, "microseconds": 276382}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "drive-virtio-disk0"}}
{"timestamp": {"seconds": 1551061373, "microseconds": 276462}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "drive-virtio-disk0"}}
{"timestamp": {"seconds": 1551061373, "microseconds": 276508}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drive-virtio-disk0", "len": 21474836480, "offset": 11141120, "speed": 0, "type": "backup"}}
{"timestamp": {"seconds": 1551061373, "microseconds": 276551}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "drive-virtio-disk0"}}
{"timestamp": {"seconds": 1551061373, "microseconds": 276583}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "drive-virtio-disk0"}}
上面第一行是执行命令,接下来的就是陆续接收到的事件,这与linux的tty终端很像 接收到的事件不仅是本窗口命令执行的相关事件,而是会收到所有qmp事件,比如开了多个qmp监听器,那么只要监听器进入command模式,就都会同时接收到事件(下面还提到了libvirt启动qmp,也是一样的效果)
除了使用telnet、nc从外部连接,还可以在qemu启动时候进入一个交互的cli界面,直接输入指令,只不过这个时候输入的是hmp(human monitor protocol),而不是qmp。hmp简化了qmp的使用,但实际在底层依然是转化为qmp进行操作的,配置方法如下
/usr/libexec/qemu-kvm -qmp tcp:127.0.0.1:4444,server,nowait -monitor stdio
此时会出现交互界面,输入help,就可以看到hmp支持的所有命令
(qemu) help
使用hmp不需要输入类似qmp的{ "execute" : "qmp_capabilities" }
这里列出几个范例
# 直接输入info回车,可以看到所有查询类的指令使用方法
(qemu) info
# 查看块设备
(qemu) info block
# 在线增加磁盘
(qemu) drive_add 0 file=/opt/data.qcow2,format=qcow2,id=drive-virtio-disk1,if=none
(qemu) device_add virtio-blk-pci,scsi=off,drive=drive-virtio-disk1
还有一种脱裤子放屁的hmp写法,是将hmp套在qmp里,
{
"execute" : "human-monitor-command",
"arguments" : {
"command-line" : "这里写hmp语法"
}
}
比如
{
"execute" : "human-monitor-command",
"arguments" : {
"command-line" : "drive_add -n buddy driver=replication,mode=primary,file.driver=nbd,file.host=xxxx,file.port=xxxx,file.export=colo1,node-name=nbd_client1"
}
}