基于QMP实现对qemu虚拟机进行交互 + telnet

https://cloud.tencent.com/developer/article/1468105

qemu) "ctrl+]"  to return to telnet,    (qemu)"quit" to exit qemu applicatoin.

 

 

 

 

通过网络连接到QEMU MONITO

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访问:

 

关于这里-monitor的选项,做如下说明:


通过telnet连接到远程的QEMU monitor上:

 

2. QEMU monitor支持RAW socket的远程访问:

 

可以使用netcat去连接这个socket:

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"
  }
}

 

posted on 2020-11-05 17:09  tycoon3  阅读(2181)  评论(0编辑  收藏  举报

导航