QEMU使用Qemu-Guest-Agent传输文件、执行指令等
Qemu和宿主机不使用外网进行文件传输。这是一种方式,这里还有另一种方式:使用,后面简称qga。
简介
之前介绍过qemu传输文件,使用的挂载 / samba方式 :Qemu和宿主机不使用外网进行文件传输。
这是一种方式,这里还有另一种方式:使用Qemu-Guest-Agent,后面简称qga。
官网介绍:https://www.qemu.org/docs/master/interop/qemu-ga.html
安装
这里有一篇参考文章,会比我下面介绍的相对复杂一点,但也可以完成操作。
参考文章:https://www.easystack.cn/doc/ComputingService/6.1.1/zh-cn/FAQs/DeployQGA.html
一、Linux的Qemu机器
直接install命令即可,查看上面的参考链接即可。
二、Windows的Qemu机器
Windows的Qemu机器:需要安装好virtio-serial driver,下面详细介绍一下:
首先下载该文件(1积分),这个文件我已经测试了Windows7-10、Centos7-8、Ubuntu16-24可用:Qemu-Guest-Agnet整理包
这是一个Windows整理后的qga包,包含amd64.zip和qemu-ga.zip两个文件,请都解压出来。
1、amd64:首先安装证书,管理员运行cmd,命令:pnputil -I -a vioser.inf
2、qemu-ga:将qemu-ga目录放到C:\Program Files下,管理员运行cmd,命令:qemu-ga -s install
3、然后检查【服务】,是否包含以下两个服务,如果存在,则说明安装成功,将两个内容全部设置为自动启动
QEMU Guest Agent
QEMU Guest Agent VSS Provider
4、验证
转为qcow2上传到linux服务器,运行以下指令(假设该qcow2文件名字为Windows10.qcow2)
运行以下内容
qemu-system-x86_64 -name test -hda Windows10.qcow2 -m 4096M -smp cpus=2,sockets=1 -enable-kvm -netdev user,id=net0 -device e1000,netdev=net0 -chardev socket,path=/tmp/test.sock,server=on,wait=off,id=qga0 -device virtio-serial -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 -machine usb=on -device usb-tablet
成功开机后,有可能QEMU Guest Agent服务并没有成功运行,那么此时到【服务】中手动开启,如果能手动开启成功,则没问题(下次就能自动开启了)。
此时,使用命令socat - unix-connect:/tmp/test.sock
,连接上以后,输入一些命令测试一下,如:{"execute":"guest-info"}
。
使用
前面安装没问题以后,就可以用代码去连接socket文件并执行内容了。这里写几个demo
1、获取系统信息
import asyncio
import json
class QEMUGuestAgent(object):
endpoint: str
def __init__(self, endpoint):
self.endpoint = endpoint
async def execute(self, command, timeout=2.0):
try:
reader, writer = await asyncio.open_unix_connection(self.endpoint)
writer.write(json.dumps(command).encode())
response = await asyncio.wait_for(reader.readline(), timeout)
writer.close()
return json.loads(response)
except ConnectionAbortedError:
print("ConnectionAbortedError: QEMU Agent功能未开启")
return {}
except asyncio.TimeoutError:
print("TimeoutError: Agent 未安装或运行")
return {}
async def get_os_info(self):
"""
查询虚拟机操作系统版本
:param command:
:return:
"""
command = {
"execute": "guest-get-osinfo"
}
return await self.execute(command)
async def main():
if __name__ == '__main__':
qga = QEMUGuestAgent("/tmp/test.sock")
rv = await qga.get_os_info()
print(rv)
2、上传文件
import asyncio
import json
class QEMUGuestAgent(object):
endpoint: str
def __init__(self, endpoint):
self.endpoint = endpoint
async def execute(node_id, command, timeout=30.0):
try:
qga_location = f'/tmp/{node_id}.sock'
if not os.path.exists(qga_location):
raise aiohttp.web.HTTPBadRequest(text="系统未启动或不支持QEMU Agent功能")
reader, writer = await asyncio.open_unix_connection(qga_location)
writer.write(json.dumps(command).encode())
response = await asyncio.wait_for(reader.readline(), timeout)
writer.close()
return json.loads(response)
except ConnectionAbortedError:
raise aiohttp.web.HTTPBadRequest(text="ConnectionAbortedError: QEMU Agent功能未开启")
except asyncio.TimeoutError:
raise aiohttp.web.HTTPBadRequest(text="TimeoutError: QEMU Agent未安装或运行")
# 执行指令
async def guest_exec(node_id, arguments):
arguments['capture-output'] = True
command = {"execute": "guest-exec", "arguments": arguments}
rv = await execute(node_id, command)
command = {"execute": "guest-exec-status", "arguments": {"pid": rv['return']["pid"]}}
return await execute(node_id, command)
# 创建文件夹
async def mkdir(node_id, type, path):
if type == 'win':
command = {"path": "cmd", "arg": ["/c", "mkdir {}".format(path)]}
elif type == 'linux':
command = {"path": "sh", "arg": ["-c", "mkdir -p {}".format(path)]}
else:
raise aiohttp.web.HTTPBadRequest(text="不支持的系统类型")
rv = await guest_exec(node_id, command)
return rv['return']
async def upload_file(self, path, mode="r"):
## 获取系统os_type代码略(参考上一个代码块)
# 创建kvm的路径文件夹
await mkdir(node_id, os_type, target_address)
await asyncio.sleep(0.5)
try:
# 1. 获取文件句柄
command = {
"execute": "guest-file-open",
"arguments": {
"path": path, ## 该文件上传到qemu内的地址
"mode": 'w'
}
}
rv = await self.execute(command)
# TODO: 判断返回值, 文件不存在会报错
fd = rv['return']
return fd
except:
raise aiohttp.web.HTTPBadRequest(text="文件传输失败")
with open(file_path, 'rb') as f:
buf = base64.b64encode(f.read())
command = {"execute": "guest-file-write", "arguments": {"handle": fd, "buf-b64": buf.decode()}}
await execute(node_id, command)
# 关闭文件句柄
command = {"execute": "guest-file-close", "arguments": {"handle": fd}}
rv = await execute(node_id, command)
if os_type == 'linux':
# 因为qga上传为root用户,所以为了其他用户能访问,将目录和其下内容赋权777
command = {"path": "sh", "arg": ["-c", "chmod -R 777 {}".format(target_address)]}
await guest_exec(node_id, command)
return rv['return']
async def main():
if __name__ == '__main__':
qga = QEMUGuestAgent("/tmp/test.sock")
fd = await qga.upload_file("C:\\cccc\\1111.txt", mode="w")
其他的比如下载文件、在qemu内执行指令等功能参考:https://www.qemu.org/docs/master/interop/qemu-ga-ref.html。
更多推荐
所有评论(0)