From 7cd1afbb3c5596d1f3aac220ef68e5e50c41fb24 Mon Sep 17 00:00:00 2001 From: Ivan Konov Date: Sun, 5 Jun 2016 22:19:18 +0300 Subject: [PATCH] Implemented 'Restart' button QubesOS/qubes-issues#1499 --- icons/restartvm.png | Bin 0 -> 2135 bytes mainwindow.ui | 17 +++++++++ qubesmanager/main.py | 84 ++++++++++++++++++++++++++++++++----------- resources.qrc | 1 + 4 files changed, 81 insertions(+), 21 deletions(-) create mode 100644 icons/restartvm.png diff --git a/icons/restartvm.png b/icons/restartvm.png new file mode 100644 index 0000000000000000000000000000000000000000..2a84e90c561f85d3576074a7a3c4bd6a6ac00bbc GIT binary patch literal 2135 zcmV-d2&ngoP)Lugn?D1iP~EzmDXLgXjQ|grlw57N?7>xOYaEq ziIeeM94+L!wsalx%f^iwHPZJ}snnC}%B_3J_cV=bYDk4nIQ5yQ-WK5FANIMZC%0|G zK}SrPu*axOs5VqYDJu2s=-Bap{>`FEV;VAnk9_v?HwF0PBk`+ow5MxR$3uS6q`fAk zQu-N#Sm#u)2HDc_4Ofhs(3Aec=P9wcI8fq+yT@2KOPV6z<98IyS9%T3WBd z%i+O4FCeV|9{gRuSITYM@*7&_-7c#WFqJB;TDLKHJH}--aP>`%nD#9}DiIFEQFjNJ8ssrq%Ol;SI4>+ecA2CWRkYK{&JHH z%G2fwJGQ*nJ@(h;Q>mU+Z@8>&RX&svZEY=&nKe~s7*Xi~-?t^i)YFwaV!~~M z#9Z}7-<5-=8FLoQVAVw{b;!E@%NIRiT2#tp#ysqsx>AJW{yzKISUgrLbj_JCRR<^N zdBd`X|I;Gs)CMvY%D7uiQ|Rbj-NMXa*%eb zE~|KCzmK}Zw2^v~n_8yKd(Gc!E3LU?*8U-gL%w1}!gzQjDUU{_Lhg{n&VWt|t9pWl zId^Co9m=6##GHd#GUVFYdNoTVn(mh?s*ZIuDGyYAf5N0pPe(cEIxyq7eK(X=<}K!l5=>k0hIUP)2D4L>ej0k{luI26mAlxP}lU@uJL^f*ZaRMWpTM0zNu6UK}20^ zL;h83$?9rW=l_Zv4b!qA^M#E*IW1>#soJ#buGv$ItEiM(^>Q^I%XlJn)vxFp8HmKF9BgoqI^;v{){tAZ;*u3VR0?JsH&yGULaFOJQVHUg z=d;gkpM1{oAhYPYaXmemL?RB7G2(VdjcW^ayIzymVVl*GDQfcUx#kDPs_c92^V=CN z$KydN_=@-I%Id~d4x&$V%|#6Xxi#H-(;E)?O?$FaE>VmOKWs7H?*&OOmA4 + @@ -369,6 +370,7 @@ + @@ -455,6 +457,21 @@ Shutdown selected VM + + + false + + + + :/restartvm.png:/restartvm.png + + + Restart VM + + + Restart selected VM + + false diff --git a/qubesmanager/main.py b/qubesmanager/main.py index 3159e98..fb4e0ad 100755 --- a/qubesmanager/main.py +++ b/qubesmanager/main.py @@ -240,36 +240,48 @@ class VmRowInTable(object): vm_shutdown_timeout = 20000 # in msec +vm_restart_check_timeout= 1000 # in msec class VmShutdownMonitor(QObject): - def __init__(self, vm, shutdown_time=vm_shutdown_timeout): + def __init__(self, vm, shutdown_time=vm_shutdown_timeout, check_time=vm_restart_check_timeout, and_restart=False, caller=None): QObject.__init__(self) self.vm = vm self.shutdown_time = shutdown_time + self.check_time = check_time + self.and_restart = and_restart + self.shutdown_started = datetime.now() + self.caller = caller def check_if_vm_has_shutdown(self): vm = self.vm vm_start_time = vm.get_start_time() - if not vm.is_running() or ( - vm_start_time and vm_start_time >= datetime.now() - - timedelta(0, self.shutdown_time / 1000)): - return - - reply = QMessageBox.question( - None, "VM Shutdown", - "The VM '{0}' hasn't shutdown within the last {1} seconds, " - "do you want to kill it?
".format( - vm.name, self.shutdown_time / 1000), - "Kill it!", - "Wait another {0} seconds...".format( - self.shutdown_time / 1000)) - if reply == 0: - vm.force_shutdown() + if vm.is_running() and vm_start_time and vm_start_time < self.shutdown_started: + if (datetime.now()-self.shutdown_started) > timedelta(milliseconds=self.shutdown_time): + reply = QMessageBox.question( + None, "VM Shutdown", + "The VM '{0}' hasn't shutdown within the last {1} seconds, " + "do you want to kill it?
".format( + vm.name, self.shutdown_time / 1000), + "Kill it!", + "Wait another {0} seconds...".format( + self.shutdown_time / 1000)) + if reply == 0: + vm.force_shutdown() + if self.and_restart: + if self.caller: + self.caller.start_vm(vm) + else: + # noinspection PyTypeChecker,PyCallByClass + self.shutdown_started=datetime.now() + QTimer.singleShot(self.check_time, self.check_if_vm_has_shutdown) + else: + QTimer.singleShot(self.check_time, self.check_if_vm_has_shutdown) else: - # noinspection PyTypeChecker,PyCallByClass - QTimer.singleShot(self.shutdown_time, self.check_if_vm_has_shutdown) + if self.and_restart: + if self.caller: + self.caller.start_vm(vm) class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): row_height = 30 @@ -408,6 +420,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): self.context_menu.addAction(self.action_startvm_tools_install) self.context_menu.addAction(self.action_pausevm) self.context_menu.addAction(self.action_shutdownvm) + self.context_menu.addAction(self.action_restartvm) self.context_menu.addAction(self.action_killvm) self.context_menu.addSeparator() @@ -879,6 +892,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): vm.last_running and vm.last_power_state != "Paused" and vm.qid != 0) + self.action_restartvm.setEnabled( + vm.last_running and + vm.last_power_state != "Paused" and + vm.qid != 0) self.action_killvm.setEnabled((vm.last_running or vm.last_power_state == "Paused") and vm.qid != 0) @@ -905,6 +922,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): self.action_resumevm.setEnabled(False) self.action_pausevm.setEnabled(False) self.action_shutdownvm.setEnabled(False) + self.action_restartvm.setEnabled(False) self.action_killvm.setEnabled(False) self.action_appmenus.setEnabled(False) self.action_editfwrules.setEnabled(False) @@ -1129,6 +1147,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): "ERROR: {0}".format(ex)) return + + self.start_vm(vm) + + def start_vm(self, vm): assert not vm.is_running() thread_monitor = ThreadMonitor() thread = threading.Thread(target=self.do_start_vm, @@ -1238,7 +1260,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): if reply == QMessageBox.Yes: self.shutdown_vm(vm) - def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout): + def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout, check_time=vm_restart_check_timeout, and_restart=False): try: vm.shutdown() except Exception as ex: @@ -1249,11 +1271,31 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): trayIcon.showMessage("VM '{0}' is shutting down...".format(vm.name), msecs=3000) - self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, shutdown_time) + self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, shutdown_time, check_time, and_restart, self) # noinspection PyCallByClass,PyTypeChecker - QTimer.singleShot(shutdown_time, self.shutdown_monitor[ + QTimer.singleShot(check_time, self.shutdown_monitor[ vm.qid].check_if_vm_has_shutdown) + + @pyqtSlot(name='on_action_restartvm_triggered') + def action_restartvm_triggered(self): + vm = self.get_selected_vm() + assert vm.is_running() + + self.blk_manager.check_if_serves_as_backend(vm) + + reply = QMessageBox.question( + None, "VM Restart Confirmation", + "Are you sure you want to restart the VM '{0}'?
" + "This will shutdown all the running applications " + "within this VM.".format(vm.name), + QMessageBox.Yes | QMessageBox.Cancel) + + app.processEvents() + + if reply == QMessageBox.Yes: + self.shutdown_vm(vm, and_restart=True) + @pyqtSlot(name='on_action_killvm_triggered') def action_killvm_triggered(self): vm = self.get_selected_vm() diff --git a/resources.qrc b/resources.qrc index c9f9172..c499d27 100644 --- a/resources.qrc +++ b/resources.qrc @@ -48,5 +48,6 @@ icons/pausevm.png icons/showcpuload.png icons/mic.png + icons/restartvm.png