[Kimchi-devel] [PATCH V5 1/5] Add spice backend support for kimchi

apporc appleorchard2000 at gmail.com
Fri Jan 10 12:44:19 UTC 2014


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/control/templates.py |    6 ++++--
 src/kimchi/control/vms.py       |    4 +++-
 src/kimchi/model.py             |   34 +++++++++++++++++++++-------------
 src/kimchi/osinfo.py            |    7 ++++---
 src/kimchi/vmtemplate.py        |   31 +++++++++++++++++++++++++++++--
 5 files changed, 61 insertions(+), 21 deletions(-)

diff --git a/src/kimchi/control/templates.py b/src/kimchi/control/templates.py
index bf40e2c..a77936e 100644
--- a/src/kimchi/control/templates.py
+++ b/src/kimchi/control/templates.py
@@ -35,7 +35,8 @@ class Template(Resource):
         super(Template, self).__init__(model, ident)
         self.update_params = ["name", "folder", "icon", "os_distro",
                               "storagepool", "os_version", "cpus",
-                              "memory", "cdrom", "disks", "networks"]
+                              "memory", "cdrom", "disks", "networks",
+                              "graphics"]
         self.uri_fmt = "/templates/%s"
 
     @property
@@ -50,4 +51,5 @@ class Template(Resource):
                 'disks': self.info['disks'],
                 'storagepool': self.info['storagepool'],
                 'networks': self.info['networks'],
-                'folder': self.info.get('folder', [])}
+                'folder': self.info.get('folder', []),
+                'graphics': self.info['graphics']}
diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py
index d722920..7843be7 100644
--- a/src/kimchi/control/vms.py
+++ b/src/kimchi/control/vms.py
@@ -53,7 +53,9 @@ 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']}
+                }
 
 
 class VMScreenShot(Resource):
diff --git a/src/kimchi/model.py b/src/kimchi/model.py
index ed613b1..4f4b837 100644
--- a/src/kimchi/model.py
+++ b/src/kimchi/model.py
@@ -503,7 +503,8 @@ class Model(object):
         info = dom.info()
         state = Model.dom_state_map[info[0]]
         screenshot = None
-        graphics_type, graphics_port = self._vm_get_graphics(name)
+        graphics_type, graphics_listen, graphics_port = self._vm_get_graphics(name)
+        graphics_port = graphics_port if state == 'running' else None
         try:
             if state == 'running':
                 screenshot = self.vmscreenshot_lookup(name)
@@ -536,7 +537,10 @@ 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}
+                }
 
     def _vm_get_disk_paths(self, dom):
         xml = dom.XMLDesc(0)
@@ -580,21 +584,21 @@ 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:
-            vnc.add_proxy_token(name, port)
+        graphics_type, graphics_listen, graphics_port \
+            = self._vm_get_graphics(name)
+        if graphics_port is not None:
+            vnc.add_proxy_token(name, graphics_port)
         else:
             raise OperationFailed("Only able to connect to running vm's vnc "
                                   "graphics.")
@@ -628,8 +632,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 0509622..f92db3d 100644
--- a/src/kimchi/osinfo.py
+++ b/src/kimchi/osinfo.py
@@ -73,8 +73,9 @@ isolinks = {
 
 defaults = {'networks': ['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 _get_arch():
@@ -90,7 +91,7 @@ def lookup(distro, version):
     'defaults' and merging the parameters given for the identified OS.  If
     known, a link to a remote install CD is added.
     """
-    params = copy.copy(defaults)
+    params = copy.deepcopy(defaults)
     params['os_distro'] = distro
     params['os_version'] = version
     params['cdrom'] = isolinks.get(distro, {}).get(version, '')
diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py
index 6587bbb..58147e3 100644
--- a/src/kimchi/vmtemplate.py
+++ b/src/kimchi/vmtemplate.py
@@ -76,6 +76,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):
@@ -157,6 +162,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 = []
@@ -198,7 +221,7 @@ class VMTemplate(object):
             networks += network % net_info
         return networks
 
-    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
@@ -207,7 +230,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
@@ -238,7 +265,7 @@ class VMTemplate(object):
             %(disks)s
             %(cdroms)s
             %(networks)s
-            <graphics type='vnc' />
+            %(graphics)s
             <sound model='ich6' />
             <memballoon model='virtio' />
           </devices>
-- 
1.7.9.5




More information about the Kimchi-devel mailing list