# HG changeset patch # User john.levon@xxxxxxx # 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@xxxxxxx> 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): _______________________________________________ et-mgmt-tools mailing list et-mgmt-tools@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/et-mgmt-tools