1.在virsh的xml定义中加入channel指定host的socket映射到guest的dev
用virsh启动虚拟机的时候
注意加channel
<channel type='unix'>
<source mode='bind' path='/var/lib/libvirt/qemu/test.agent'/>
<target type='virtio' name='com.haoning.spice.0'/>
<alias name='channel0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
2.在guest中启动qemu-ga:
qemu-ga -v -p /dev/virtio-ports/com.haoning.spice.0
3.在host上使用python连socket或者socat
socat unix-connect:/var/lib/libvirt/qemu/test.agent readline
具体的control.xml
<domain type='kvm' id='12'>
<name>control</name>
<uuid>d07d7290-9b1d-f33e-f54a-70a821252410</uuid>
<memory unit='KiB'>4194304</memory>
<currentMemory unit='KiB'>4194304</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='x86_64' machine='rhel6.5.0'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/home/rhel-server-6.5-x86_64-dvd.iso'/>
<target dev='hdc' bus='ide'/>
<readonly/>
<alias name='ide0-1-0'/>
<address type='drive' controller='0' bus='1' target='0' unit='0'/>
</disk>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source file='/home/control.img'/>
<target dev='vda' bus='virtio'/>
<alias name='virtio-disk0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</disk>
<controller type='usb' index='0'>
<alias name='usb0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='virtio-serial' index='0'>
<alias name='virtio-serial0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</controller>
<interface type='bridge'>
<mac address='52:54:02:a1:90:81'/>
<source bridge='br0'/>
<target dev='vnet0'/>
<model type='virtio'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/1'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/1'>
<source path='/dev/pts/1'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<channel type='unix'>
<source mode='bind' path='/var/lib/libvirt/qemu/test.agent'/>
<target type='virtio' name='com.haoning.spice.0'/>
<alias name='channel0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='5900' autoport='no' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<sound model='ich6'>
<alias name='sound0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</sound>
<video>
<model type='cirrus' vram='9216' heads='1'/>
<alias name='video0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</memballoon>
</devices>
<seclabel type='dynamic' model='selinux' relabel='yes'>
<label>system_u:system_r:svirt_t:s0:c681,c978</label>
<imagelabel>system_u:object_r:svirt_image_t:s0:c681,c978</imagelabel>
</seclabel>
</domain>
virsh define control.xml
virsh start control
在guest中
[root@control ~]# qemu-ga -v -p /dev/virtio-ports/com.haoning.spice.0
1437616495.53279: debug: received EOF
1437616495.153410: debug: received EOF
1437616495.253627: debug: received EOF
1437616495.353849: debug: received EOF
1437616495.454057: debug: received EOF
1437616495.554266: debug: received EOF
1437616495.654507: debug: received EOF
1437616495.754719: debug: received EOF
1437616495.854928: debug: received EOF
1437616495.955151: debug: received EOF
1437616496.55375: debug: received EOF
1437616496.155490: debug: received EOF
^C1437616496.170249: debug: received signal num 2, quitting
[root@control ~]#
[root@node11 ~]# ls
poll_qemu_guest_agent.py
[root@node11 ~]# cat poll_qemu_guest_agent.py
#! /usr/bin/python
import base64
import json
import select
import socket
#sock_file = "/tmp/foo.sock"
sock_file = "/var/lib/libvirt/qemu/test.agent"
#import pdb;pdb.set_trace()
READ_LEN = 1024
read_file = "/proc/cpuinfo"
send_cmds = [{"execute": "guest-file-open", "arguments": {"path": read_file, "mode": "r"}},
{"execute": "guest-file-read", "arguments": {"handle": None, "count": READ_LEN}},
{"execute": "guest-file-close", "arguments": {"handle": None}}]
serversocket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
serversocket.connect(sock_file)
serversocket.setblocking(0)
vm_fileno = serversocket.fileno()
instances = {}
instances[vm_fileno] = "instance-000004e8"
epoll = select.epoll()
epoll.register(vm_fileno, select.EPOLLIN | select.EPOLLOUT | select.EPOLLET)
try:
#import ipdb;ipdb.set_trace()
cmd = 0
stop = False
while True:
print '-'*10 + 'start epoll' + '-'*10
events = epoll.poll(1)
for fileno, event in events:
if fileno in instances.keys():# new client is connecting
print 'instance: ' + instances[fileno]
if event & select.EPOLLIN: # new msg is coming in
print "<<<<<<<<<<<recv"
try:
vm_resp = ''
while True:
vm_resp += serversocket.recv(READ_LEN)
except socket.error:
pass
epoll.modify(fileno, select.EPOLLOUT | select.EPOLLET)
try:
vm_resps = vm_resp.split('\n')
ok_resp = None
for resp in vm_resps:
if 'error' not in resp and 'return' in resp:
ok_resp = resp
break
elif 'error' in resp:
print 'error occurs: ', resp
if ok_resp is not None:
resp = json.loads(ok_resp)
else:
print 'no valid data recv'
break
except ValueError:
print 'response content error: ', vm_resp
break
if len(send_cmds) <= cmd:
stop = True
print resp
break
try:
if cmd == 1:
print('+'*10 + 'receive:' + '+'*10 + '\n' + vm_resp)
handle = resp["return"]
send_cmds[cmd]["arguments"]["handle"] = handle
send_cmds[cmd+1]["arguments"]["handle"] = handle
elif cmd == 2:
decoded_file = base64.decodestring(resp["return"]["buf-b64"])
print 'file content:\n', decoded_file
print resp["return"]["count"]
print 'EOF: ', resp["return"]["eof"]
except (KeyError, ValueError, TypeError):
print 'response content error: ', resp
elif event & select.EPOLLOUT: # new msg need send out
print ">>>>>>>>>send"
if len(send_cmds) <= cmd:
print 'no data to send'
break
try:
byteswritten = 0
data = json.dumps(send_cmds[cmd])
while True:
byteswritten += serversocket.send(data[byteswritten:])
if byteswritten == len(data):
print '*'*10 + 'send over' + '*'*10
break
except socket.error:
pass
epoll.modify(fileno, select.EPOLLIN | select.EPOLLET)
cmd += 1
elif event & select.EPOLLHUP: # connect closed
epoll.unregister(serversocket.fileno())
serversocket.close()
print '-'*10 + 'end epoll' + '-'*10 + '\n'
if stop:
print 'stop now'
break
finally:
epoll.unregister(serversocket.fileno())
epoll.close()
serversocket.close()
[root@node11 ~]#
用socat调用
socat unix-connect:/tmp/qga.sock readline
{"execute":"guest-sync", "arguments":{"id":1234}}
{"return": 1234}
socat参考
http://wiki.qemu.org/Features/QAPI/GuestAgent
libvirt配置参考
http://wiki.libvirt.org/page/Qemu_guest_agent
其他参考
http://aspirer2004.blog.163.com/blog/static/1067647201352423628885/