[et-mgmt-tools] [PATCH 10 of 11] Support CD-ROMs

john.levon at sun.com john.levon at sun.com
Mon Jul 7 22:51:40 UTC 2008


# HG changeset patch
# User john.levon at sun.com
# Date 1215470463 25200
# Node ID bed866186030cc9549f6a020e0abda871fc008c2
# Parent  26beabc283b11e40ed01584be33678fd0840fed2
Support CD-ROMs

Add support for CD-ROMs and also extend disk handling with some hokey checks
for block versus file.

Signed-off-by: John Levon <john.levon at sun.com>

diff --git a/virtconv/parsers/virtimage.py b/virtconv/parsers/virtimage.py
--- a/virtconv/parsers/virtimage.py
+++ b/virtconv/parsers/virtimage.py
@@ -35,7 +35,7 @@ pv_boot_template = """
    <os>
     <loader>pygrub</loader>
    </os>
-   %(pv_disks)s
+   %(disks)s
   </boot>
 """
 
@@ -47,7 +47,7 @@ hvm_boot_template = """
    <os>
     <loader dev="hd" />
    </os>
-   %(hvm_disks)s
+   %(disks)s
   </boot>
 """
 
@@ -73,6 +73,71 @@ image_template = """
 </image>
 """
 
+def export_disks(vm):
+    """
+    Export code for the disks.  Slightly tricky for two reasons.
+    
+    We can't handle duplicate disks: some vmx files define SCSI/IDE devices
+    that point to the same storage, and Xen isn't happy about that. We
+    just ignore any entries that have duplicate paths.
+
+    Since there is no meaningful SCSI support in rombios/qemu, we
+    forcibly switch the disks to IDE, and expect the guest OS to cope
+    (which at least Linux does admirably).
+    """
+
+    paths = []
+
+    disks = {}
+
+    for (bus, instance), disk in sorted(vm.disks.iteritems()):
+
+        if disk.path and disk.path in paths:
+            continue
+
+        if bus == "scsi":
+            instance = 0
+            while disks.get(("ide", instance)):
+                instance += 1
+
+        disks[("ide", instance)] = disk
+
+        if disk.path:
+            paths += [ disk.path ]
+
+    diskout = []
+    storage = []
+
+    for (bus, instance), disk in sorted(disks.iteritems()):
+
+        # virt-image XML cannot handle an empty CD device
+        if not disk.path:
+            continue
+
+        path = disk.path
+        drive_nr = ascii_letters[int(instance) % 26]
+
+        disk_prefix = "xvd"
+        if vm.type == vmconfig.VM_TYPE_HVM:
+            if bus == "ide":
+                disk_prefix = "hd"
+            else:
+                disk_prefix = "sd"
+
+        # FIXME: needs updating for later Xen enhancements; need to
+        # implement capabilities checking for max disks etc.
+        diskout.append("""<drive disk="%s" target="%s%s" />\n""" %
+            (path, disk_prefix, drive_nr))
+
+        type = "raw"
+        if disk.type == vmconfig.DISK_TYPE_ISO:
+            type = "iso"
+        storage.append(
+            """<disk file="%s" use="system" format="%s"/>\n""" %
+                (path, type))
+
+    return storage, diskout
+
 def export_os_params(vm):
     """
     Export OS-specific parameters.
@@ -143,26 +208,7 @@ class virtimage_parser(vmconfig.parser):
         if not vm.memory:
             raise ValueError("VM must have a memory setting")
 
-        pv_disks = []
-        hvm_disks = []
-        storage_disks = []
-
-        # create disk filename lists for xml template
-        for devid, disk in sorted(vm.disks.iteritems()):
-            if disk.type != vmconfig.DISK_TYPE_DISK:
-                continue
-
-            path = disk.path
-            drive_nr = ascii_letters[int(devid[1]) % 26]
-
-            # FIXME: needs updating for later Xen enhancements; need to
-            # implement capabilities checking for max disks etc.
-            pv_disks.append("""<drive disk="%s" target="xvd%s" />\n""" %
-                (path, drive_nr))
-            hvm_disks.append("""<drive disk="%s" target="hd%s" />\n""" %
-                (path, drive_nr))
-            storage_disks.append(
-                """<disk file="%s" use="system" format="raw"/>\n""" % path)
+        (storage, disks) = export_disks(vm)
 
         # Hmm.  Any interface is a good interface?
         interface = None
@@ -177,8 +223,7 @@ class virtimage_parser(vmconfig.parser):
             boot_template = hvm_boot_template
 
         boot_xml = boot_template % {
-            "pv_disks" : "".join(pv_disks),
-            "hvm_disks" : "".join(hvm_disks),
+            "disks" : "".join(disks),
             "arch" : vm.arch,
             "acpi" : acpi,
             "apic" : apic,
@@ -192,7 +237,7 @@ class virtimage_parser(vmconfig.parser):
             # Mb to Kb
             "memory" : int(vm.memory) * 1024,
             "interface" : interface,
-            "storage" : "".join(storage_disks),
+            "storage" : "".join(storage),
         }
 
         outfile = open(output_file, "w")
diff --git a/virtconv/parsers/virtinstance.py b/virtconv/parsers/virtinstance.py
--- a/virtconv/parsers/virtinstance.py
+++ b/virtconv/parsers/virtinstance.py
@@ -22,6 +22,8 @@ import virtconv.vmconfig as vmconfig
 import virtconv.vmconfig as vmconfig
 import virtinst.FullVirtGuest as fv
 
+import os
+import stat
 import re
 
 bootloaders = {
@@ -50,10 +52,10 @@ consoles = {
 }
 
 disk_template = """
-<disk type='block' device='disk'>
- <driver name='phy' />
- <source dev='%(path)s' />
+<disk %(typeattr)s device='%(device)s'>
+ %(hostdev)s
  <target dev='%(prefix)s%(dev)s' />
+ %(readonly)s
 </disk>
 """
 
@@ -104,7 +106,7 @@ def export_netdevs(vm):
 
     netdevs = []
 
-    for number, netdev in sorted(vm.netdevs.iteritems()):
+    for netdev in vm.netdevs.values():
         mac = ""
         if netdev.mac != "auto":
             mac = "<mac address='%s' />" % netdev.mac
@@ -142,30 +144,97 @@ def export_netdevs(vm):
 
 def export_disks(vm):
     """
-    Export code for the disks.
-    """
-
-    disk_prefix = "xvd"
-    if (vm.type == vmconfig.VM_TYPE_HVM):
-        disk_prefix = "hd"
-
-    disks = []
-
-    for devid, disk in sorted(vm.disks.iteritems()):
-        if disk.type != vmconfig.DISK_TYPE_DISK:
+    Export code for the disks.  Slightly tricky for two reasons.
+    
+    We can't handle duplicate disks: some vmx files define SCSI/IDE devices
+    that point to the same storage, and Xen isn't happy about that. We
+    just ignore any entries that have duplicate paths.
+
+    Since there is no meaningful SCSI support in rombios/qemu, we
+    forcibly switch the disks to IDE, and expect the guest OS to cope
+    (which at least Linux does admirably).
+    """
+
+    out = []
+    paths = []
+
+    disks = {}
+
+    for (bus, instance), disk in sorted(vm.disks.iteritems()):
+
+        if disk.path and disk.path in paths:
             continue
+
+        if bus == "scsi":
+            instance = 0
+            while disks.get(("ide", instance)):
+                instance += 1
+
+        disks[("ide", instance)] = disk
+
+        if disk.path:
+            paths += [ disk.path ]
+
+    for (bus, instance), disk in sorted(disks.iteritems()):
+
+        if not disk.path:
+            typeattr = ""
+            hostdev = ""
+
+            # It's quite common for .vmx files to reference a
+            # non-existent ISO (which was cleaned up in vmx_parser).
+            # Just skip them.
+            if disk.type == vmconfig.DISK_TYPE_ISO:
+                continue
+        else:
+            # Of course, this file path might be relative, so we won't be
+            # able to stat() it.  In such a case, it's almost certainly a
+            # file anyway, so the fallback is fine.
+            typeattr = "type='file'"
+            hostdev = ("<driver name='file' />\n"
+                "<source file='%s' />\n" % disk.path)
+
+            try:
+                if stat.S_ISBLK(os.stat(disk.path)[0]):
+                    typeattr = "type='block'"
+                    hostdev = ("<driver name='phy' />\n"
+                        "<source dev='%s' />\n" % disk.path)
+            except:
+                pass
+
+        device = "disk"
+        readonly = ""
+
+        if (disk.type == vmconfig.DISK_TYPE_CDROM or
+            disk.type == vmconfig.DISK_TYPE_ISO):
+            device = "cdrom"
+            readonly = "<readonly />"
+
+        bus = "ide"
+
+        disk_prefix = "xvd"
+        if vm.type == vmconfig.VM_TYPE_HVM:
+            if bus == "ide":
+                disk_prefix = "hd"
+            else:
+                disk_prefix = "sd"
 
         # FIXME: needs updating for later Xen enhancements; need to
         # implement capabilities checking for max disks etc.
-        drive_nr = ascii_letters[int(devid[1]) % 26]
-
-        disks.append(disk_template % {
-            "path" : disk.path,
+        drive_nr = ascii_letters[int(instance) % 26]
+
+        instance += 1
+
+        out.append(disk_template % {
+            "typeattr" : typeattr,
+            "device" : device,
+            "hostdev" : hostdev,
             "prefix" : disk_prefix,
-            "dev" :  drive_nr
+            "dev" :  drive_nr,
+            "readonly" : readonly,
         })
-
-    return disks
+ 
+    return out
 
 def export_os_params(vm):
     """
diff --git a/virtconv/parsers/vmx.py b/virtconv/parsers/vmx.py
--- a/virtconv/parsers/vmx.py
+++ b/virtconv/parsers/vmx.py
@@ -32,14 +32,18 @@ def parse_disk_entry(vm, fullkey, value)
     if re.match(r"^(scsi|ide)[0-9]+[^:]", fullkey):
         return
 
-    # FIXME: we don't check bus number, we should
-    _, bus, _, inst, key = re.split(r"^(scsi|ide)([0-9]+):([0-9]+)\.",
+    _, bus, bus_nr, inst, key = re.split(r"^(scsi|ide)([0-9]+):([0-9]+)\.",
         fullkey)
 
     lvalue = value.lower()
 
     if key == "present" and lvalue == "false":
         return
+
+    # Does anyone else think it's scary that we're still doing things
+    # like this?
+    if bus == "ide":
+        inst = int(inst) + int(bus_nr) * 2
 
     devid = (bus, inst)
     if not vm.disks.get(devid):




More information about the et-mgmt-tools mailing list