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 <crobinso(a)redhat.com>
---
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 <mdehaan(a)redhat.com>
+
+Original version based on virtguest-install
+Jeremy Katz <katzj(a)redhat.com>
+Option handling added by Andrew Puch <apuch(a)redhat.com>
+Simplified for use as library by koan, Michael DeHaan <mdehaan(a)redhat.com>
+
+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