The attached patch is the result of trying to add error reporting to some common tasks in virt-manager: pause, unpause, shutdown, and run, as well as save and destroy. Since the first 4 commands can be called from 3 different locations (console, details, manager), I consolidated their code into engine.py, as had been done in the past with save and destroy. All these commands now show an error dialog if an exception is thrown. I also fixed an associated issue where the pause buttons in console and details can be put out of sync if pause/unpause failed. I tested all these by manually throwing exceptions in the libvirt bindings. It's kind of a lot of churn, but I think it's more maintainable this way. - Cole > console.py | 71 +++++++++------------------------ > details.py | 129 +++++++++++++++++++------------------------------------------ > engine.py | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++-- > manager.py | 32 +++++++++++---- > 4 files changed, 196 insertions(+), 150 deletions(-) -- Cole Robinson crobinso@xxxxxxxxxx
diff -r 30260e2c3a37 src/virtManager/console.py --- a/src/virtManager/console.py Tue Nov 20 11:12:20 2007 -0500 +++ b/src/virtManager/console.py Wed Nov 21 12:19:57 2007 -0500 @@ -48,7 +48,15 @@ class vmmConsole(gobject.GObject): "action-show-help": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str]), "action-destroy-domain": (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, (str,str)) + gobject.TYPE_NONE, (str,str)), + "action-suspend-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-resume-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-run-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-shutdown-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), } def __init__(self, config, vm): self.__gobject_init__() @@ -512,59 +520,22 @@ class vmmConsole(gobject.GObject): fcdialog.hide() fcdialog.destroy() - def control_vm_run(self, src): - status = self.vm.status() - if status != libvirt.VIR_DOMAIN_SHUTOFF: - pass - else: - try: - self.vm.startup() - except: - (type, value, stacktrace) = sys.exc_info () - - # Detailed error message, in English so it can be Googled. - details = \ - "Unable to start virtual machine '%s'" % \ - (str(type) + " " + str(value) + "\n" + \ - traceback.format_exc (stacktrace)) - - dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, - str(value), - details) - dg.run() - dg.hide() - dg.destroy() - - - - def control_vm_shutdown(self, src): - status = self.vm.status() - if not(status in [ libvirt.VIR_DOMAIN_SHUTDOWN, libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]): - self.vm.shutdown() - else: - logging.warning("Shutdown requested, but machine is already shutting down / shutoff") - def control_vm_pause(self, src): if self.ignorePause: return - status = self.vm.status() - if status in [ libvirt.VIR_DOMAIN_SHUTDOWN, libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]: - logging.warning("Pause/resume requested, but machine is shutdown / shutoff") - else: - if status in [ libvirt.VIR_DOMAIN_PAUSED ]: - if not src.get_active(): - self.vm.resume() - else: - logging.warning("Pause requested, but machine is already paused") - else: - if src.get_active(): - self.vm.suspend() - else: - logging.warning("Resume requested, but machine is already running") - - self.window.get_widget("control-pause").set_active(src.get_active()) - self.window.get_widget("menu-vm-pause").set_active(src.get_active()) + if src.get_active(): + self.emit("action-suspend-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) + else: + self.emit("action-resume-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) + + self.update_widget_states(self.vm, self.vm.status()) + + def control_vm_run(self, src): + self.emit("action-run-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) + + def control_vm_shutdown(self, src): + self.emit("action-shutdown-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) def control_vm_terminal(self, src): self.emit("action-show-terminal", self.vm.get_connection().get_uri(), self.vm.get_uuid()) diff -r 30260e2c3a37 src/virtManager/details.py --- a/src/virtManager/details.py Tue Nov 20 11:12:20 2007 -0500 +++ b/src/virtManager/details.py Wed Nov 21 12:19:57 2007 -0500 @@ -60,6 +60,14 @@ class vmmDetails(gobject.GObject): gobject.TYPE_NONE, (str,str)), "action-destroy-domain": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (str,str)), + "action-suspend-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-resume-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-run-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-shutdown-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), "action-show-help": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str]), } @@ -218,58 +226,22 @@ class vmmDetails(gobject.GObject): selection.select_path(0) self.window.get_widget("hw-panel").set_current_page(0) - def control_vm_run(self, src): - status = self.vm.status() - if status != libvirt.VIR_DOMAIN_SHUTOFF: - pass - else: - try: - self.vm.startup() - except: - (type, value, stacktrace) = sys.exc_info () - - # Detailed error message, in English so it can be Googled. - details = \ - "Unable to start virtual machine '%s'" % \ - (str(type) + " " + str(value) + "\n" + \ - traceback.format_exc (stacktrace)) - - dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, - str(value), - details) - dg.run() - dg.hide() - dg.destroy() - - - def control_vm_shutdown(self, src): - status = self.vm.status() - if not(status in [ libvirt.VIR_DOMAIN_SHUTDOWN, libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]): - self.vm.shutdown() - else: - logging.warning("Shutdown requested, but machine is already shutting down / shutoff") - def control_vm_pause(self, src): if self.ignorePause: return - status = self.vm.status() - if status in [ libvirt.VIR_DOMAIN_SHUTDOWN, libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]: - logging.warning("Pause/resume requested, but machine is shutdown / shutoff") - else: - if status in [ libvirt.VIR_DOMAIN_PAUSED ]: - if not src.get_active(): - self.vm.resume() - else: - logging.warning("Pause requested, but machine is already paused") - else: - if src.get_active(): - self.vm.suspend() - else: - logging.warning("Resume requested, but machine is already running") - - self.window.get_widget("control-pause").set_active(src.get_active()) - self.window.get_widget("details-menu-pause").set_active(src.get_active()) + if src.get_active(): + self.emit("action-suspend-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) + else: + self.emit("action-resume-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) + + self.update_widget_states(self.vm, self.vm.status()) + + def control_vm_run(self, src): + self.emit("action-run-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) + + def control_vm_shutdown(self, src): + self.emit("action-shutdown-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid()) def control_vm_terminal(self, src): self.emit("action-show-terminal", self.vm.get_connection().get_uri(), self.vm.get_uuid()) @@ -565,13 +537,8 @@ class vmmDetails(gobject.GObject): 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() + _err_dialog(_("Error Removing Disk: %s" % str(e)), + "".join(traceback.format_exc())) return xml = vbd.get_xml_config(diskinfo[3]) @@ -594,13 +561,8 @@ class vmmDetails(gobject.GObject): 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() + _err_dialog(_("Error Removing Network: %s" % str(e)), + "".join(traceback.format_exc())) return xml = vnic.get_xml_config() @@ -788,30 +750,20 @@ class vmmDetails(gobject.GObject): 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() + self._err_dialog(_("Error Removing CDROM: %s" % str(e)), + "".join(traceback.format_exc())) 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 + try: + self.choose_cd.connect("cdrom-chosen", self.connect_cdrom) + except Exception, e: + self._err_dialog(_("Error Connecting CDROM: %s" % str(e)), + "".join(traceback.format_exc())) + return else: self.choose_cd.set_target(self.window.get_widget("disk-target-device").get_text()) self.choose_cd.show() @@ -823,13 +775,14 @@ class vmmDetails(gobject.GObject): 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() - + self._err_dialog(_("Error Removing Device: %s" % str(e)), + "".join(traceback.format_exc())) + + def _err_dialog(self, summary, details): + dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, summary, details) + dg.run() + dg.hide() + dg.destroy() gobject.type_register(vmmDetails) diff -r 30260e2c3a37 src/virtManager/engine.py --- a/src/virtManager/engine.py Tue Nov 20 11:12:20 2007 -0500 +++ b/src/virtManager/engine.py Wed Nov 21 12:19:57 2007 -0500 @@ -37,6 +37,7 @@ from virtManager.create import vmmCreate from virtManager.create import vmmCreate from virtManager.serialcon import vmmSerialConsole from virtManager.host import vmmHost +from virtManager.error import vmmErrorDialog class vmmEngine(gobject.GObject): __gsignals__ = { @@ -57,6 +58,8 @@ class vmmEngine(gobject.GObject): self.timer = None self.last_timeout = 0 + + self._save_callback_info = [] self.config = config self.config.on_stats_update_interval_changed(self.reschedule_timer) @@ -186,6 +189,14 @@ class vmmEngine(gobject.GObject): self.save_domain(src, uri, uuid) def _do_destroy_domain(self, src, uri, uuid): self.destroy_domain(src, uri, uuid) + def _do_suspend_domain(self, src, uri, uuid): + self.suspend_domain(src, uri, uuid) + def _do_resume_domain(self, src, uri, uuid): + self.resume_domain(src, uri, uuid) + def _do_run_domain(self, src, uri, uuid): + self.run_domain(src, uri, uuid) + def _do_shutdown_domain(self, src, uri, uuid): + self.shutdown_domain(src, uri, uuid) def show_about(self): if self.windowAbout == None: @@ -231,6 +242,10 @@ class vmmEngine(gobject.GObject): console.connect("action-save-domain", self._do_save_domain) console.connect("action-destroy-domain", self._do_destroy_domain) console.connect("action-show-help", self._do_show_help) + console.connect("action-suspend-domain", self._do_suspend_domain) + console.connect("action-resume-domain", self._do_resume_domain) + console.connect("action-run-domain", self._do_run_domain) + console.connect("action-shutdown-domain", self._do_shutdown_domain) self.connections[uri]["windowConsole"][uuid] = console self.connections[uri]["windowConsole"][uuid].show() @@ -262,6 +277,10 @@ class vmmEngine(gobject.GObject): details.connect("action-save-domain", self._do_save_domain) details.connect("action-destroy-domain", self._do_destroy_domain) details.connect("action-show-help", self._do_show_help) + details.connect("action-suspend-domain", self._do_suspend_domain) + details.connect("action-resume-domain", self._do_resume_domain) + details.connect("action-run-domain", self._do_run_domain) + details.connect("action-shutdown-domain", self._do_shutdown_domain) self.connections[uri]["windowDetails"][uuid] = details self.connections[uri]["windowDetails"][uuid].show() return self.connections[uri]["windowDetails"][uuid] @@ -269,6 +288,10 @@ class vmmEngine(gobject.GObject): def get_manager(self): if self.windowManager == None: self.windowManager = vmmManager(self.get_config(), self) + self.windowManager.connect("action-suspend-domain", self._do_suspend_domain) + self.windowManager.connect("action-resume-domain", self._do_resume_domain) + self.windowManager.connect("action-run-domain", self._do_run_domain) + self.windowManager.connect("action-shutdown-domain", self._do_shutdown_domain) self.windowManager.connect("action-show-console", self._do_show_console) self.windowManager.connect("action-show-terminal", self._do_show_terminal) self.windowManager.connect("action-show-details", self._do_show_details) @@ -355,11 +378,22 @@ class vmmEngine(gobject.GObject): self.fcdialog.hide() if(response == gtk.RESPONSE_ACCEPT): file_to_save = self.fcdialog.get_filename() - progWin = vmmAsyncJob(self.config, vm.save, - [file_to_save], + progWin = vmmAsyncJob(self.config, self._save_callback, + [vm, file_to_save], _("Saving Virtual Machine")) progWin.run() self.fcdialog.destroy() + + if self._save_callback_info != []: + self._err_dialog(_("Error saving domain: %s" % self._save_callback_info[0]), self._save_callback_info[1]) + self._save_callback_info = [] + + def _save_callback(self, vm, file_to_save, ignore1=None): + try: + vm.save(file_to_save) + except Exception, e: + self._save_callback_info = [str(e), \ + "".join(traceback.format_exc())] def destroy_domain(self, src, uri, uuid): con = self.get_connection(uri, False) @@ -378,8 +412,78 @@ class vmmEngine(gobject.GObject): response_id = message_box.run() message_box.destroy() if response_id == gtk.RESPONSE_OK: - vm.destroy() - else: - return + try: + vm.destroy() + except Exception, e: + self._err_dialog(_("Error shutting down domain: %s" % str(e)), "".join(traceback.format_exc())) + + def suspend_domain(self, src, uri, uuid): + con = self.get_connection(uri, False) + vm = con.get_vm(uuid) + status = vm.status() + if status in [ libvirt.VIR_DOMAIN_SHUTDOWN, \ + libvirt.VIR_DOMAIN_SHUTOFF, \ + libvirt.VIR_DOMAIN_CRASHED ]: + logging.warning("Pause requested, but machine is shutdown / shutoff") + elif status in [ libvirt.VIR_DOMAIN_PAUSED ]: + logging.warning("Pause requested, but machine is already paused") + else: + try: + vm.suspend() + except Exception, e: + self._err_dialog(_("Error pausing domain: %s" % str(e)), + "".join(traceback.format_exc())) + + def resume_domain(self, src, uri, uuid): + con = self.get_connection(uri, False) + vm = con.get_vm(uuid) + status = vm.status() + if status in [ libvirt.VIR_DOMAIN_SHUTDOWN, \ + libvirt.VIR_DOMAIN_SHUTOFF, \ + libvirt.VIR_DOMAIN_CRASHED ]: + logging.warning("Resume requested, but machine is shutdown / shutoff") + elif status in [ libvirt.VIR_DOMAIN_PAUSED ]: + try: + vm.resume() + except Exception, e: + self._err_dialog(_("Error unpausing domain: %s" % str(e)), + "".join(traceback.format_exc())) + else: + logging.warning("Resume requested, but machine is already running") + + def run_domain(self, src, uri, uuid): + con = self.get_connection(uri, False) + vm = con.get_vm(uuid) + status = vm.status() + if status != libvirt.VIR_DOMAIN_SHUTOFF: + logging.warning("Run requested, but domain isn't shutoff.") + else: + try: + vm.startup() + except Exception, e: + self._err_dialog(_("Error starting domain: %s" % str(e)), + "".join(traceback.format_exc())) + + def shutdown_domain(self, src, uri, uuid): + con = self.get_connection(uri, False) + vm = con.get_vm(uuid) + status = vm.status() + if not(status in [ libvirt.VIR_DOMAIN_SHUTDOWN, \ + libvirt.VIR_DOMAIN_SHUTOFF, \ + libvirt.VIR_DOMAIN_CRASHED ]): + try: + vm.shutdown() + except Exception, e: + self._err_dialog(_("Error shutting down domain: %s" % str(e)), + "".join(traceback.format_exc())) + else: + logging.warning("Shutdown requested, but machine is already shutting down / shutoff") + + def _err_dialog(self, summary, details): + dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, summary, details) + dg.run() + dg.hide() + dg.destroy() gobject.type_register(vmmEngine) diff -r 30260e2c3a37 src/virtManager/manager.py --- a/src/virtManager/manager.py Tue Nov 20 11:12:20 2007 -0500 +++ b/src/virtManager/manager.py Wed Nov 21 12:19:57 2007 -0500 @@ -24,6 +24,7 @@ import threading import threading import logging import sys +import traceback import sparkline import libvirt @@ -81,6 +82,14 @@ class vmmManager(gobject.GObject): gobject.TYPE_NONE, []), "action-show-create": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str]), + "action-suspend-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-resume-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-run-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), + "action-shutdown-domain": (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, (str, str)), "action-connect": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str]), "action-show-help": (gobject.SIGNAL_RUN_FIRST, @@ -229,7 +238,7 @@ class vmmManager(gobject.GObject): # store any error message from the restore-domain callback self.domain_restore_error = "" - self.window.get_widget("menu_file_restore_saved").set_sensitive(False) + #self.window.get_widget("menu_file_restore_saved").set_sensitive(False) self.engine.connect("connection-added", self._add_connection) self.engine.connect("connection-removed", self._remove_connection) @@ -712,9 +721,12 @@ class vmmManager(gobject.GObject): if result == gtk.RESPONSE_NO: return conn = vm.get_connection() - vm.delete() + try: + vm.delete() + except Exception, e: + self._err_dialog(_("Error deleting domain: %s" % str(e)),\ + "".join(traceback.format_exc())) conn.tick(noStatsUpdate=True) - def show_about(self, src): self.emit("action-show-about") @@ -929,22 +941,22 @@ class vmmManager(gobject.GObject): def start_vm(self, ignore): vm = self.current_vm() if vm is not None: - vm.startup() + self.emit("action-run-domain", vm.get_connection().get_uri(), vm.get_uuid()) def stop_vm(self, ignore): vm = self.current_vm() if vm is not None: - vm.shutdown() + self.emit("action-shutdown-domain", vm.get_connection().get_uri(), vm.get_uuid()) def pause_vm(self, ignore): vm = self.current_vm() if vm is not None: - vm.suspend() + self.emit("action-suspend-domain", vm.get_connection().get_uri(), vm.get_uuid()) def resume_vm(self, ignore): vm = self.current_vm() if vm is not None: - vm.resume() + self.emit("action-resume-domain", vm.get_connection().get_uri(), vm.get_uuid()) def _add_connection(self, engine, conn): conn.connect("vm-added", self.vm_added) @@ -1001,5 +1013,11 @@ class vmmManager(gobject.GObject): dg.hide() dg.destroy() + def _err_dialog(self, summary, details): + dg = vmmErrorDialog(None, 0, gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, summary, details) + dg.run() + dg.hide() + dg.destroy() gobject.type_register(vmmManager)
_______________________________________________ et-mgmt-tools mailing list et-mgmt-tools@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/et-mgmt-tools