mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-25 18:55:27 -06:00
Add better error catching and reporting for add/remove hardware.
The particulars: 1) Build virtinst VirtualDisk and VirtualNics as we go through creation wizards to reuse present validation. 2) Added a few cases of using the "install_error" infrastructure if we fail when at the end of the wizard. 3) Added error checking for removing hardware in the 'details' screen. 4) A small cleanup in create.py
This commit is contained in:
@@ -59,6 +59,8 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.__gobject_init__()
|
||||
self.config = config
|
||||
self.vm = vm
|
||||
self._net = None
|
||||
self._disk = None
|
||||
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-add-hardware.glade", "vmm-add-hardware", domain="virt-manager")
|
||||
self.topwin = self.window.get_widget("vmm-add-hardware")
|
||||
self.topwin.hide()
|
||||
@@ -429,18 +431,8 @@ class vmmAddHardware(gobject.GObject):
|
||||
self.close()
|
||||
|
||||
def add_network(self):
|
||||
net = self.get_config_network()
|
||||
mac = self.get_config_macaddr()
|
||||
vnic = None
|
||||
if net[0] == "bridge":
|
||||
vnic = virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], bridge=net[1])
|
||||
elif net[0] == "network":
|
||||
vnic = virtinst.VirtualNetworkInterface(macaddr=mac, type=net[0], network=net[1])
|
||||
else:
|
||||
raise ValueError, "Unsupported networking type " + net[0]
|
||||
|
||||
vnic.setup(self.vm.get_connection().vmm)
|
||||
self.add_device(vnic.get_xml_config())
|
||||
self._net.setup(self.vm.get_connection().vmm)
|
||||
self.add_device(self._net.get_xml_config())
|
||||
|
||||
def add_input(self):
|
||||
input = self.get_config_input()
|
||||
@@ -469,22 +461,6 @@ class vmmAddHardware(gobject.GObject):
|
||||
|
||||
def add_storage(self):
|
||||
node, maxnode, device = self.get_config_disk_target()
|
||||
filesize = None
|
||||
disk = None
|
||||
if self.get_config_disk_size() != None:
|
||||
filesize = self.get_config_disk_size() / 1024.0
|
||||
try:
|
||||
disk = virtinst.VirtualDisk(self.get_config_disk_image(),
|
||||
filesize,
|
||||
device = device,
|
||||
sparse = self.is_sparse_file())
|
||||
if disk.type == virtinst.VirtualDisk.TYPE_FILE and \
|
||||
not self.vm.is_hvm() \
|
||||
and virtinst.util.is_blktap_capable():
|
||||
disk.driver_name = virtinst.VirtualDisk.DRIVER_TAP
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid storage address"), e.args[0])
|
||||
return
|
||||
|
||||
used = {}
|
||||
for d in self.vm.get_disk_devices():
|
||||
@@ -511,33 +487,30 @@ class vmmAddHardware(gobject.GObject):
|
||||
break
|
||||
|
||||
if node is None:
|
||||
self._validation_error_box(_("Too many virtual disks"),
|
||||
_("There are no more available virtual disk device nodes"))
|
||||
value = _("There are no more available virtual disk device nodes")
|
||||
details = "Unable to complete install: '%s'" % value
|
||||
self.install_error = _("Unable to complete install: '%s'") % value
|
||||
self.install_details = details
|
||||
return
|
||||
|
||||
progWin = vmmAsyncJob(self.config, self.do_file_allocate, [disk],
|
||||
progWin = vmmAsyncJob(self.config, self.do_file_allocate, [self._disk],
|
||||
title=_("Creating Storage File"),
|
||||
text=_("Allocation of disk storage may take a few minutes " + \
|
||||
"to complete."))
|
||||
progWin.run()
|
||||
|
||||
if self.install_error == None:
|
||||
self.add_device(disk.get_xml_config(node))
|
||||
self.add_device(self._disk.get_xml_config(node))
|
||||
|
||||
def add_device(self, xml):
|
||||
logging.debug("Adding device " + xml)
|
||||
try:
|
||||
self.vm.add_device(xml)
|
||||
except:
|
||||
(type, value, stacktrace) = sys.exc_info ()
|
||||
|
||||
# Detailed error message, in English so it can be Googled.
|
||||
details = \
|
||||
"Unable to complete install '%s'" % \
|
||||
(str(type) + " " + str(value) + "\n" + \
|
||||
traceback.format_exc (stacktrace))
|
||||
|
||||
self.install_error = _("Unable to complete install: '%s'") % str(value)
|
||||
except Exception, e:
|
||||
details = "Unable to complete install: '%s'" % \
|
||||
"".join(traceback.format_exc())
|
||||
self.install_error = _("Unable to complete install: '%s'") \
|
||||
% str(e)
|
||||
self.install_details = details
|
||||
logging.error(details)
|
||||
|
||||
@@ -547,16 +520,11 @@ class vmmAddHardware(gobject.GObject):
|
||||
logging.debug("Starting background file allocate process")
|
||||
disk.setup(meter)
|
||||
logging.debug("Allocation completed")
|
||||
except:
|
||||
(type, value, stacktrace) = sys.exc_info ()
|
||||
|
||||
# Detailed error message, in English so it can be Googled.
|
||||
details = \
|
||||
"Unable to complete install '%s'" % \
|
||||
(str(type) + " " + str(value) + "\n" + \
|
||||
traceback.format_exc (stacktrace))
|
||||
|
||||
self.install_error = _("Unable to complete install: '%s'") % str(value)
|
||||
except Exception, e:
|
||||
details = "Unable to complete install: '%s'" % \
|
||||
"".join(traceback.format_exc())
|
||||
self.install_error = _("Unable to complete install: '%s'") \
|
||||
% str(e)
|
||||
self.install_details = details
|
||||
logging.error(details)
|
||||
|
||||
@@ -671,28 +639,27 @@ class vmmAddHardware(gobject.GObject):
|
||||
_("You must specify what type of hardware to add"))
|
||||
return False
|
||||
elif page_num == PAGE_DISK:
|
||||
disk = self.get_config_disk_image()
|
||||
if disk == None or len(disk) == 0:
|
||||
path = self.get_config_disk_image()
|
||||
if path == None or len(path) == 0:
|
||||
self._validation_error_box(_("Storage Address Required"), \
|
||||
_("You must specify a partition or a file for storage for the guest install"))
|
||||
return False
|
||||
|
||||
if not self.window.get_widget("storage-partition").get_active():
|
||||
if os.path.isdir(disk):
|
||||
self._validation_error_box(_("Storage Address Is Directory"), \
|
||||
_("You chose 'Simple File' storage for your storage method, but chose a directory instead of a file. Please enter a new filename or choose an existing file."))
|
||||
return False
|
||||
|
||||
|
||||
if self.window.get_widget("target-device").get_active() == -1:
|
||||
self._validation_error_box(_("Target Device Required"),
|
||||
_("You must select a target device for the disk"))
|
||||
return False
|
||||
|
||||
node, nodemax, device = self.get_config_disk_target()
|
||||
if self.window.get_widget("storage-partition").get_active():
|
||||
type = virtinst.VirtualDisk.TYPE_BLOCK
|
||||
else:
|
||||
type = virtinst.VirtualDisk.TYPE_FILE
|
||||
|
||||
if not self.window.get_widget("storage-partition").get_active():
|
||||
disk = self.get_config_disk_image()
|
||||
size = self.get_config_disk_size()
|
||||
if not os.path.exists(disk):
|
||||
dir = os.path.dirname(os.path.abspath(disk))
|
||||
if not os.path.exists(path):
|
||||
dir = os.path.dirname(os.path.abspath(path))
|
||||
if not os.path.exists(dir):
|
||||
self._validation_error_box(_("Storage Path Does not exist"),
|
||||
_("The directory %s containing the disk image does not exist") % dir)
|
||||
@@ -712,22 +679,30 @@ class vmmAddHardware(gobject.GObject):
|
||||
_("There is not enough free space to create the disk"))
|
||||
return False
|
||||
|
||||
node, nodemax, device = self.get_config_disk_target()
|
||||
if self.window.get_widget("storage-partition").get_active():
|
||||
type = virtinst.VirtualDisk.TYPE_BLOCK
|
||||
else:
|
||||
type = virtinst.VirtualDisk.TYPE_FILE
|
||||
|
||||
d = virtinst.VirtualDisk(self.get_config_disk_image(),
|
||||
self.get_config_disk_size(),
|
||||
type = type,
|
||||
sparse = self.is_sparse_file(),
|
||||
device=device)
|
||||
if d.is_conflict_disk(self.vm.get_connection().vmm) is True:
|
||||
res = self._yes_no_box(_('Disk "%s" is already in use by another guest!' % disk), \
|
||||
# Build disk object
|
||||
filesize = self.get_config_disk_size()
|
||||
if self.get_config_disk_size() != None:
|
||||
filesize = self.get_config_disk_size() / 1024.0
|
||||
try:
|
||||
self._disk = virtinst.VirtualDisk(self.get_config_disk_image(),
|
||||
filesize,
|
||||
type = type,
|
||||
sparse = self.is_sparse_file(),
|
||||
device=device)
|
||||
if self._disk.type == virtinst.VirtualDisk.TYPE_FILE and \
|
||||
not self.vm.is_hvm() and virtinst.util.is_blktap_capable():
|
||||
disk.driver_name = virtinst.VirtualDisk.DRIVER_TAP
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid Storage Parameters"), \
|
||||
str(e))
|
||||
return False
|
||||
|
||||
if self._disk.is_conflict_disk(self.vm.get_connection().vmm) is True:
|
||||
res = self._yes_no_box(_('Disk "%s" is already in use by another guest!' % self._disk), \
|
||||
_("Do you really want to use the disk ?"))
|
||||
return res
|
||||
elif page_num == PAGE_NETWORK:
|
||||
net = self.get_config_network()
|
||||
if self.window.get_widget("net-type-network").get_active():
|
||||
if self.window.get_widget("net-network").get_active() == -1:
|
||||
self._validation_error_box(_("Virtual Network Required"),
|
||||
@@ -739,16 +714,21 @@ class vmmAddHardware(gobject.GObject):
|
||||
_("You must select one of the physical devices"))
|
||||
return False
|
||||
|
||||
mac = self.get_config_macaddr()
|
||||
if self.window.get_widget("mac-address").get_active():
|
||||
mac= self.window.get_widget("create-mac-address").get_text()
|
||||
if len(mac) != 17:
|
||||
|
||||
if mac is None or len(mac) == 0:
|
||||
self._validation_error_box(_("Invalid MAC address"), \
|
||||
_("MAC adrress must be 17 characters"))
|
||||
_("No MAC address was entered. Please enter a valid MAC address."))
|
||||
return False
|
||||
if re.match("^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$",mac) == None:
|
||||
|
||||
try:
|
||||
self._net = virtinst.VirtualNetworkInterface(macaddr=mac)
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid MAC address"), \
|
||||
_("MAC address must be a form such as AA:BB:CC:DD:EE:FF, and MAC adrress may contain numeric and alphabet of A-F(a-f) and ':' characters only"))
|
||||
str(e))
|
||||
return False
|
||||
|
||||
hostdevs = virtinst.util.get_host_network_devices()
|
||||
for hostdev in hostdevs:
|
||||
if mac.lower() == hostdev[4]:
|
||||
@@ -765,14 +745,30 @@ class vmmAddHardware(gobject.GObject):
|
||||
vm = self.vm.get_connection().vmm.lookupByName(name)
|
||||
inactive_vm.append(vm)
|
||||
|
||||
vnic = virtinst.VirtualNetworkInterface(macaddr=mac)
|
||||
if (vnic.countMACaddr(vms) - vnic.countMACaddr(inactive_vm)) > 0:
|
||||
if (self._net.countMACaddr(vms) - self._net.countMACaddr(inactive_vm)) > 0:
|
||||
return self._validation_error_box(_('MAC address "%s" is already in use by an active guest') % mac, \
|
||||
_("Please enter a different MAC address or select no fixed MAC address"))
|
||||
elif vnic.countMACaddr(inactive_vm) > 0:
|
||||
elif self._net.countMACaddr(inactive_vm) > 0:
|
||||
return self._yes_no_box(_('MAC address "%s" is already in use by another inactive guest!') % mac, \
|
||||
_("Do you really want to use the MAC address ?"))
|
||||
|
||||
|
||||
try:
|
||||
if net[0] == "bridge":
|
||||
self._net = virtinst.VirtualNetworkInterface(macaddr=mac,
|
||||
type=net[0],
|
||||
bridge=net[1])
|
||||
elif net[0] == "network":
|
||||
self._net = virtinst.VirtualNetworkInterface(macaddr=mac,
|
||||
type=net[0],
|
||||
network=net[1])
|
||||
else:
|
||||
raise ValueError, _("Unsupported networking type") + net[0]
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid Network Parameter"), \
|
||||
str(e))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _validation_error_box(self, text1, text2=None):
|
||||
@@ -819,7 +815,6 @@ class vmmAddHardware(gobject.GObject):
|
||||
model.append(["%s (%s)" % (net.get_name(), _("Not bridged")), False])
|
||||
return hasShared
|
||||
|
||||
|
||||
def populate_target_device_model(self, model):
|
||||
model.clear()
|
||||
if self.vm.is_hvm():
|
||||
|
||||
@@ -934,12 +934,6 @@ class vmmCreate(gobject.GObject):
|
||||
self._validation_error_box(_("Invalid MAC address"), \
|
||||
_("No MAC address was entered. Please enter a valid MAC address."))
|
||||
return False
|
||||
try:
|
||||
self._guest.mac = mac
|
||||
except ValueError, e:
|
||||
self._validation_error_box(_("Invalid Mac address"), \
|
||||
str(e))
|
||||
return False
|
||||
|
||||
hostdevs = virtinst.util.get_host_network_devices()
|
||||
for hostdev in hostdevs:
|
||||
|
||||
@@ -24,6 +24,7 @@ import libvirt
|
||||
import sparkline
|
||||
import logging
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
from virtManager.error import vmmErrorDialog
|
||||
from virtManager.addhardware import vmmAddHardware
|
||||
@@ -557,10 +558,23 @@ class vmmDetails(gobject.GObject):
|
||||
path = None
|
||||
else:
|
||||
path = diskinfo[1]
|
||||
vbd = virtinst.VirtualDisk(path=path, type=diskinfo[0], device=diskinfo[2])
|
||||
xml = vbd.get_xml_config(diskinfo[3])
|
||||
|
||||
self.vm.remove_device(xml)
|
||||
try:
|
||||
vbd = virtinst.VirtualDisk(path=path,
|
||||
type=diskinfo[0],
|
||||
device=diskinfo[2])
|
||||
except Exception, e:
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
_("Error Removing Disk: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
return
|
||||
|
||||
xml = vbd.get_xml_config(diskinfo[3])
|
||||
self.remove_device(xml)
|
||||
self.refresh_resources()
|
||||
|
||||
def remove_network(self, src):
|
||||
@@ -571,15 +585,25 @@ class vmmDetails(gobject.GObject):
|
||||
netinfo = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
|
||||
|
||||
vnic = None
|
||||
if netinfo[0] == "bridge":
|
||||
vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], bridge=netinfo[1], macaddr=netinfo[3])
|
||||
elif netinfo[0] == "network":
|
||||
vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], network=netinfo[1], macaddr=netinfo[3])
|
||||
else:
|
||||
vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], macaddr=netinfo[3])
|
||||
try:
|
||||
if netinfo[0] == "bridge":
|
||||
vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], bridge=netinfo[1], macaddr=netinfo[3])
|
||||
elif netinfo[0] == "network":
|
||||
vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], network=netinfo[1], macaddr=netinfo[3])
|
||||
else:
|
||||
vnic = virtinst.VirtualNetworkInterface(type=netinfo[0], macaddr=netinfo[3])
|
||||
except ValueError, e:
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
_("Error Removing Network: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
return
|
||||
|
||||
xml = vnic.get_xml_config()
|
||||
self.vm.remove_device(xml)
|
||||
self.remove_device(xml)
|
||||
self.refresh_resources()
|
||||
|
||||
def remove_input(self, src):
|
||||
@@ -590,7 +614,7 @@ class vmmDetails(gobject.GObject):
|
||||
inputinfo = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
|
||||
|
||||
xml = "<input type='%s' bus='%s'/>" % (inputinfo[0], inputinfo[1])
|
||||
self.vm.remove_device(xml)
|
||||
self.remove_device(xml)
|
||||
self.refresh_resources()
|
||||
|
||||
def remove_graphics(self, src):
|
||||
@@ -601,7 +625,7 @@ class vmmDetails(gobject.GObject):
|
||||
inputinfo = active[0].get_value(active[1], HW_LIST_COL_DEVICE)
|
||||
|
||||
xml = "<graphics type='%s'/>" % inputinfo[0]
|
||||
self.vm.remove_device(xml)
|
||||
self.remove_device(xml)
|
||||
self.refresh_resources()
|
||||
|
||||
def prepare_hw_list(self):
|
||||
@@ -760,12 +784,33 @@ class vmmDetails(gobject.GObject):
|
||||
def toggle_cdrom(self, src):
|
||||
if src.get_label() == gtk.STOCK_DISCONNECT:
|
||||
#disconnect the cdrom
|
||||
self.vm.disconnect_cdrom_device(self.window.get_widget("disk-target-device").get_text())
|
||||
try:
|
||||
self.vm.disconnect_cdrom_device(self.window.get_widget("disk-target-device").get_text())
|
||||
except Exception, e:
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
_("Error Removing CDROM: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
return
|
||||
|
||||
else:
|
||||
# connect a new cdrom
|
||||
if self.choose_cd is None:
|
||||
self.choose_cd = vmmChooseCD(self.config, self.window.get_widget("disk-target-device").get_text())
|
||||
try:
|
||||
self.choose_cd.connect("cdrom-chosen", self.connect_cdrom)
|
||||
except Exception, e:
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
_("Error Connecting CDROM: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
return
|
||||
else:
|
||||
self.choose_cd.set_target(self.window.get_widget("disk-target-device").get_text())
|
||||
self.choose_cd.show()
|
||||
@@ -773,4 +818,17 @@ class vmmDetails(gobject.GObject):
|
||||
def connect_cdrom(self, src, type, source, target):
|
||||
self.vm.connect_cdrom_device(type, source, target)
|
||||
|
||||
def remove_device(self, xml):
|
||||
try:
|
||||
self.vm.remove_device(xml)
|
||||
except Exception, e:
|
||||
dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
_("Error Removing Device: %s" % str(e)),
|
||||
"".join(traceback.format_exc()))
|
||||
dg.run()
|
||||
dg.hide()
|
||||
dg.destroy()
|
||||
|
||||
|
||||
gobject.type_register(vmmDetails)
|
||||
|
||||
Reference in New Issue
Block a user