Merge remote-tracking branch 'origin/pr/281'

* origin/pr/281:
  Tests suite fixes
  Use internal vm.shutdown_timeout
  Fix pylint warning
  Show all non halted vm's as running
  use force=True when restarting a netvm with connected vms
  Join all connected VM's in same warning
  Rewrite without cascade var
  Don't wait!
  First initiate shutdown for all vm's, then wait
  Fix wrong identation (thanks pylint)
  Avoid infite loop while waiting vm to shutdown
  Fix pylint warnings
  Cascade shutdown
This commit is contained in:
Marek Marczykowski-Górecki 2021-05-30 00:56:11 +02:00
commit aaf99091ef
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 53 additions and 26 deletions

View File

@ -493,17 +493,15 @@ class QubesTableModel(QAbstractTableModel):
return def_flags | Qt.ItemIsUserCheckable
return def_flags
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,
check_time=vm_restart_check_timeout,
def __init__(self, vm, check_time=vm_restart_check_timeout,
and_restart=False, caller=None):
QObject.__init__(self)
self.vm = vm
self.shutdown_time = shutdown_time
self.shutdown_timeout = vm.shutdown_timeout
self.check_time = check_time
self.and_restart = and_restart
self.shutdown_started = datetime.now()
@ -519,7 +517,7 @@ class VmShutdownMonitor(QObject):
def timeout_reached(self):
actual = datetime.now() - self.shutdown_started
allowed = timedelta(milliseconds=self.shutdown_time)
allowed = timedelta(seconds=self.shutdown_timeout)
return actual > allowed
@ -541,12 +539,12 @@ class VmShutdownMonitor(QObject):
msgbox.setText(self.tr(
"The Qube <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))
vm.name, self.shutdown_timeout))
kill_button = msgbox.addButton(
self.tr("Kill it!"), QMessageBox.YesRole)
wait_button = msgbox.addButton(
self.tr("Wait another {0} seconds...").format(
self.shutdown_time / 1000),
self.shutdown_timeout),
QMessageBox.NoRole)
ignore_button = msgbox.addButton(self.tr("Don't ask again"),
QMessageBox.RejectRole)
@ -668,7 +666,7 @@ class QubesProxyModel(QSortFilterProxyModel):
vm = self.sourceModel().data(index, Qt.UserRole)
if self.window.show_running.isChecked() and \
vm.state['power'] == 'Running':
vm.state['power'] != 'Halted':
return super().filterAcceptsRow(sourceRow, sourceParent)
if self.window.show_halted.isChecked() and \
vm.state['power'] == 'Halted':
@ -1407,24 +1405,52 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
if reply == QMessageBox.Yes:
self.shutdown_vm(vm)
def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout,
check_time=vm_restart_check_timeout, and_restart=False):
def get_connected_vms(self, vm, connected_vms):
for connected_vm in vm.connected_vms:
if connected_vm.is_running():
connected_vms.append(connected_vm)
self.get_connected_vms(connected_vm, connected_vms)
def shutdown_vm(self, vm, force=False, check_time=vm_restart_check_timeout,
and_restart=False):
try:
vm.shutdown()
connected_vms = []
if not and_restart:
self.get_connected_vms(vm, connected_vms)
if len(connected_vms) > 0:
reply = QMessageBox.question(
self, self.tr("Qube Shutdown Confirmation"),
self.tr("There are some qubes connected to <b>'{0}'</b>!"
"<br><small>Do you want to shutdown: </small>"
"<b>'{1}'</b>?").format(vm.name,
", ".join([x.name for x in connected_vms])),
QMessageBox.Yes | QMessageBox.Cancel)
if reply != QMessageBox.Yes:
return False
force = True
for connected_vm in connected_vms:
connected_vm.shutdown(force=force)
vm.shutdown(force=force)
except exc.QubesException as ex:
QMessageBox.warning(
self,
self.tr("Error shutting down Qube!"),
self.tr("ERROR: {0}").format(ex))
return
return False
self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, shutdown_time,
check_time,
self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, check_time,
and_restart, self)
# noinspection PyCallByClass,PyTypeChecker
QTimer.singleShot(check_time, self.shutdown_monitor[
vm.qid].check_if_vm_has_shutdown)
return True
# noinspection PyArgumentList
@pyqtSlot(name='on_action_restartvm_triggered')
def action_restartvm_triggered(self):
@ -1441,7 +1467,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
# in case the user shut down the VM in the meantime
try:
if manager_utils.is_running(vm, False):
self.shutdown_vm(vm, and_restart=True)
self.shutdown_vm(vm, force=True, and_restart=True)
else:
self.start_vm(vm)
except exc.QubesException as ex:

View File

@ -457,11 +457,10 @@ class QubeManagerTest(unittest.TestCase):
with unittest.mock.patch.object(selected_vm, 'shutdown')\
as mock_shutdown:
self.dialog.action_shutdownvm.trigger()
mock_shutdown.assert_called_once_with()
mock_shutdown.assert_called_once_with(force=False)
mock_monitor.assert_called_once_with(
selected_vm,
unittest.mock.ANY, unittest.mock.ANY,
unittest.mock.ANY, unittest.mock.ANY)
selected_vm, unittest.mock.ANY, unittest.mock.ANY,
unittest.mock.ANY)
mock_timer.assert_called_once_with(unittest.mock.ANY,
unittest.mock.ANY)
@ -546,10 +545,9 @@ class QubeManagerTest(unittest.TestCase):
with unittest.mock.patch.object(selected_vm, 'shutdown')\
as mock_shutdown:
action.trigger()
mock_shutdown.assert_called_once_with()
mock_shutdown.assert_called_once_with(force=True)
mock_monitor.assert_called_once_with(
selected_vm, unittest.mock.ANY,
unittest.mock.ANY, True, unittest.mock.ANY)
selected_vm, 1000, True, unittest.mock.ANY)
@unittest.mock.patch('qubesmanager.qube_manager.StartVMThread')
@unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question",
@ -1484,7 +1482,7 @@ class QubeManagerTest(unittest.TestCase):
for row in range(self.dialog.table.model().rowCount()):
template = self._get_table_item(row, "Template")
vm = self._get_table_vm(row)
if template != 'AdminVM' and \
if template != 'AdminVM' and not vm.provides_network and \
(running is None
or (running and vm.is_running())
or (not running and not vm.is_running())):
@ -1691,8 +1689,9 @@ class VMShutdownMonitorTest(unittest.TestCase):
mock_vm = unittest.mock.Mock()
mock_vm.is_running.return_value = True
mock_vm.start_time = datetime.datetime.now().timestamp() - 3000
mock_vm.shutdown_timeout = 60
monitor = qube_manager.VmShutdownMonitor(mock_vm, shutdown_time=1)
monitor = qube_manager.VmShutdownMonitor(mock_vm)
time.sleep(3)
monitor.check_if_vm_has_shutdown()
@ -1708,8 +1707,9 @@ class VMShutdownMonitorTest(unittest.TestCase):
mock_vm = unittest.mock.Mock()
mock_vm.is_running.return_value = True
mock_vm.start_time = datetime.datetime.now().timestamp() - 3000
mock_vm.shutdown_timeout = 1
monitor = qube_manager.VmShutdownMonitor(mock_vm, shutdown_time=1)
monitor = qube_manager.VmShutdownMonitor(mock_vm)
time.sleep(3)
monitor.restart_vm_if_needed = unittest.mock.Mock()
@ -1725,8 +1725,9 @@ class VMShutdownMonitorTest(unittest.TestCase):
mock_vm = unittest.mock.Mock()
mock_vm.is_running.return_value = True
mock_vm.start_time = datetime.datetime.now().timestamp() - 3000
mock_vm.shutdown_timeout = 30
monitor = qube_manager.VmShutdownMonitor(mock_vm, shutdown_time=3000)
monitor = qube_manager.VmShutdownMonitor(mock_vm)
time.sleep(1)
monitor.check_if_vm_has_shutdown()