[et-mgmt-tools] [PATCH 07 of 11] Implement network device handling
john.levon at sun.com
john.levon at sun.com
Mon Jul 7 22:51:37 UTC 2008
# HG changeset patch
# User john.levon at sun.com
# Date 1215470437 25200
# Node ID 20daa7230dc53978e5f67fabf7950d961ed3bdd8
# Parent a8f5d5be978f0237f41c35275936863c2787a73b
Implement network device handling
Also clean up disk processing somewhat.
Signed-off-by: John Levon <john.levon at sun.com>
diff --git a/virt-convert b/virt-convert
--- a/virt-convert
+++ b/virt-convert
@@ -24,8 +24,8 @@
#
# Convert between VM definition formats. TODO:
#
-# support networking
# port virtinstance.py to Solaris
+# networking support is nowhere near complete
# better disk checking
# support CD-ROM
# add option for host selection
@@ -212,9 +212,9 @@ def main():
try:
for d in vmdef.disks:
verbose(options, "Converting disk \"%s\" to type %s..." %
- (d.path, vmconfig.qemu_formats[vmconfig.DISK_TYPE_RAW]))
+ (d.path, vmconfig.qemu_formats[vmconfig.DISK_FORMAT_RAW]))
d.convert(options.input_dir, options.output_dir,
- vmconfig.DISK_TYPE_RAW)
+ vmconfig.DISK_FORMAT_RAW)
except OSError, e:
cleanup("Couldn't convert disks: %s" % e.strerror, options, created_dir)
except RuntimeError, e:
diff --git a/virtconv/parsers/virtimage.py b/virtconv/parsers/virtimage.py
--- a/virtconv/parsers/virtimage.py
+++ b/virtconv/parsers/virtimage.py
@@ -26,7 +26,7 @@ pv_boot_template = """
<guest>
<arch>%(arch)s</arch>
<features>
- <pae/>
+ <pae />
</features>
</guest>
<os>
@@ -42,7 +42,7 @@ hvm_boot_template = """
<arch>%(arch)s</arch>
</guest>
<os>
- <loader dev="hd"/>
+ <loader dev="hd" />
</os>
%(hvm_disks)s
</boot>
@@ -60,8 +60,8 @@ image_template = """
<devices>
<vcpu>%(nr_vcpus)s</vcpu>
<memory>%(memory)s</memory>
- <interface/>
- <graphics/>
+ %(interface)s
+ <graphics />
</devices>
</domain>
<storage>
@@ -114,18 +114,26 @@ class virtimage_parser(vmconfig.parser):
storage_disks = []
# create disk filename lists for xml template
- for disk in vm.disks:
- number = disk.number
+ 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, ascii_letters[number % 26]))
+ (path, drive_nr))
hvm_disks.append("""<drive disk="%s" target="hd%s" />\n""" %
- (path, ascii_letters[number % 26]))
+ (path, drive_nr))
storage_disks.append(
"""<disk file="%s" use="system" format="raw"/>\n""" % path)
+
+ # Hmm. Any interface is a good interface?
+ interface = None
+ if len(vm.netdevs):
+ interface = "<interface />"
if vm.type == vmconfig.VM_TYPE_PV:
boot_template = pv_boot_template
@@ -145,6 +153,7 @@ class virtimage_parser(vmconfig.parser):
"nr_vcpus" : vm.nr_vcpus,
# Mb to Kb
"memory" : int(vm.memory) * 1024,
+ "interface" : interface,
"storage" : "".join(storage_disks),
}
diff --git a/virtconv/parsers/virtinstance.py b/virtconv/parsers/virtinstance.py
--- a/virtconv/parsers/virtinstance.py
+++ b/virtconv/parsers/virtinstance.py
@@ -54,6 +54,14 @@ disk_template = """
<source dev='%(path)s' />
<target dev='%(prefix)s%(dev)s' />
</disk>
+"""
+
+netdev_template = """
+<interface type='%(type)s'>
+ %(source)s
+ %(mac)s
+ %(model)s
+</interface>
"""
instance_template = """
@@ -77,6 +85,7 @@ instance_template = """
<devices>
%(emulator)s
%(disks)s
+ %(netdevs)s
<input type='mouse' bus='ps2' />
<input type='tablet' bus='usb' />
<graphics type='vnc' port='-1' />
@@ -95,6 +104,11 @@ class virtinstance_parser(vmconfig.parse
example, the pygrub path. For now, we'll assume it's for the current
platform. In the future we might want to consider adding a
--host-type option.
+
+ Known limitations:
+
+ - Only handles bridge, ethernet, and network type netdevs
+ - doesn't handle netdev script or IP address
"""
name = "virt-instance"
@@ -142,16 +156,54 @@ class virtinstance_parser(vmconfig.parse
disk_prefix = "hd"
disks = []
-
- for disk in vm.disks:
- drive_nr = ascii_letters[disk.number % 26]
+ netdevs = []
+
+ for devid, disk in sorted(vm.disks.iteritems()):
+ if disk.type != vmconfig.DISK_TYPE_DISK:
+ continue
# 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,
"prefix" : disk_prefix,
"dev" : drive_nr
+ })
+
+ for number, netdev in sorted(vm.netdevs.iteritems()):
+ mac = ""
+ if netdev.mac != "auto":
+ mac = "<mac address='%s' />" % netdev.mac
+
+ nettype = {
+ vmconfig.NETDEV_TYPE_DEV : "ethernet",
+ vmconfig.NETDEV_TYPE_BRIDGE : "bridge",
+ vmconfig.NETDEV_TYPE_UNKNOWN : "bridge",
+ vmconfig.NETDEV_TYPE_NETWORK : "network",
+ }.get(netdev.type)
+
+ source = ""
+ if netdev.source:
+ srcattr = nettype
+ if netdev.type == vmconfig.NETDEV_TYPE_DEV:
+ srcattr = "dev"
+ source = "<source %s='%s' />" % (srcattr, netdev.source)
+
+ # FIXME: should warn here
+ if not nettype:
+ continue
+
+ model = ""
+ if netdev.driver:
+ model = "<model type='%s' />" % netdev.driver
+
+ netdevs.append(netdev_template % {
+ "type" : nettype,
+ "source" : source,
+ "mac" : mac,
+ "model": model,
})
out = instance_template % {
@@ -164,6 +216,7 @@ class virtinstance_parser(vmconfig.parse
"memory" : int(vm.memory) * 1024,
"nr_vcpus" : vm.nr_vcpus,
"emulator" : emulators[vm.type],
+ "netdevs" : "".join(netdevs),
"disks" : "".join(disks),
"console" : consoles[vm.type],
}
diff --git a/virtconv/parsers/vmx.py b/virtconv/parsers/vmx.py
--- a/virtconv/parsers/vmx.py
+++ b/virtconv/parsers/vmx.py
@@ -20,7 +20,68 @@
import virtconv.vmconfig as vmconfig
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
+
+ # FIXME: we don't check bus number, we should
+ _, bus, _, inst, key = re.split(r"^(scsi|ide)([0-9]+):([0-9]+)\.",
+ fullkey)
+
+ lvalue = value.lower()
+
+ if key == "present" and lvalue == "false":
+ return
+
+ devid = (bus, inst)
+ if not vm.disks.get(devid):
+ vm.disks[devid] = vmconfig.disk(bus = bus,
+ type = vmconfig.DISK_TYPE_DISK)
+
+ if key == "deviceType":
+ if lvalue == "atapi-cdrom" or lvalue == "cdrom-raw":
+ vm.disks[devid].type = vmconfig.DISK_TYPE_CDROM
+ elif lvalue == "cdrom-image":
+ vm.disks[devid].type = vmconfig.DISK_TYPE_ISO
+
+ if key == "fileName":
+ vm.disks[devid].path = value
+ vm.disks[devid].format = vmconfig.DISK_FORMAT_RAW
+ if lvalue.endswith(".vmdk"):
+ vm.disks[devid].format = vmconfig.DISK_FORMAT_VMDK
+
+def parse_netdev_entry(vm, fullkey, value):
+ """
+ Parse a particular key/value for a network. Throws ValueError.
+ """
+
+ _, _, inst, key = re.split("^(ethernet)([0-9]+).", fullkey)
+
+ lvalue = value.lower()
+
+ if key == "present" and lvalue == "false":
+ return
+
+ if not vm.netdevs.get(inst):
+ vm.netdevs[inst] = vmconfig.netdev(type = vmconfig.NETDEV_TYPE_UNKNOWN)
+
+ # "vlance", "vmxnet", "e1000"
+ if key == "virtualDev":
+ vm.netdevs[inst].driver = lvalue
+ if key == "addressType" and lvalue == "generated":
+ vm.netdevs[inst].mac = "auto"
+ # we ignore .generatedAddress for auto mode
+ if key == "address":
+ vm.netdevs[inst].mac = lvalue
+
class vmx_parser(vmconfig.parser):
"""
Support for VMWare .vmx files. Note that documentation is
@@ -71,22 +132,31 @@ class vmx_parser(vmconfig.parser):
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)
+ if key.startswith("ethernet"):
+ parse_netdev_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 == vmconfig.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)
@@ -95,10 +165,7 @@ class vmx_parser(vmconfig.parser):
vm.memory = config.get("memsize")
vm.description = config.get("annotation")
vm.nr_vcpus = config.get("numvcpus")
-
- for (number, path) in enumerate(disks):
- vm.disks += [ vmconfig.disk(path, number, vmconfig.DISK_TYPE_VMDK) ]
-
+
vm.validate()
return vm
diff --git a/virtconv/vmconfig.py b/virtconv/vmconfig.py
--- a/virtconv/vmconfig.py
+++ b/virtconv/vmconfig.py
@@ -25,40 +25,54 @@ VM_TYPE_PV = 0
VM_TYPE_PV = 0
VM_TYPE_HVM = 1
-DISK_TYPE_RAW = 0
-DISK_TYPE_VMDK = 1
+NETDEV_TYPE_UNKNOWN = 0
+NETDEV_TYPE_DEV = 1
+NETDEV_TYPE_BRIDGE = 2
+NETDEV_TYPE_NETWORK = 3
+
+DISK_FORMAT_RAW = 0
+DISK_FORMAT_VMDK = 1
+
+DISK_TYPE_DISK = 0
+DISK_TYPE_CDROM = 1
+DISK_TYPE_ISO = 2
disk_suffixes = {
- DISK_TYPE_RAW: ".img",
- DISK_TYPE_VMDK: ".vmdk",
+ DISK_FORMAT_RAW: ".img",
+ DISK_FORMAT_VMDK: ".vmdk",
}
qemu_formats = {
- DISK_TYPE_RAW: "raw",
- DISK_TYPE_VMDK: "vmdk",
+ DISK_FORMAT_RAW: "raw",
+ DISK_FORMAT_VMDK: "vmdk",
}
class disk(object):
"""Definition of an individual disk instance."""
- def __init__(self, path = None, number = None, type = None):
+ def __init__(self, path = None, format = None, bus = "ide",
+ type = DISK_TYPE_DISK):
self.path = path
- self.number = number
+ self.format = format
+ self.bus = bus
self.type = type
- def convert(self, input_dir, output_dir, output_type):
+ def convert(self, input_dir, output_dir, output_format):
"""
Convert a disk into the requested format if possible, in the
- given output directory. Raises NotImplementedError or other
+ given output directory. Raises RuntimeError or other
failures.
"""
- if self.type == output_type:
+ if self.format == output_format:
return
- if output_type != DISK_TYPE_RAW:
- raise NotImplementedError("Cannot convert to disk type %d" %
- output_type)
+ if self.type != DISK_TYPE_DISK:
+ return
+
+ if output_format != DISK_FORMAT_RAW:
+ raise NotImplementedError("Cannot convert to disk format %d" %
+ output_format)
infile = self.path
@@ -70,11 +84,11 @@ class disk(object):
if os.path.isabs(outfile):
outfile = os.path.basename(outfile)
- outfile = outfile.replace(disk_suffixes[self.type],
- disk_suffixes[output_type]).strip()
+ outfile = outfile.replace(disk_suffixes[self.format],
+ disk_suffixes[output_format]).strip()
convert_cmd = ("qemu-img convert \"%s\" -O %s \"%s\"" %
- (infile, qemu_formats[output_type],
+ (infile, qemu_formats[output_format],
os.path.join(output_dir, outfile)))
ret = os.system(convert_cmd)
@@ -83,8 +97,22 @@ class disk(object):
# Note: this is the *relative* path still
self.path = outfile
- self.type = output_type
-
+ self.format = output_format
+
+class netdev(object):
+ """Definition of an individual network device."""
+
+ def __init__(self, mac = "auto", type = NETDEV_TYPE_UNKNOWN,
+ source = None, driver = None):
+ """@mac: either a MAC address, or "auto"
+ @type: NETDEV_TYPE_*
+ @source: bridge or net device, or network name
+ @driver: device emulated for VM (e.g. vmxnet)
+ """
+ self.mac = mac
+ self.type = type
+ self.source = source
+ self.driver = driver
class vm(object):
"""
@@ -111,7 +139,8 @@ class vm(object):
self.description = None
self.memory = None
self.nr_vcpus = None
- self.disks = [ ]
+ self.disks = {}
+ self.netdevs = {}
self.type = VM_TYPE_HVM
self.arch = "i686" # FIXME?
@@ -132,7 +161,11 @@ class vm(object):
if not self.arch:
raise ValueError("VM arch is not set")
-
+ for (bus, inst), disk in self.disks.iteritems():
+ if not disk.path and disk.type == DISK_TYPE_DISK:
+ raise ValueError("Disk device %s:%d has no path." %
+ (bus, inst))
+
class parser(object):
"""
Base class for particular config file format definitions of
More information about the et-mgmt-tools
mailing list