[virt-tools-list] [PATCH] wip: add VirtualSmartCardDevice

Marc-André Lureau marcandre.lureau at gmail.com
Thu Jun 23 15:33:23 UTC 2011


From: Marc-André Lureau <marcandre.lureau at redhat.com>

This is not a complete patch (it doesn't support all the smartcard
options, in particular host-certificates method), but it does good
enough for spice smartcard passthrough & virt-manager integration.

Feel free to take it up from there and improving it if you feel like
it's not ready for merge.
---
 tests/clitest.py                   |   27 +++++++++++
 tests/xmlparse.py                  |   17 +++++++
 virt-image                         |    1 +
 virt-install                       |    4 ++
 virtinst/Guest.py                  |    1 +
 virtinst/VirtualDevice.py          |    4 +-
 virtinst/VirtualSmartCardDevice.py |   88 ++++++++++++++++++++++++++++++++++++
 virtinst/__init__.py               |    4 +-
 virtinst/cli.py                    |   49 ++++++++++++++++++++
 9 files changed, 193 insertions(+), 2 deletions(-)
 create mode 100644 virtinst/VirtualSmartCardDevice.py

diff --git a/tests/clitest.py b/tests/clitest.py
index 31cd061..10a3f70 100644
--- a/tests/clitest.py
+++ b/tests/clitest.py
@@ -349,6 +349,33 @@ args_dict = {
 
      }, # category "graphics"
 
+     "smartcard": {
+      "args": "--noautoconsole --nodisks --pxe",
+
+      "valid": [
+        # --smartcard host
+        "--graphics host",
+        # --smartcard none,
+        "--graphics none",
+        # --smartcard mode with type
+        "--graphics passthrough,type=spicevmc",
+        # --smartcard mode with type
+        "--graphics passthrough,type=tcp",
+      ],
+
+      "invalid": [
+        # Missing argument
+        "--smartcard",
+        # Invalid argument
+        "--smartcard foo",
+        # Invalid type
+        "--smartcard passthrough,type=foo",
+        # --smartcard bogus
+        "--smarcard host,foobar=baz",
+      ],
+
+     }, # category "smartcard"
+
     "char" : {
      "args": "--hvm --nographics --noautoconsole --nodisks --pxe",
 
diff --git a/tests/xmlparse.py b/tests/xmlparse.py
index 3f19c98..636e043 100644
--- a/tests/xmlparse.py
+++ b/tests/xmlparse.py
@@ -639,6 +639,23 @@ class XMLParseTest(unittest.TestCase):
 
         self._alter_compare(guest.get_config_xml(), outfile)
 
+    def testAlterSmartCard(self):
+        infile  = "tests/xmlparse-xml/change-smartcard-in.xml"
+        outfile = "tests/xmlparse-xml/change-smartcard-out.xml"
+        guest = virtinst.Guest(connection=conn,
+                               parsexml=file(infile).read())
+
+        dev1 = guest.get_devices("smartcard")[0]
+        dev2 = guest.get_devices("smartcard")[1]
+
+        check = self._make_checker(dev1)
+        check("type", None, "tcp")
+
+        check = self._make_checker(dev2)
+        check("mode", "passthrough", "host")
+        check("type", "spicevmc", None)
+
+        self._alter_compare(guest.get_config_xml(), outfile)
 
     def testConsoleCompat(self):
         infile  = "tests/xmlparse-xml/console-compat-in.xml"
diff --git a/virt-image b/virt-image
index ea55181..19fa5d4 100755
--- a/virt-image
+++ b/virt-image
@@ -172,6 +172,7 @@ def main():
 
     get_graphics(image.domain, guest, options)
     cli.get_video(guest)
+    cli.get_smartcard(guest, options.smartcard)
 
     cli.set_os_variant(guest, options.distro_type, options.distro_variant)
 
diff --git a/virt-install b/virt-install
index e2309b9..62c79c1 100755
--- a/virt-install
+++ b/virt-install
@@ -488,6 +488,7 @@ def build_guest_instance(conn, options):
     get_chardevs(VirtualDevice.VIRTUAL_DEV_CHANNEL, options.channels, guest)
     get_chardevs(VirtualDevice.VIRTUAL_DEV_CONSOLE, options.consoles, guest)
     cli.get_hostdevs(options.hostdevs, guest)
+    cli.get_smartcard(guest, options.smartcard)
 
 
     # Install options
@@ -867,6 +868,9 @@ def parse_args():
                     help=_("Don't create network interfaces for the guest."))
     parser.add_option_group(netg)
 
+    scg = cli.smartcard_option_group(parser)
+    parser.add_option_group(scg)
+
     vncg = cli.graphics_option_group(parser)
     vncg.add_option("", "--noautoconsole", action="store_false",
                     dest="autoconsole", default=True,
diff --git a/virtinst/Guest.py b/virtinst/Guest.py
index 60b8175..430dd8d 100644
--- a/virtinst/Guest.py
+++ b/virtinst/Guest.py
@@ -784,6 +784,7 @@ class Guest(XMLBuilderDomain.XMLBuilderDomain):
             "watchdog"  : virtinst.VirtualWatchdog,
             "controller": virtinst.VirtualController,
             "filesystem": virtinst.VirtualFilesystem,
+            "smartcard" : virtinst.VirtualSmartCardDevice,
         }
 
         # Hand off all child element parsing to relevant classes
diff --git a/virtinst/VirtualDevice.py b/virtinst/VirtualDevice.py
index 87af418..158037c 100644
--- a/virtinst/VirtualDevice.py
+++ b/virtinst/VirtualDevice.py
@@ -41,6 +41,7 @@ class VirtualDevice(XMLBuilderDomain):
     VIRTUAL_DEV_CONTROLLER      = "controller"
     VIRTUAL_DEV_WATCHDOG        = "watchdog"
     VIRTUAL_DEV_FILESYSTEM      = "filesystem"
+    VIRTUAL_DEV_SMARTCARD       = "smartcard"
 
     # Ordering in this list is important: it will be the order the
     # Guest class outputs XML. So changing this may upset the test suite
@@ -57,7 +58,8 @@ class VirtualDevice(XMLBuilderDomain):
                             VIRTUAL_DEV_AUDIO,
                             VIRTUAL_DEV_VIDEO,
                             VIRTUAL_DEV_HOSTDEV,
-                            VIRTUAL_DEV_WATCHDOG]
+                            VIRTUAL_DEV_WATCHDOG,
+                            VIRTUAL_DEV_SMARTCARD]
 
     # General device type (disk, interface, etc.)
     _virtual_device_type = None
diff --git a/virtinst/VirtualSmartCardDevice.py b/virtinst/VirtualSmartCardDevice.py
new file mode 100644
index 0000000..f07bbf3
--- /dev/null
+++ b/virtinst/VirtualSmartCardDevice.py
@@ -0,0 +1,88 @@
+# coding=utf-8
+#
+# Copyright 2011  Red Hat, Inc.
+# Cole Robinson <crobinso at redhat.com>
+# Marc-André Lureau <marcandre.lureau at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free  Software Foundation; either version 2 of the License, or
+# (at your option)  any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+
+import VirtualDevice
+from XMLBuilderDomain import _xml_property
+from virtinst import _virtinst as _
+
+class VirtualSmartCardDevice(VirtualDevice.VirtualDevice):
+
+    _virtual_device_type = VirtualDevice.VirtualDevice.VIRTUAL_DEV_SMARTCARD
+
+    # Default models list
+    MODE_DEFAULT = "passthrough"
+    _modes = [ "passthrough", "host-certificates", "host" ]
+
+    TYPE_DEFAULT = "tcp"
+    _types = [ "tcp", "spicevmc", None ]
+
+    def __init__(self, conn, mode=MODE_DEFAULT,
+                 parsexml=None, parsexmlnode=None, caps=None):
+        VirtualDevice.VirtualDevice.__init__(self, conn,
+                                             parsexml, parsexmlnode, caps)
+
+        self._mode = None
+        self._type = None
+
+        if self._is_parse():
+            return
+
+        self.mode = mode
+
+    def get_modes(self):
+        return self._modes[:]
+    modes = property(get_modes)
+
+    def get_mode(self):
+        return self._mode
+    def set_mode(self, val):
+        if val not in self.modes:
+            raise ValueError(_("Unknown smartcard mode '%s'") % val)
+        self._mode = val
+    mode = _xml_property(get_mode, set_mode,
+                         xpath="./@mode")
+
+    def get_types(self):
+        return self._types[:]
+    types = property(get_types)
+
+    def get_type(self):
+        if self._type is None and self.mode == "passthrough":
+            return "spicevmc"
+        return self._type
+    def set_type(self, val):
+        if val not in self.types:
+            raise ValueError(_("Unknown smartcard type '%s'") % val)
+        self._type = val
+    type = _xml_property(get_type, set_type,
+                         xpath="./@type")
+
+    def _get_xml_config(self):
+        mode = self.mode
+
+        xml = "    <smartcard mode='%s'" % mode
+        if self.type:
+            xml += " type='%s'" % self.type
+        xml += ">\n"
+        xml += "      <protocol type='raw'/>\n"
+        xml += "    </smartcard>"
+
+        return xml
diff --git a/virtinst/__init__.py b/virtinst/__init__.py
index 287e90e..6460e95 100644
--- a/virtinst/__init__.py
+++ b/virtinst/__init__.py
@@ -44,6 +44,7 @@ from VirtualVideoDevice import VirtualVideoDevice
 from VirtualController import VirtualController
 from VirtualWatchdog import VirtualWatchdog
 from VirtualFilesystem import VirtualFilesystem
+from VirtualSmartCardDevice import VirtualSmartCardDevice
 from FullVirtGuest import FullVirtGuest
 from ParaVirtGuest import ParaVirtGuest
 from DistroInstaller import DistroInstaller
@@ -73,4 +74,5 @@ __all__ = ["Guest", "XenGuest", "VirtualNetworkInterface",
            "CPU",
            "VirtualHostDevice", "VirtualHostDeviceUSB", "VirtualVideoDevice",
            "VirtualHostDevicePCI", "VirtualCharDevice", "VirtualInputDevice",
-           "VirtualController", "VirtualWatchdog"]
+           "VirtualController", "VirtualWatchdog",
+           "VirtualFilesystem", "VirtualSmartCardDevice"]
diff --git a/virtinst/cli.py b/virtinst/cli.py
index 4f78738..19602cf 100644
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -969,6 +969,16 @@ def get_hostdevs(hostdevs, guest):
                                                           name=devname)
         guest.hostdevs.append(dev)
 
+def get_smartcard(guest, sc_opts):
+    for sc in sc_opts:
+        try:
+            dev = parse_smartcard(guest, sc)
+        except Exception, e:
+            fail(_("Error in smartcard device parameters: %s") % str(e))
+
+        if dev:
+            guest.add_device(dev)
+
 #############################
 # Common CLI option/group   #
 #############################
@@ -1036,6 +1046,17 @@ def network_option_group(parser):
 
     return netg
 
+def smartcard_option_group(parser):
+    """
+    Register smartcard options for virt-install and virt-image
+    """
+    scg = optparse.OptionGroup(parser, _("SmartCard Configuration"))
+
+    scg.add_option("-S", "--smartcard", dest="smartcard", action="append",
+      help=_("Add a smartcard device to the domain. Ex:\n"
+             "--smartcard mode=passthrough\n"))
+    return scg
+
 #############################################
 # CLI complex parsing helpers               #
 # (for options like --disk, --network, etc. #
@@ -1480,6 +1501,34 @@ def parse_graphics(guest, optstring):
 
     return dev
 
+#######################
+# --smartcard parsing #
+#######################
+def parse_smartcard(guest, optstring):
+    if optstring is None:
+        return None
+
+    # Peel the mode off the front
+    opts = parse_optstr(optstring, remove_first="mode")
+    if opts.get("mode") == "none":
+        return None
+    dev = virtinst.VirtualSmartCardDevice(guest.conn, opts.get("mode"))
+
+    def set_param(paramname, dictname, val=None):
+        val = get_opt_param(opts, dictname, val)
+        if val == None:
+            return
+
+        setattr(dev, paramname, val)
+
+    set_param("mode", "mode")
+    set_param("type", "type")
+
+    if opts:
+        raise ValueError(_("Unknown options %s") % opts.keys())
+
+    return dev
+
 ######################
 # --watchdog parsing #
 ######################
-- 
1.7.5.2




More information about the virt-tools-list mailing list