[Kimchi-devel] [PATCH V3 1/5] Add spice backend support for kimchi
apporc
appleorchard2000 at gmail.com
Sun Dec 22 08:43:06 UTC 2013
1. Add spice support for kimchi template
Now we can specify a spice parameter when creating a template and updating it.
2. Add spice support for kimchi vm
When creating a vm, we have a chance to change the graphics configuration to override
the value from the template.
3. Expose the real port for vnc/spice, so that users can connect vm with popular
vnc/spice client tool.
4. Spice-vdagent support is added too, so that when users happended to install
spice-tool/spice-vdagent in their vm, they will get improved spice graphics effect immediately.
5. Specifying graphics parameters when updating vm is not supported yet, it will be added separately
in another patch.
Signed-off-by: apporc <appleorchard2000 at gmail.com>
---
src/kimchi/controller.py | 10 +++++++---
src/kimchi/model.py | 41 +++++++++++++++++++++++++----------------
src/kimchi/osinfo.py | 5 +++--
src/kimchi/vmtemplate.py | 32 ++++++++++++++++++++++++++++++--
4 files changed, 65 insertions(+), 23 deletions(-)
diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py
index 2940278..dacaa6a 100644
--- a/src/kimchi/controller.py
+++ b/src/kimchi/controller.py
@@ -384,7 +384,10 @@ class VM(Resource):
'screenshot': self.info['screenshot'],
'icon': self.info['icon'],
'graphics': {'type': self.info['graphics']['type'],
- 'port': self.info['graphics']['port']}}
+ 'listen': self.info['graphics']['listen'],
+ 'port': self.info['graphics']['port'],
+ 'real_port': self.info['graphics']['real_port']}
+ }
class VMScreenShot(Resource):
@@ -406,7 +409,7 @@ class Template(Resource):
super(Template, self).__init__(model, ident)
self.update_params = ["name", "folder", "icon", "os_distro",
"storagepool", "os_version", "cpus",
- "memory", "cdrom", "disks"]
+ "memory", "cdrom", "disks", "graphics"]
self.uri_fmt = "/templates/%s"
@property
@@ -420,7 +423,8 @@ class Template(Resource):
'cdrom': self.info['cdrom'],
'disks': self.info['disks'],
'storagepool': self.info['storagepool'],
- 'folder': self.info.get('folder', [])}
+ 'folder': self.info.get('folder', []),
+ 'graphics': self.info['graphics']}
class Interfaces(Collection):
diff --git a/src/kimchi/model.py b/src/kimchi/model.py
index 3bc5d6d..3ee949d 100644
--- a/src/kimchi/model.py
+++ b/src/kimchi/model.py
@@ -503,9 +503,10 @@ class Model(object):
info = dom.info()
state = Model.dom_state_map[info[0]]
screenshot = None
- graphics_type, _ = self._vm_get_graphics(name)
# 'port' must remain None until a connect call is issued
- graphics_port = (self.graphics_ports.get(name, None) if state == 'running'
+ graphics_type, graphics_listen, real_port = self._vm_get_graphics(name)
+ real_port = real_port if state == 'running' else None
+ graphics_port = (self.graphics_ports.get(name) if state == 'running'
else None)
try:
if state == 'running':
@@ -539,7 +540,12 @@ class Model(object):
'cpus': info[3],
'screenshot': screenshot,
'icon': icon,
- 'graphics': {"type": graphics_type, "port": graphics_port}}
+ 'graphics': {"type": graphics_type,
+ "listen": graphics_listen,
+ "port": graphics_port,
+ "real_port": real_port
+ }
+ }
def _vm_get_disk_paths(self, dom):
xml = dom.XMLDesc(0)
@@ -581,24 +587,23 @@ class Model(object):
expr = "/domain/devices/graphics/@type"
res = xmlutils.xpath_get_text(xml, expr)
graphics_type = res[0] if res else None
- port = None
+ expr = "/domain/devices/graphics/@listen"
+ res = xmlutils.xpath_get_text(xml, expr)
+ graphics_listen = res[0] if res else None
+ graphics_port = None
if graphics_type:
expr = "/domain/devices/graphics[@type='%s']/@port" % graphics_type
res = xmlutils.xpath_get_text(xml, expr)
- port = int(res[0]) if res else None
- # FIX ME
- # graphics_type should be 'vnc' or None. 'spice' should only be
- # returned if we support it in the future.
- graphics_type = None if graphics_type != "vnc" else graphics_type
- return graphics_type, port
+ graphics_port = int(res[0]) if res else None
+ return graphics_type, graphics_listen, graphics_port
def vm_connect(self, name):
- graphics, port = self._vm_get_graphics(name)
- if graphics == "vnc" and port != None:
- port = vnc.new_ws_proxy(port)
- self.graphics_ports[name] = port
+ graphics_type, graphics_listen, graphics_port \
+ = self._vm_get_graphics(name)
+ if graphics_port is not None:
+ self.graphics_ports[name] = vnc.new_ws_proxy(graphics_port)
else:
- raise OperationFailed("Unable to find VNC port in %s" % name)
+ raise OperationFailed("Unable to find connection port in %s" % name)
def vms_create(self, params):
conn = self.conn.get()
@@ -629,8 +634,12 @@ class Model(object):
session.store('vm', vm_uuid, {'icon': icon})
libvirt_stream = False if len(self.libvirt_stream_protocols) == 0 else True
+ graphics = params.get('graphics')
- xml = t.to_vm_xml(name, vm_uuid, libvirt_stream, self.qemu_stream_dns)
+ xml = t.to_vm_xml(name, vm_uuid,
+ libvirt_stream=libvirt_stream,
+ qemu_stream_dns=self.qemu_stream_dns,
+ graphics=graphics)
try:
dom = conn.defineXML(xml.encode('utf-8'))
except libvirt.libvirtError as e:
diff --git a/src/kimchi/osinfo.py b/src/kimchi/osinfo.py
index 20a93a6..b8ec244 100644
--- a/src/kimchi/osinfo.py
+++ b/src/kimchi/osinfo.py
@@ -171,7 +171,8 @@ isolinks = {
}
defaults = {'network': 'default', 'storagepool': '/storagepools/default',
- 'domain': 'kvm', 'arch': os.uname()[4]
+ 'domain': 'kvm', 'arch': os.uname()[4],
+ 'graphics':{'type': 'vnc', 'listen': '0.0.0.0'}
}
def lookup(distro, version):
@@ -184,7 +185,7 @@ def lookup(distro, version):
for name, entry in osinfo:
# Test if this entry is a valid match
if entry['version'](distro, version):
- params = copy.copy(defaults)
+ params = copy.deepcopy(defaults)
params['os_distro'] = distro
params['os_version'] = version
params.update(entry)
diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py
index dd43faa..6901e0a 100644
--- a/src/kimchi/vmtemplate.py
+++ b/src/kimchi/vmtemplate.py
@@ -25,6 +25,7 @@ import string
import socket
import urllib
import urlparse
+import copy
from kimchi import isoinfo
@@ -74,6 +75,11 @@ class VMTemplate(object):
self.info.update(entry)
# Override with the passed in parameters
+ graph_args = args.get('graphics')
+ if graph_args:
+ graphics = dict(self.info['graphics'])
+ graphics.update(graph_args)
+ args['graphics'] = graphics
self.info.update(args)
def _get_cdrom_xml(self, libvirt_stream, qemu_stream_dns):
@@ -155,6 +161,24 @@ class VMTemplate(object):
""" % params
return ret
+ def _get_graphics_xml(self, params):
+ graphics_xml = """
+ <graphics type='%(type)s' autoport='yes' listen='%(listen)s'>
+ </graphics>
+ """
+ spicevmc_xml = """
+ <channel type='spicevmc'>
+ <target type='virtio' name='com.redhat.spice.0'/>
+ </channel>
+ """
+ graphics = dict(self.info['graphics'])
+ if params:
+ graphics.update(params)
+ graphics_xml = graphics_xml % graphics
+ if graphics['type'] == 'spice':
+ graphics_xml = graphics_xml + spicevmc_xml
+ return graphics_xml
+
def to_volume_list(self, vm_uuid):
storage_path = self._get_storage_path()
ret = []
@@ -182,7 +206,7 @@ class VMTemplate(object):
ret.append(info)
return ret
- def to_vm_xml(self, vm_name, vm_uuid, libvirt_stream = False, qemu_stream_dns = False):
+ def to_vm_xml(self, vm_name, vm_uuid, **kwargs):
params = dict(self.info)
params['name'] = vm_name
params['uuid'] = vm_uuid
@@ -190,7 +214,11 @@ class VMTemplate(object):
params['qemu-namespace'] = ''
params['cdroms'] = ''
params['qemu-stream-cmdline'] = ''
+ graphics = kwargs.get('graphics')
+ params['graphics'] = self._get_graphics_xml(graphics)
+ qemu_stream_dns = kwargs.get('qemu_stream_dns', False)
+ libvirt_stream = kwargs.get('libvirt_stream', False)
cdrom_xml = self._get_cdrom_xml(libvirt_stream, qemu_stream_dns)
if not libvirt_stream and params.get('iso_stream', False):
params['qemu-namespace'] = QEMU_NAMESPACE
@@ -224,7 +252,7 @@ class VMTemplate(object):
<source network='%(network)s'/>
<model type='%(nic_model)s'/>
</interface>
- <graphics type='vnc' />
+ %(graphics)s
<sound model='ich6' />
<memballoon model='virtio' />
</devices>
--
1.8.1.2
More information about the Kimchi-devel
mailing list