Browse Source

Implemented 'Restart' button
QubesOS/qubes-issues#1499

Ivan Konov 8 years ago
parent
commit
7cd1afbb3c
4 changed files with 81 additions and 21 deletions
  1. BIN
      icons/restartvm.png
  2. 17 0
      mainwindow.ui
  3. 63 21
      qubesmanager/main.py
  4. 1 0
      resources.qrc

BIN
icons/restartvm.png


+ 17 - 0
mainwindow.ui

@@ -320,6 +320,7 @@
     <addaction name="action_resumevm"/>
     <addaction name="action_pausevm"/>
     <addaction name="action_shutdownvm"/>
+    <addaction name="action_restartvm"/>
     <addaction name="action_killvm"/>
     <addaction name="separator"/>
     <addaction name="action_settings"/>
@@ -369,6 +370,7 @@
    <addaction name="action_resumevm"/>
    <addaction name="action_pausevm"/>
    <addaction name="action_shutdownvm"/>
+   <addaction name="action_restartvm"/>
    <addaction name="separator"/>
    <addaction name="action_settings"/>
    <addaction name="action_editfwrules"/>
@@ -455,6 +457,21 @@
     <string>Shutdown selected VM</string>
    </property>
   </action>
+  <action name="action_restartvm">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/restartvm.png</normaloff>:/restartvm.png</iconset>
+   </property>
+   <property name="text">
+    <string>Restart VM</string>
+   </property>
+   <property name="toolTip">
+    <string>Restart selected VM</string>
+   </property>
+  </action>
   <action name="action_appmenus">
    <property name="enabled">
     <bool>false</bool>

+ 63 - 21
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 <b>'{0}'</b> hasn't shutdown within the last {1} seconds, "
-            "do you want to kill it?<br>".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 <b>'{0}'</b> hasn't shutdown within the last {1} seconds, "
+		    "do you want to kill it?<br>".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 <b>'{0}'</b>?<br>"
+            "<small>This will shutdown all the running applications "
+            "within this VM.</small>".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()

+ 1 - 0
resources.qrc

@@ -48,5 +48,6 @@
     <file alias="pausevm.png">icons/pausevm.png</file>
     <file alias="showcpuload.png">icons/showcpuload.png</file>
     <file alias="mic.png">icons/mic.png</file>
+    <file alias="restartvm.png">icons/restartvm.png</file>
   </qresource>
 </RCC>