[et-mgmt-tools] [PATCH 07 of 11] virt-convert: improve disk handling
john.levon at sun.com
john.levon at sun.com
Thu Jul 10 13:48:37 UTC 2008
# HG changeset patch
# User john.levon at sun.com
# Date 1215697571 25200
# Node ID 8ffd21ddf5c72ddbe8a30f65f0761e2f39705d57
# Parent 91d463e8e9921844271a90f416e0e6d94fd2af40
virt-convert: improve disk handling
A whole bunch of fixes for more accurate disk handling.
Signed-off-by: John Levon <john.levon at sun.com>
diff --git a/virt-convert b/virt-convert
--- a/virt-convert
+++ b/virt-convert
@@ -25,7 +25,6 @@
import os
import logging
import errno
-import platform
from optparse import OptionParser
import virtinst.cli as cli
@@ -125,15 +124,15 @@
logging.error(msg)
try:
+ for disk in vmdef.disks.values():
+ disk.cleanup()
+
paths.reverse()
for path in paths:
if os.path.isdir(path):
os.rmdir(path)
elif os.path.isfile(path):
os.remove(path)
-
- for disk in vmdef.disks:
- disk.cleanup()
except OSError, e:
logging.error("Couldn't clean up output directory \"%s\": %s" %
(options.output_dir, e.strerror))
@@ -196,18 +195,18 @@
(options.output_format, options.output_dir))
try:
- for d in vmdef.disks:
+ for d in vmdef.disks.values():
format = options.disk_format
- # no auto-conversion on Solaris for VMDK disks
+ # VMDK disks on Solaris converted to vdisk by default
if (d.format == diskcfg.DISK_FORMAT_VMDK and
- not format and platform.system() == "SunOS"):
- continue
+ not format and vmcfg.host() == "SunOS"):
+ format = "vdisk"
if not format:
format = "raw"
- if format != "none":
+ if d.path and format != "none":
verbose(options, "Converting disk \"%s\" to type %s..." %
(d.path, format))
diff --git a/virtconv/diskcfg.py b/virtconv/diskcfg.py
--- a/virtconv/diskcfg.py
+++ b/virtconv/diskcfg.py
@@ -64,11 +64,10 @@
class disk(object):
"""Definition of an individual disk instance."""
- def __init__(self, path = None, number = 0, format = None, bus = "ide",
+ def __init__(self, path = None, format = None, bus = "ide",
type = DISK_TYPE_DISK):
self.path = path
self.format = format
- self.number = number
self.bus = bus
self.type = type
self.clean = []
@@ -140,6 +139,9 @@
failures.
"""
+ if self.type != DISK_TYPE_DISK:
+ return
+
out_format = disk_format_names[output_format]
indir = os.path.normpath(os.path.abspath(indir))
outdir = os.path.normpath(os.path.abspath(outdir))
@@ -160,11 +162,13 @@
convert_cmd = ("""/usr/bin/vdiskadm import -t %s "%s" "%s" """ %
(qemu_formats[out_format], absin, absout))
elif out_format == DISK_FORMAT_RAW:
- convert_cmd = ("""qemu-img convert "%s" -O %s "%s" """ %
- (absin, qemu_formats[out_format], absout))
+ convert_cmd = ("""qemu-img convert -O %s "%s" "%s" """ %
+ (qemu_formats[out_format], absin, absout))
else:
raise NotImplementedError("Cannot convert to disk format %s" %
output_format)
+
+ self.clean += [ absout ]
ret = os.system(convert_cmd)
if ret != 0:
diff --git a/virtconv/parsers/virtimage.py b/virtconv/parsers/virtimage.py
--- a/virtconv/parsers/virtimage.py
+++ b/virtconv/parsers/virtimage.py
@@ -37,7 +37,7 @@
<os>
<loader>pygrub</loader>
</os>
- %(pv_disks)s
+ %(disks)s
</boot>
"""
@@ -49,7 +49,7 @@
<os>
<loader dev="hd"/>
</os>
- %(hvm_disks)s
+ %(disks)s
</boot>
"""
@@ -74,6 +74,74 @@
</storage>
</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 SCSI support in rombios, and the SCSI emulation is
+ troublesome with Solaris, we forcibly switch the disks to IDE, and expect
+ the guest OS to cope (which at least Linux does admirably).
+
+ Note that we even go beyond hdd: above that work if the domU has PV
+ drivers.
+ """
+
+ 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 == vmcfg.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 == diskcfg.DISK_TYPE_ISO:
+ type = "iso"
+ storage.append(
+ """<disk file="%s" use="system" format="%s"/>\n""" %
+ (path, type))
+
+ return storage, diskout
class virtimage_parser(formats.parser):
"""
@@ -117,33 +185,15 @@
# xend wants the name to match r'^[A-Za-z0-9_\-\.\:\/\+]+$'
vmname = re.sub(r'[^A-Za-z0-9_.:/+-]+', '_', vm.name)
- pv_disks = []
- hvm_disks = []
- storage_disks = []
-
- # create disk filename lists for xml template
- for disk in vm.disks:
- number = disk.number
- path = disk.path
-
- # 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, ascii_letters[number % 26]))
- hvm_disks.append("""<drive disk="%s" target="hd%s" />\n""" %
- (path, ascii_letters[number % 26]))
- storage_disks.append(
- """<disk file="%s" use="system" format="%s"/>\n"""
- % (path, diskcfg.qemu_formats[disk.format]))
-
if vm.type == vmcfg.VM_TYPE_PV:
boot_template = pv_boot_template
else:
boot_template = hvm_boot_template
+ (storage, disks) = export_disks(vm)
+
boot_xml = boot_template % {
- "pv_disks" : "".join(pv_disks),
- "hvm_disks" : "".join(hvm_disks),
+ "disks" : "".join(disks),
"arch" : vm.arch,
}
@@ -154,7 +204,7 @@
"nr_vcpus" : vm.nr_vcpus,
# Mb to Kb
"memory" : int(vm.memory) * 1024,
- "storage" : "".join(storage_disks),
+ "storage" : "".join(storage),
}
outfile = open(output_file, "w")
diff --git a/virtconv/parsers/vmx.py b/virtconv/parsers/vmx.py
--- a/virtconv/parsers/vmx.py
+++ b/virtconv/parsers/vmx.py
@@ -23,6 +23,47 @@
import virtconv.diskcfg as diskcfg
import re
+import os
+
+def parse_disk_entry(vm, fullkey, value):
+ """
+ Parse a particular key/value for a disk. FIXME: this should be a
+ lot smarter.
+ """
+
+ # skip bus values, e.g. 'scsi0.present = "TRUE"'
+ if re.match(r"^(scsi|ide)[0-9]+[^:]", fullkey):
+ return
+
+ _, 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):
+ vm.disks[devid] = diskcfg.disk(bus = bus,
+ type = diskcfg.DISK_TYPE_DISK)
+
+ if key == "deviceType":
+ if lvalue == "atapi-cdrom" or lvalue == "cdrom-raw":
+ vm.disks[devid].type = diskcfg.DISK_TYPE_CDROM
+ elif lvalue == "cdrom-image":
+ vm.disks[devid].type = diskcfg.DISK_TYPE_ISO
+
+ if key == "fileName":
+ vm.disks[devid].path = value
+ vm.disks[devid].format = diskcfg.DISK_FORMAT_RAW
+ if lvalue.endswith(".vmdk"):
+ vm.disks[devid].format = diskcfg.DISK_FORMAT_VMDK
class vmx_parser(formats.parser):
"""
@@ -74,22 +115,29 @@
lines.append(line)
config = {}
- disks = []
# split out all remaining entries of key = value form
for (line_nr, line) in enumerate(lines):
try:
before_eq, after_eq = line.split("=", 1)
- key = before_eq.replace(" ","")
- value = after_eq.replace('"',"")
- value = value.strip()
+ key = before_eq.strip()
+ value = after_eq.strip().strip('"')
config[key] = value
- # FIXME: this should probably be a lot smarter.
- if value.endswith(".vmdk"):
- disks += [ value ]
+
+ if key.startswith("scsi") or key.startswith("ide"):
+ parse_disk_entry(vm, key, value)
except:
raise Exception("Syntax error at line %d: %s" %
(line_nr + 1, line.strip()))
+
+ for devid, disk in vm.disks.iteritems():
+ if disk.type == diskcfg.DISK_TYPE_DISK:
+ continue
+
+ # vmx files often have dross left in path for CD entries
+ if (disk.path == "auto detect" or
+ not os.path.exists(disk.path)):
+ vm.disks[devid].path = None
if not config.get("displayName"):
raise ValueError("No displayName defined in \"%s\"" % input_file)
@@ -98,10 +146,7 @@
vm.memory = config.get("memsize")
vm.description = config.get("annotation")
vm.nr_vcpus = config.get("numvcpus")
-
- for (number, path) in enumerate(disks):
- vm.disks += [ diskcfg.disk(path, number, diskcfg.DISK_FORMAT_VMDK) ]
-
+
vm.validate()
return vm
diff --git a/virtconv/vmcfg.py b/virtconv/vmcfg.py
--- a/virtconv/vmcfg.py
+++ b/virtconv/vmcfg.py
@@ -17,6 +17,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
+
+import platform
+from virtconv import diskcfg
+from virtinst import CapabilitiesParser
VM_TYPE_UNKNOWN = 0
VM_TYPE_PV = 1
@@ -47,7 +51,7 @@
self.description = None
self.memory = None
self.nr_vcpus = None
- self.disks = [ ]
+ self.disks = {}
self.type = VM_TYPE_HVM
self.arch = "i686"
@@ -67,3 +71,25 @@
raise ValueError("VM type is not set")
if not self.arch:
raise ValueError("VM arch is not set")
+
+ for (bus, inst), disk in sorted(self.disks.iteritems()):
+ if disk.type == diskcfg.DISK_TYPE_DISK and not disk.path:
+ raise ValueError("Disk %s:%s storage does not exist"
+ % (bus, inst))
+
+def host(conn=None):
+ """
+ Return the host, as seen in platform.system(), but possibly from a
+ hypervisor connection. Note: use default_arch() in almost all
+ cases, unless you need to detect the OS. In particular, this value
+ gives no indication of 32 vs 64 bitness.
+ """
+ if conn:
+ cap = CapabilitiesParser.parse(conn.getCapabilities())
+ if cap.host.arch == "i86pc":
+ return "SunOS"
+ else:
+ # or Linux-alike. Hmm.
+ return "Linux"
+
+ return platform.system()
More information about the et-mgmt-tools
mailing list