We break out the virt-install logic to a separate file, since further conversions are going to be able to share 90% of the code (basically the whole point of libvirt :) ).
In the process we drop a lot of hacks and workarounds for things that have been fixed in virtinst for at least a year, some for as long as 3. The required virtinst dep is fairly recent anyways with the call to guest.set_autostart. Signed-off-by: Cole Robinson <[email protected]> --- koan/virtinstall.py | 182 +++++++++++++++++++++++++++++++++++++++++++++ koan/xencreate.py | 173 ++----------------------------------------- tests/koan/__init__.py | 1 + tests/koan/virtinstall.py | 57 ++++++++++++++ 4 files changed, 246 insertions(+), 167 deletions(-) create mode 100755 koan/virtinstall.py create mode 100644 tests/koan/virtinstall.py diff --git a/koan/virtinstall.py b/koan/virtinstall.py new file mode 100755 index 0000000..5a56634 --- /dev/null +++ b/koan/virtinstall.py @@ -0,0 +1,182 @@ +""" +Virtualization installation functions. +Currently somewhat Xen/paravirt specific, will evolve later. + +Copyright 2006-2008 Red Hat, Inc. +Michael DeHaan <[email protected]> + +Original version based on virtguest-install +Jeremy Katz <[email protected]> +Option handling added by Andrew Puch <[email protected]> +Simplified for use as library by koan, Michael DeHaan <[email protected]> + +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 +""" + +import re + +import app as koan +import utils + +def _sanitize_disks(disks): + ret = [] + for d in disks: + if d[1] != 0 or d[0].startswith("/dev"): + ret.append((d[0], d[1])) + else: + raise koan.InfoException("this virtualization type does not work without a disk image, set virt-size in Cobbler to non-zero") + + return ret + +def _sanitize_nics(nics, bridge, profile_bridge): + ret = [] + + if not nics: + return ret + + interfaces = nics.keys() + interfaces.sort() + counter = -1 + vlanpattern = re.compile("[a-zA-Z0-9]+\.[0-9]+") + + for iname in interfaces: + counter = counter + 1 + intf = nics[iname] + + if (intf["interface_type"] in ("master","bond","bridge") or + vlanpattern.match(iname) or iname.find(":") != -1): + continue + + mac = intf["mac_address"] + + if not bridge: + intf_bridge = intf["virt_bridge"] + if intf_bridge == "": + if profile_bridge == "": + raise koan.InfoException("virt-bridge setting is not defined in cobbler") + intf_bridge = profile_bridge + + else: + if bridge.find(",") == -1: + intf_bridge = bridge + else: + bridges = bridge.split(",") + intf_bridge = bridges[counter] + + ret.append((intf_bridge, mac)) + + return ret + + +def build_commandline(name=None, + ram=None, + disks=None, + uuid=None, + extra=None, + vcpus=None, + profile_data=None, + arch=None, + no_gfx=False, + fullvirt=False, + bridge=None, + virt_type=None, + virt_auto_boot=False, + qemu_driver_type=None, + qemu_net_type=None): + + if profile_data.has_key("file"): + raise koan.InfoException("Xen does not work with --image yet") + + disks = _sanitize_disks(disks) + nics = _sanitize_nics(profile_data.get("interfaces"), + bridge, + profile_data.get("virt_bridge")) + if not nics: + # for --profile you get one NIC, go define a system if you want more. + # FIXME: can mac still be sent on command line in this case? + + if bridge is None: + bridge = profile_data["virt_bridge"] + + if bridge == "": + raise koan.InfoException("virt-bridge setting is not defined in cobbler") + nics = [(bridge, None)] + + + kernel = profile_data.get("kernel_local") + initrd = profile_data.get("initrd_local") + breed = profile_data.get("breed") + os_version = profile_data.get("os_version") + + cmd = "virt-install --connect xen:/// " + + cmd += "--name %s " % name + cmd += "--ram %s " % ram + cmd += "--vcpus %s " % vcpus + + if uuid: + cmd += "--uuid %s " % uuid + + if virt_auto_boot: + cmd += "--autostart " + + if no_gfx: + cmd += "--nographics " + else: + cmd += "--vnc " + + if fullvirt: + cmd += "--hvm " + cmd += "--pxe " + if arch: + cmd += "--arch %s " % arch + else: + cmd += "--paravirt " + cmd += ("--boot kernel=%s,initrd=%s,kernel_args=%s " % + (kernel, initrd, extra)) + + if breed and breed != "other": + if os_version and os_version != "other": + cmd += "--os-variant %s " % os_version + else: + distro = "unix" + if breed in [ "debian", "suse", "redhat" ]: + distro = "linux" + elif breed in [ "windows" ]: + distro = "windows" + + cmd += "--os-type %s " % distro + + for path, size in disks: + cmd += "--disk path=%s" % (path) + if str(size) != "0": + cmd += ",size=%s" % size + cmd += " " + + for bridge, mac in nics: + cmd += "--network bridge=%s" % bridge + if mac: + cmd += ",mac=%s" % mac + cmd += " " + + cmd += "--wait 0 " + cmd += "--noautoconsole " + + return cmd + +def start_install(*args, **kwargs): + cmd = build_commandline(*args, **kwargs) + utils.subprocess_call(cmd) diff --git a/koan/xencreate.py b/koan/xencreate.py index 50178a3..6279fe7 100755 --- a/koan/xencreate.py +++ b/koan/xencreate.py @@ -1,5 +1,5 @@ """ -Virtualization installation functions. +Virtualization installation functions. Currently somewhat Xen/paravirt specific, will evolve later. Copyright 2006-2008 Red Hat, Inc. @@ -26,170 +26,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """ -import os, sys, time, stat -import tempfile -import random -import exceptions -import errno -import re -import virtinst -import app as koan +import utils +import virtinstall -try: - import virtinst.DistroInstaller as DistroManager -except: - # older virtinst, this is probably ok - # but we know we can't do Xen fullvirt installs - pass -import traceback - -def random_mac(): - """ - from xend/server/netif.py - Generate a random MAC address. - Uses OUI 00-16-3E, allocated to - Xensource, Inc. Last 3 fields are random. - return: MAC address string - """ - mac = [ 0x00, 0x16, 0x3e, - random.randint(0x00, 0x7f), - random.randint(0x00, 0xff), - random.randint(0x00, 0xff) ] - return ':'.join(map(lambda x: "%02x" % x, mac)) - - -def start_install(name=None, - ram=None, - disks=None, - uuid=None, - extra=None, - vcpus=None, - profile_data=None, - arch=None, - no_gfx=False, - fullvirt=False, - bridge=None, - virt_type=None, - virt_auto_boot=False, - qemu_driver_type=None, - qemu_net_type=None): - - if profile_data.has_key("file"): - raise koan.InfoException("Xen does not work with --image yet") - - if fullvirt: - # FIXME: add error handling here to explain when it's not supported - guest = virtinst.FullVirtGuest(installer=virtinst.PXEInstaller()) - else: - guest = virtinst.ParaVirtGuest() - - extra = extra.replace("&","&") - - if not fullvirt: - guest.set_boot((profile_data["kernel_local"], profile_data["initrd_local"])) - # fullvirt OS's will get this from the PXE config (managed by Cobbler) - guest.extraargs = extra - else: - print "- fullvirt mode" - if profile_data.has_key("breed"): - breed = profile_data["breed"] - if breed != "other" and breed != "": - if breed in [ "debian", "suse", "redhat" ]: - guest.set_os_type("linux") - elif breed in [ "windows" ]: - guest.set_os_type("windows") - else: - guest.set_os_type("unix") - if profile_data.has_key("os_version"): - # FIXME: when os_version is not defined and it's linux, do we use generic24/generic26 ? - version = profile_data["os_version"] - if version != "other" and version != "": - try: - guest.set_os_variant(version) - except: - print "- virtinst library does not understand variant %s, treating as generic" % version - pass - - - guest.set_name(name) - guest.set_memory(ram) - guest.set_vcpus(vcpus) - guest.set_autostart(virt_auto_boot) - - if not no_gfx: - guest.set_graphics("vnc") - else: - guest.set_graphics(False) - - if uuid is not None: - guest.set_uuid(uuid) - - for d in disks: - if d[1] != 0 or d[0].startswith("/dev"): - guest.disks.append(virtinst.XenDisk(d[0], size=d[1])) - else: - raise koan.InfoException("this virtualization type does not work without a disk image, set virt-size in Cobbler to non-zero") - - counter = 0 - - if profile_data.has_key("interfaces"): - - interfaces = profile_data["interfaces"].keys() - interfaces.sort() - counter = -1 - vlanpattern = re.compile("[a-zA-Z0-9]+\.[0-9]+") - - for iname in interfaces: - counter = counter + 1 - intf = profile_data["interfaces"][iname] - - if intf["interface_type"] in ("master","bond","bridge") or vlanpattern.match(iname) or iname.find(":") != -1: - continue - - mac = intf["mac_address"] - if mac == "": - mac = random_mac() - - if not bridge: - profile_bridge = profile_data["virt_bridge"] - - intf_bridge = intf["virt_bridge"] - if intf_bridge == "": - if profile_bridge == "": - raise koan.InfoException("virt-bridge setting is not defined in cobbler") - intf_bridge = profile_bridge - - else: - if bridge.find(",") == -1: - intf_bridge = bridge - else: - bridges = bridge.split(",") - intf_bridge = bridges[counter] - - - nic_obj = virtinst.XenNetworkInterface(macaddr=mac, bridge=intf_bridge) - guest.nics.append(nic_obj) - counter = counter + 1 - - else: - # for --profile you just get one NIC, go define a system if you want more. - # FIXME: can mac still be sent on command line in this case? - - if bridge is None: - profile_bridge = profile_data["virt_bridge"] - else: - profile_bridge = bridge - - if profile_bridge == "": - raise koan.InfoException("virt-bridge setting is not defined in cobbler") - - nic_obj = virtinst.XenNetworkInterface(macaddr=random_mac(), bridge=profile_bridge) - guest.nics.append(nic_obj) - - - - - guest.start_install() - - return "use virt-manager or reconnect with virsh console %s" % name - +def start_install(*args, **kwargs): + cmd = virtinstall.build_commandline("xen:///", *args, **kwargs) + utils.subprocess_call(cmd) diff --git a/tests/koan/__init__.py b/tests/koan/__init__.py index e69de29..370e90e 100644 --- a/tests/koan/__init__.py +++ b/tests/koan/__init__.py @@ -0,0 +1 @@ +import virtinstall diff --git a/tests/koan/virtinstall.py b/tests/koan/virtinstall.py new file mode 100644 index 0000000..cff0f2e --- /dev/null +++ b/tests/koan/virtinstall.py @@ -0,0 +1,57 @@ +import unittest + +from koan.virtinstall import build_commandline + +class KoanVirtInstallTest(unittest.TestCase): + def testXenPVBasic(self): + cmd = build_commandline("xen:///", + name="foo", + ram=256, + uuid="ad6611b9-98e4-82c8-827f-051b6b6680d7", + vcpus=1, + bridge="br0", + disks=[("/tmp/foo1.img", 8), ("/dev/foo1", 0)], + profile_data={ + "kernel_local" : "kernel", + "initrd_local" : "initrd", + }, + extra="ks=http://example.com/ks.ks") + + self.assertEquals(cmd, + ("virt-install --connect xen:/// --name foo --ram 256 --vcpus 1 " + "--uuid ad6611b9-98e4-82c8-827f-051b6b6680d7 --vnc --paravirt " + "--boot kernel=kernel,initrd=initrd,kernel_args=ks=http://example.com/ks.ks " + "--disk path=/tmp/foo1.img,size=8 --disk path=/dev/foo1 " + "--network bridge=br0 " + "--wait 0 --noautoconsole ")) + + def testXenFVBasic(self): + cmd = build_commandline("xen:///", + name="foo", + ram=256, + vcpus=1, + disks=[("/dev/foo1", 0)], + fullvirt=True, + arch="x86_64", + bridge="br0,br1", + profile_data = { + "breed" : "redhat", + "os_version" : "fedora14", + "interfaces" : { + "eth0": { + "interface_type": "na", + "mac_address": "11:22:33:44:55:66", + }, "eth1": { + "interface_type": "na", + "mac_address": "11:22:33:33:22:11", + } + } + }) + + self.assertEquals(cmd, + ("virt-install --connect xen:/// --name foo --ram 256 --vcpus 1 " + "--vnc --hvm --pxe --arch x86_64 " + "--os-variant fedora14 --disk path=/dev/foo1 " + "--network bridge=br0,mac=11:22:33:44:55:66 " + "--network bridge=br1,mac=11:22:33:33:22:11 " + "--wait 0 --noautoconsole ")) -- 1.7.7.5 _______________________________________________ cobbler mailing list [email protected] https://fedorahosted.org/mailman/listinfo/cobbler
