[Kimchi-devel] [PATCH] Template: Check if the host supports Spice

zhshzhou at linux.vnet.ibm.com zhshzhou at linux.vnet.ibm.com
Tue Mar 25 07:53:41 UTC 2014


From: Zhou Zheng Sheng <zhshzhou at linux.vnet.ibm.com>

On some architecture of hosts, such as ppc64 hosts, QEMU is not compiled
with Spice. So we'd like to disable Spice on these hosts. Unfortunately
even QEMU is not compiled with Spice, 'qemu --help' still prints Spice
related help. In this patch we use ldd to determine if QEMU is linked to
libspice-server.so, and provide this information through the
/config/capabilities URI. The front-end code then checks the capabilities
and add or remove Spice from the graphic options respectively.

Signed-off-by: Zhou Zheng Sheng <zhshzhou at linux.vnet.ibm.com>
---
 docs/API.md                            |  1 +
 src/kimchi/config.py.in                | 10 +++++++---
 src/kimchi/mockmodel.py                |  1 +
 src/kimchi/model/config.py             | 15 ++++++++++++++-
 tests/test_rest.py                     |  1 +
 ui/js/src/kimchi.api.js                |  6 ++++--
 ui/js/src/kimchi.template_edit_main.js | 13 +++++++++++--
 7 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/docs/API.md b/docs/API.md
index a380558..3711fbe 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -573,6 +573,7 @@ creation.
 * **GET**: Retrieve capabilities information
     * libvirt_stream_protocols: list of which network protocols are accepted
       for iso streaming by libvirt
+    * qemu_spice: True, if QEMU supports Spice; False, otherwise
     * qemu_stream: True, if QEMU supports ISO streaming; False, otherwise
     * screenshot: True, if libvirt stream functionality can create screenshot
       file without problems; False, otherwise or None if the functionality was
diff --git a/src/kimchi/config.py.in b/src/kimchi/config.py.in
index cf8497a..d15a6b5 100644
--- a/src/kimchi/config.py.in
+++ b/src/kimchi/config.py.in
@@ -54,15 +54,19 @@ def get_debugreports_path():
     return os.path.join(paths.state_dir, 'debugreports')
 
 
-def find_qemu_binary():
+def find_qemu_binary(find_emulator=False):
     try:
         connect = libvirt.open('qemu:///system')
     except Exception, e:
         raise Exception("Unable to get qemu binary location: %s" % e)
     try:
         xml = connect.getCapabilities()
-        expr = "/capabilities/guest/arch[@name='%s']\
-                /domain[@type='kvm']/emulator" % platform.machine()
+        if find_emulator:
+            expr = "/capabilities/guest/arch[@name='%s']\
+                    /emulator" % platform.machine()
+        else:
+            expr = "/capabilities/guest/arch[@name='%s']\
+                    /domain[@type='kvm']/emulator" % platform.machine()
         res = xpath_get_text(xml, expr)
         location = res[0]
     except Exception, e:
diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py
index faf1049..7b567cb 100644
--- a/src/kimchi/mockmodel.py
+++ b/src/kimchi/mockmodel.py
@@ -65,6 +65,7 @@ class MockModel(object):
     def capabilities_lookup(self, *ident):
         return {'libvirt_stream_protocols':
                 ['http', 'https', 'ftp', 'ftps', 'tftp'],
+                'qemu_spice': True,
                 'qemu_stream': True,
                 'screenshot': True,
                 'system_report_tool': True,
diff --git a/src/kimchi/model/config.py b/src/kimchi/model/config.py
index a6a25e4..7f553ea 100644
--- a/src/kimchi/model/config.py
+++ b/src/kimchi/model/config.py
@@ -23,6 +23,7 @@ import cherrypy
 
 from kimchi.basemodel import Singleton
 from kimchi.config import config as kconfig
+from kimchi.config import find_qemu_binary
 from kimchi.distroloader import DistroLoader
 from kimchi.exception import NotFoundError
 from kimchi.featuretests import FeatureTests
@@ -30,7 +31,7 @@ from kimchi.model.debugreports import DebugReportsModel
 from kimchi.repositories import Repositories
 from kimchi.screenshot import VMScreenshot
 from kimchi.swupdate import SoftwareUpdate
-from kimchi.utils import check_url_path, kimchi_log
+from kimchi.utils import check_url_path, kimchi_log, run_command
 
 
 class ConfigModel(object):
@@ -72,6 +73,17 @@ class CapabilitiesModel(object):
         kimchi_log.info("*** Feature tests completed ***")
     _set_capabilities.priority = 90
 
+    def _qemu_support_spice(self):
+        qemu_path = find_qemu_binary(find_emulator=True)
+        out, err, rc = run_command(['ldd', qemu_path])
+        if rc != 0:
+            kimchi_log.error('Failed to find qemu binary dependencies: %s', err)
+            return False
+        for line in out.split('\n'):
+            if line.lstrip().startswith('libspice-server.so'):
+                return True
+        return False
+
     def lookup(self, *ident):
         report_tool = DebugReportsModel.get_system_report_tool()
         try:
@@ -89,6 +101,7 @@ class CapabilitiesModel(object):
             repo_mngt_tool = repo._pkg_mnger.TYPE
 
         return {'libvirt_stream_protocols': self.libvirt_stream_protocols,
+                'qemu_spice': self._qemu_support_spice(),
                 'qemu_stream': self.qemu_stream,
                 'screenshot': VMScreenshot.get_stream_test_result(),
                 'system_report_tool': bool(report_tool),
diff --git a/tests/test_rest.py b/tests/test_rest.py
index 3f2e449..ca4eeed 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -1346,6 +1346,7 @@ class RestTests(unittest.TestCase):
         conf = json.loads(resp)
         self.assertIn('libvirt_stream_protocols', conf)
         self.assertIn('qemu_stream', conf)
+        self.assertIn('qemu_spice', conf)
         self.assertIn('screenshot', conf)
         self.assertIn('system_report_tool', conf)
         self.assertIn('update_tool', conf)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 4310435..075b9d0 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -49,14 +49,16 @@ var kimchi = {
      * Get host capabilities
      * suc: callback if succeed err: callback if failed
      */
-    getCapabilities : function(suc, err) {
+    getCapabilities : function(suc, err, done) {
+        done = typeof done !== 'undefined' ? done: function(){};
         kimchi.requestJSON({
             url : "/config/capabilities",
             type : "GET",
             contentType : "application/json",
             dataType : "json",
             success: suc,
-            error: err
+            error: err,
+            complete: done
         });
     },
 
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index 58f4506..9c429c4 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -30,8 +30,17 @@ kimchi.template_edit_main = function() {
         }
         var disks = template.disks;
         $('input[name="disks"]').val(disks[0].size);
-        var options = [{label: 'VNC', value: 'vnc'}, {label: 'Spice', value: 'spice'}];
-        kimchi.select('template-edit-graphics-list', options);
+
+        var options = [{label: 'VNC', value: 'vnc'}];
+        kimchi.getCapabilities(function(result) {
+            if (result.qemu_spice == true) {
+                options.push({label: 'Spice', value: 'spice'})
+            }
+        }, function() {
+        }, function(){
+            kimchi.select('template-edit-graphics-list', options);
+        });
+
         kimchi.listStoragePools(function(result) {
             var options = [];
             if (result && result.length) {
-- 
1.8.5.3




More information about the Kimchi-devel mailing list