Linux Archive

Linux Archive (http://www.linux-archive.org/)
-   Fedora/Linux Management Tools (http://www.linux-archive.org/fedora-linux-management-tools/)
-   -   virt-convert: Add "virt-instance" formatter (http://www.linux-archive.org/fedora-linux-management-tools/122431-virt-convert-add-virt-instance-formatter.html)

07-10-2008 01:48 PM

virt-convert: Add "virt-instance" formatter
 
# HG changeset patch
# User john.levon@sun.com
# Date 1215697572 25200
# Node ID 112cd8c4aa97e9da9d7532fee7d826d35e1003e8
# Parent 92de696f634f80d47b9413b9db5101de0edf9b7f
virt-convert: Add "virt-instance" formatter.

Allow output in libvirt.rng format

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

diff --git a/man/en/virt-convert.1 b/man/en/virt-convert.1
--- a/man/en/virt-convert.1
+++ b/man/en/virt-convert.1
@@ -174,7 +174,8 @@
Input format. Currently, f(CW*(C`vmx*(C'fR is the only supported input format.
.IP "-o format" 4
.IX Item "-o format"
-Output format. Currently, f(CW*(C`virt-image*(C'fR is the only supported output format.
+Output format. Currently, the only supported outputs are f(CW*(C`virt-image*(C'fR
+and f(CW*(C`virt-instance*(C'fR.
.IP "-D format" 4
.IX Item "-D format"
Output disk format, or f(CW*(C`none*(C'fR if no conversion should be performed. See
diff --git a/man/en/virt-convert.pod b/man/en/virt-convert.pod
--- a/man/en/virt-convert.pod
+++ b/man/en/virt-convert.pod
@@ -56,7 +56,8 @@

=item -o format

-Output format. Currently, C<virt-image> is the only supported output format.
+Output format. Currently, the only supported outputs are C<virt-image>
+and C<virt-instance>.

=item -D format

diff --git a/virt-convert b/virt-convert
--- a/virt-convert
+++ b/virt-convert
@@ -156,10 +156,10 @@
inp = formats.parser_by_name(options.input_format)
outp = formats.parser_by_name(options.output_format)

- vmdef = None
+ vmdef = vmcfg.vm(options.arch, options.paravirt)

try:
- vmdef = inp.import_file(options.input_file)
+ inp.import_file(options.input_file, vmdef)
except IOError, e:
logging.error("Couldn't import file "%s": %s" %
(options.input_file, e.strerror))
@@ -169,12 +169,6 @@
(options.input_file, e.message))
sys.exit(1)

- if options.paravirt:
- vmdef.type = vmcfg.VM_TYPE_PV
- else:
- vmdef.type = vmcfg.VM_TYPE_HVM
-
- vmdef.arch = options.arch
vmdef.os_type = options.os_type
vmdef.os_variant = options.os_variant
vmdef.noapic = options.noapic
diff --git a/virtconv/formats.py b/virtconv/formats.py
--- a/virtconv/formats.py
+++ b/virtconv/formats.py
@@ -39,7 +39,7 @@
raise NotImplementedError

@staticmethod
- def import_file(input_file):
+ def import_file(input_file, vm):
"""
Import a configuration file. Raises if the file couldn't be
opened, or parsing otherwise failed.
diff --git a/virtconv/parsers/virtimage.py b/virtconv/parsers/virtimage.py
--- a/virtconv/parsers/virtimage.py
+++ b/virtconv/parsers/virtimage.py
@@ -195,7 +195,7 @@
raise NotImplementedError

@staticmethod
- def import_file(input_file):
+ def import_file(input_file, vm):
"""
Import a configuration file. Raises if the file couldn't be
opened, or parsing otherwise failed.
diff --git a/virtconv/parsers/virtinstance.py b/virtconv/parsers/virtinstance.py
new file mode 100644
--- /dev/null
+++ b/virtconv/parsers/virtinstance.py
@@ -0,0 +1,370 @@
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# 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.
+#
+
+from string import ascii_letters
+import virtconv.vmcfg as vmcfg
+import virtconv.diskcfg as diskcfg
+import virtconv.netdevcfg as netdevcfg
+import virtconv.formats as formats
+import virtinst.FullVirtGuest as fv
+
+import os
+import stat
+import re
+
+bootdevs = {
+ vmcfg.VM_TYPE_PV: "",
+ vmcfg.VM_TYPE_HVM: "<boot dev='hd' />",
+}
+
+consoles = {
+ vmcfg.VM_TYPE_PV: "",
+ vmcfg.VM_TYPE_HVM: "<console type='pty' />",
+}
+
+disk_template = """
+<disk %(typeattr)s device='%(device)s'>
+ %(hostdev)s
+ <target dev='%(prefix)s%(dev)s' />
+ %(readonly)s
+</disk>
+"""
+
+netdev_template = """
+<interface type='%(type)s'>
+ %(source)s
+ %(mac)s
+ %(model)s
+</interface>
+"""
+
+instance_template = """
+<domain type='xen'>
+ <name>%(name)s</name>
+ %(bootloader)s
+ <os>
+ <type>%(type)s</type>
+ %(loader)s
+ %(bootdev)s
+ </os>
+ <memory>%(memory)s</memory>
+ <vcpu>%(nr_vcpus)s</vcpu>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <clock offset='%(clock)s'/>
+ <features>
+ %(acpi)s
+ %(apic)s
+ <pae />
+ </features>
+ <devices>
+ %(emulator)s
+ %(disks)s
+ %(netdevs)s
+ <graphics type='vnc' port='-1' />
+ <input type='mouse' bus='ps2' />
+ %(usbtablet)s
+ %(console)s
+ </devices>
+</domain>
+"""
+
+def export_netdevs(vm):
+ """
+ Export code for the network devices.
+ """
+
+ netdevs = []
+
+ for netdev in vm.netdevs.values():
+ mac = ""
+ if netdev.mac != "auto":
+ mac = "<mac address='%s' />" % netdev.mac
+
+ nettype = {
+ netdevcfg.NETDEV_TYPE_DEV : "ethernet",
+ netdevcfg.NETDEV_TYPE_BRIDGE : "bridge",
+ netdevcfg.NETDEV_TYPE_UNKNOWN : "bridge",
+ netdevcfg.NETDEV_TYPE_NETWORK : "network",
+ }.get(netdev.type)
+
+ source = ""
+ if netdev.source:
+ srcattr = nettype
+ if netdev.type == netdevcfg.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,
+ })
+
+ return netdevs
+
+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).
+ """
+
+ 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 == diskcfg.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' />
"
+ "<source file='%s' />
" % disk.path)
+
+ try:
+ if stat.S_ISBLK(os.stat(disk.path)[0]):
+ typeattr = "type='block'"
+ hostdev = ("<driver name='phy' />
"
+ "<source dev='%s' />
" % disk.path)
+ except:
+ pass
+
+ if disk.format == diskcfg.DISK_FORMAT_VDISK:
+ hostdev = ("<driver name='tap' type='vdisk' />
"
+ "<source file='%s' />
" % disk.path)
+
+ device = "disk"
+ readonly = ""
+
+ if (disk.type == diskcfg.DISK_TYPE_CDROM or
+ disk.type == diskcfg.DISK_TYPE_ISO):
+ device = "cdrom"
+ readonly = "<readonly />"
+
+ bus = "ide"
+
+ 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.
+ 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,
+ "readonly" : readonly,
+ })
+
+ return out
+
+def export_os_params(vm):
+ """
+ Export OS-specific parameters.
+ """
+ ostype = None
+ osvariant = None
+
+ ostype = fv.OS_TYPES.get(vm.os_type)
+ if ostype:
+ osvariant = ostype.variants.get(vm.os_variant)
+
+ def get_os_val(key, default):
+ val = None
+ if osvariant:
+ val = osvariant.get(key)
+ if not val and ostype:
+ val = ostype.get(key)
+ if not val:
+ val = default
+ return val
+
+ acpi = ""
+ if vm.noacpi is False and get_os_val("acpi", True):
+ acpi = "<acpi />"
+
+ apic = ""
+ if vm.noapic is False and get_os_val("apic", False):
+ apic = "<apic />"
+
+ clock = get_os_val("clock", "utc")
+
+ usbtablet = ""
+ if get_os_val("input", [ "tablet", "usb" ])[0] == "tablet":
+ usbtablet = "<input type='tablet' bus='usb' />"
+
+ return acpi, apic, clock, usbtablet
+
+
+class virtinstance_parser(formats.parser):
+ """
+ Support for libvirt's domain instance format as defined (mostly) by
+ libvirt.rng. Currently, this only produces domains for Xen.
+
+ This is a somewhat challenging format as it encodes significant
+ amounts of information specific to a particular platform (for
+ example, the pygrub path. For now, we'll assume it's for the current
+ platform. Later, we'd take an optional hypervisor connection.
+
+ Known limitations:
+
+ - Only handles bridge, ethernet, and network type netdevs
+ - doesn't handle netdev script or IP address
+ """
+
+ name = "virt-instance"
+ suffix = ".virt-instance.xml"
+ can_import = False
+ can_export = True
+ can_identify = False
+
+ @staticmethod
+ def identify_file(input_file):
+ """
+ Return True if the given file is of this format.
+ """
+ raise NotImplementedError
+
+ @staticmethod
+ def import_file(input_file, vm):
+ """
+ Import a configuration file. Raises if the file couldn't be
+ opened, or parsing otherwise failed.
+ """
+ raise NotImplementedError
+
+ @staticmethod
+ def export_file(vm, output_file):
+ """
+ Export a configuration file.
+ @vm vm configuration instance
+ @file Output file
+
+ Raises ValueError if configuration is not suitable, or another
+ exception on failure to write the output file.
+ """
+
+ if not vm.memory:
+ raise ValueError("VM must have a memory setting")
+
+ # xend wants the name to match r'^[A-Za-z0-9_-.:/+]+$'
+ vmname = re.sub(r'[^A-Za-z0-9_.:/+-]+', '_', vm.name)
+
+ vmtype = "xen"
+ if vm.type == vmcfg.VM_TYPE_HVM:
+ vmtype = "hvm"
+
+ emulator = vm.emulator()
+ bootloader = ""
+ loader = vm.loader()
+
+ if vm.type == vmcfg.VM_TYPE_PV:
+ bootloader = loader
+ loader = ""
+
+ if bootloader:
+ bootloader = "<bootloader>%s</bootloader>" % bootloader
+ if emulator:
+ emulator = "<emulator>%s</emulator>" % emulator
+ if loader:
+ loader = "<loader>%s</loader>" % loader
+
+ netdevs = export_netdevs(vm)
+ disks = export_disks(vm)
+
+ acpi, apic, clock, usbtablet = export_os_params(vm)
+
+ out = instance_template % {
+ "name" : vmname,
+ "bootloader" : bootloader,
+ "type" : vmtype,
+ "loader" : loader,
+ "bootdev" : bootdevs[vm.type],
+ # Mb to Kb
+ "memory" : int(vm.memory) * 1024,
+ "nr_vcpus" : vm.nr_vcpus,
+ "clock" : clock,
+ "acpi" : acpi,
+ "apic" : apic,
+ "emulator" : emulator,
+ "disks" : "".join(disks),
+ "netdevs" : "".join(netdevs),
+ "usbtablet" : usbtablet,
+ "console" : consoles[vm.type],
+ }
+
+ outfile = open(output_file, "w")
+ outfile.writelines(out)
+ outfile.close()
+
+formats.register_parser(virtinstance_parser)
diff --git a/virtconv/parsers/vmx.py b/virtconv/parsers/vmx.py
--- a/virtconv/parsers/vmx.py
+++ b/virtconv/parsers/vmx.py
@@ -118,13 +118,11 @@
return re.match(r'^#!s*/usr/bin/vm(ware|player)', line) is not None

@staticmethod
- def import_file(input_file):
+ def import_file(input_file, vm):
"""
Import a configuration file. Raises if the file couldn't be
opened, or parsing otherwise failed.
"""
-
- vm = vmcfg.vm()

infile = open(input_file, "r")
contents = infile.readlines()
@@ -175,7 +173,6 @@
vm.nr_vcpus = config.get("numvcpus")

vm.validate()
- return vm

@staticmethod
def export_file(vm, output_file):
diff --git a/virtconv/vmcfg.py b/virtconv/vmcfg.py
--- a/virtconv/vmcfg.py
+++ b/virtconv/vmcfg.py
@@ -21,6 +21,7 @@
import platform
from virtconv import diskcfg
from virtinst import CapabilitiesParser
+from virtinst import util

VM_TYPE_UNKNOWN = 0
VM_TYPE_PV = 1
@@ -46,19 +47,21 @@
name = None
suffix = None

- def __init__(self):
+ def __init__(self, arch, is_pv):
self.name = None
self.description = None
self.memory = None
self.nr_vcpus = None
self.disks = {}
self.netdevs = {}
- self.type = VM_TYPE_HVM
- self.arch = "i686"
+ self.arch = arch
self.noacpi = None
self.noapic = None
self.os_type = None
self.os_variant = None
+ self.type = VM_TYPE_HVM
+ if is_pv:
+ self.type = VM_TYPE_PV

def validate(self):
"""
@@ -82,6 +85,41 @@
raise ValueError("Disk %s:%s storage does not exist"
% (bus, inst))

+ def emulator(self, conn=None):
+ """
+ Return the emulator path for this VM.
+ """
+ typename = "xen"
+ if self.type == VM_TYPE_HVM:
+ typename = "hvm"
+
+ if conn:
+ caps = CapabilitiesParser.parse(conn.getCapabilities())
+ guest = caps.guestForOSType(typename, self.arch)
+ if guest and len(guest.domains):
+ return guest.domains[0].emulator
+
+ if self.type == VM_TYPE_PV:
+ return ""
+ return util.default_emulator()
+
+ def loader(self, conn=None):
+ """
+ Return the loader path for this VM.
+ """
+
+ # loader is not set for PV in capabilities
+ if self.type == VM_TYPE_PV:
+ return util.pygrub_path(conn)
+
+ if conn:
+ caps = CapabilitiesParser.parse(conn.getCapabilities())
+ guest = caps.guestForOSType("hvm", self.arch)
+ if guest and len(guest.domains):
+ return guest.domains[0].loader
+
+ return util.default_loader()
+
def host(conn=None):
"""
Return the host, as seen in platform.system(), but possibly from a
diff --git a/virtinst/FullVirtGuest.py b/virtinst/FullVirtGuest.py
--- a/virtinst/FullVirtGuest.py
+++ b/virtinst/FullVirtGuest.py
@@ -124,13 +124,10 @@
self.arch = arch
if emulator is None:
if self.type == "xen":
- if os.uname()[4] in ("x86_64"):
- emulator = "/usr/lib64/xen/bin/qemu-dm"
- else:
- emulator = "/usr/lib/xen/bin/qemu-dm"
+ emulator = util.default_emulator()
self.emulator = emulator
if self.type == "xen":
- self.loader = "/usr/lib/xen/boot/hvmloader"
+ self.loader = util.default_loader()
else:
self.loader = None
self._os_type = None
diff --git a/virtinst/util.py b/virtinst/util.py
--- a/virtinst/util.py
+++ b/virtinst/util.py
@@ -295,3 +295,13 @@
if platform.system() == "SunOS":
return "/usr/lib/xen/bin/pygrub"
return "/usr/bin/pygrub"
+
+def default_emulator():
+ """Return a default emulator for a domain."""
+ if os.uname()[4] in ("x86_64"):
+ return "/usr/lib64/xen/bin/qemu-dm"
+ return "/usr/lib/xen/bin/qemu-dm"
+
+def default_loader():
+ """Return a default loader for a domain."""
+ return "/usr/lib/xen/boot/hvmloader"

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Cole Robinson 07-14-2008 04:55 PM

virt-convert: Add "virt-instance" formatter
 
john.levon@sun.com wrote:
> # HG changeset patch
> # User john.levon@sun.com
> # Date 1215697572 25200
> # Node ID 112cd8c4aa97e9da9d7532fee7d826d35e1003e8
> # Parent 92de696f634f80d47b9413b9db5101de0edf9b7f
> virt-convert: Add "virt-instance" formatter.
>
> Allow output in libvirt.rng format
>

So I'm not generally opposed to this idea, however the way this patch
implements it is a massive duplication of the virtinst apis, so
NACK in this current form.

Like Dan mentioned before, if we allow converting to libvirt xml, we
need to make it clear that the generated config is really only
applicable on the machine it is generated. A connection must be
required in order to do the conversion so we can use the virtinst
apis and check capabilities xml. This makes it kind of messy since
we will have cli options that are relevant for some formats and
not for others, but it's unavoidable, and as long as the
documentation is clear, it shouldn't be confusing.

Thanks,
Cole

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools


All times are GMT. The time now is 12:23 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.