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:
commit
aaf99091ef
@ -493,17 +493,15 @@ class QubesTableModel(QAbstractTableModel):
|
|||||||
return def_flags | Qt.ItemIsUserCheckable
|
return def_flags | Qt.ItemIsUserCheckable
|
||||||
return def_flags
|
return def_flags
|
||||||
|
|
||||||
vm_shutdown_timeout = 20000 # in msec
|
|
||||||
vm_restart_check_timeout = 1000 # in msec
|
vm_restart_check_timeout = 1000 # in msec
|
||||||
|
|
||||||
|
|
||||||
class VmShutdownMonitor(QObject):
|
class VmShutdownMonitor(QObject):
|
||||||
def __init__(self, vm, shutdown_time=vm_shutdown_timeout,
|
def __init__(self, vm, check_time=vm_restart_check_timeout,
|
||||||
check_time=vm_restart_check_timeout,
|
|
||||||
and_restart=False, caller=None):
|
and_restart=False, caller=None):
|
||||||
QObject.__init__(self)
|
QObject.__init__(self)
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
self.shutdown_time = shutdown_time
|
self.shutdown_timeout = vm.shutdown_timeout
|
||||||
self.check_time = check_time
|
self.check_time = check_time
|
||||||
self.and_restart = and_restart
|
self.and_restart = and_restart
|
||||||
self.shutdown_started = datetime.now()
|
self.shutdown_started = datetime.now()
|
||||||
@ -519,7 +517,7 @@ class VmShutdownMonitor(QObject):
|
|||||||
|
|
||||||
def timeout_reached(self):
|
def timeout_reached(self):
|
||||||
actual = datetime.now() - self.shutdown_started
|
actual = datetime.now() - self.shutdown_started
|
||||||
allowed = timedelta(milliseconds=self.shutdown_time)
|
allowed = timedelta(seconds=self.shutdown_timeout)
|
||||||
|
|
||||||
return actual > allowed
|
return actual > allowed
|
||||||
|
|
||||||
@ -541,12 +539,12 @@ class VmShutdownMonitor(QObject):
|
|||||||
msgbox.setText(self.tr(
|
msgbox.setText(self.tr(
|
||||||
"The Qube <b>'{0}'</b> hasn't shutdown within the last "
|
"The Qube <b>'{0}'</b> hasn't shutdown within the last "
|
||||||
"{1} seconds, do you want to kill it?<br>").format(
|
"{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(
|
kill_button = msgbox.addButton(
|
||||||
self.tr("Kill it!"), QMessageBox.YesRole)
|
self.tr("Kill it!"), QMessageBox.YesRole)
|
||||||
wait_button = msgbox.addButton(
|
wait_button = msgbox.addButton(
|
||||||
self.tr("Wait another {0} seconds...").format(
|
self.tr("Wait another {0} seconds...").format(
|
||||||
self.shutdown_time / 1000),
|
self.shutdown_timeout),
|
||||||
QMessageBox.NoRole)
|
QMessageBox.NoRole)
|
||||||
ignore_button = msgbox.addButton(self.tr("Don't ask again"),
|
ignore_button = msgbox.addButton(self.tr("Don't ask again"),
|
||||||
QMessageBox.RejectRole)
|
QMessageBox.RejectRole)
|
||||||
@ -668,7 +666,7 @@ class QubesProxyModel(QSortFilterProxyModel):
|
|||||||
vm = self.sourceModel().data(index, Qt.UserRole)
|
vm = self.sourceModel().data(index, Qt.UserRole)
|
||||||
|
|
||||||
if self.window.show_running.isChecked() and \
|
if self.window.show_running.isChecked() and \
|
||||||
vm.state['power'] == 'Running':
|
vm.state['power'] != 'Halted':
|
||||||
return super().filterAcceptsRow(sourceRow, sourceParent)
|
return super().filterAcceptsRow(sourceRow, sourceParent)
|
||||||
if self.window.show_halted.isChecked() and \
|
if self.window.show_halted.isChecked() and \
|
||||||
vm.state['power'] == 'Halted':
|
vm.state['power'] == 'Halted':
|
||||||
@ -1407,24 +1405,52 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
|||||||
if reply == QMessageBox.Yes:
|
if reply == QMessageBox.Yes:
|
||||||
self.shutdown_vm(vm)
|
self.shutdown_vm(vm)
|
||||||
|
|
||||||
def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout,
|
def get_connected_vms(self, vm, connected_vms):
|
||||||
check_time=vm_restart_check_timeout, and_restart=False):
|
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:
|
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:
|
except exc.QubesException as ex:
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
self.tr("Error shutting down Qube!"),
|
self.tr("Error shutting down Qube!"),
|
||||||
self.tr("ERROR: {0}").format(ex))
|
self.tr("ERROR: {0}").format(ex))
|
||||||
return
|
return False
|
||||||
|
|
||||||
self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, shutdown_time,
|
self.shutdown_monitor[vm.qid] = VmShutdownMonitor(vm, check_time,
|
||||||
check_time,
|
|
||||||
and_restart, self)
|
and_restart, self)
|
||||||
# noinspection PyCallByClass,PyTypeChecker
|
# noinspection PyCallByClass,PyTypeChecker
|
||||||
QTimer.singleShot(check_time, self.shutdown_monitor[
|
QTimer.singleShot(check_time, self.shutdown_monitor[
|
||||||
vm.qid].check_if_vm_has_shutdown)
|
vm.qid].check_if_vm_has_shutdown)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
# noinspection PyArgumentList
|
# noinspection PyArgumentList
|
||||||
@pyqtSlot(name='on_action_restartvm_triggered')
|
@pyqtSlot(name='on_action_restartvm_triggered')
|
||||||
def action_restartvm_triggered(self):
|
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
|
# in case the user shut down the VM in the meantime
|
||||||
try:
|
try:
|
||||||
if manager_utils.is_running(vm, False):
|
if manager_utils.is_running(vm, False):
|
||||||
self.shutdown_vm(vm, and_restart=True)
|
self.shutdown_vm(vm, force=True, and_restart=True)
|
||||||
else:
|
else:
|
||||||
self.start_vm(vm)
|
self.start_vm(vm)
|
||||||
except exc.QubesException as ex:
|
except exc.QubesException as ex:
|
||||||
|
@ -457,11 +457,10 @@ class QubeManagerTest(unittest.TestCase):
|
|||||||
with unittest.mock.patch.object(selected_vm, 'shutdown')\
|
with unittest.mock.patch.object(selected_vm, 'shutdown')\
|
||||||
as mock_shutdown:
|
as mock_shutdown:
|
||||||
self.dialog.action_shutdownvm.trigger()
|
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(
|
mock_monitor.assert_called_once_with(
|
||||||
selected_vm,
|
selected_vm, unittest.mock.ANY, unittest.mock.ANY,
|
||||||
unittest.mock.ANY, unittest.mock.ANY,
|
unittest.mock.ANY)
|
||||||
unittest.mock.ANY, unittest.mock.ANY)
|
|
||||||
mock_timer.assert_called_once_with(unittest.mock.ANY,
|
mock_timer.assert_called_once_with(unittest.mock.ANY,
|
||||||
unittest.mock.ANY)
|
unittest.mock.ANY)
|
||||||
|
|
||||||
@ -546,10 +545,9 @@ class QubeManagerTest(unittest.TestCase):
|
|||||||
with unittest.mock.patch.object(selected_vm, 'shutdown')\
|
with unittest.mock.patch.object(selected_vm, 'shutdown')\
|
||||||
as mock_shutdown:
|
as mock_shutdown:
|
||||||
action.trigger()
|
action.trigger()
|
||||||
mock_shutdown.assert_called_once_with()
|
mock_shutdown.assert_called_once_with(force=True)
|
||||||
mock_monitor.assert_called_once_with(
|
mock_monitor.assert_called_once_with(
|
||||||
selected_vm, unittest.mock.ANY,
|
selected_vm, 1000, True, unittest.mock.ANY)
|
||||||
unittest.mock.ANY, True, unittest.mock.ANY)
|
|
||||||
|
|
||||||
@unittest.mock.patch('qubesmanager.qube_manager.StartVMThread')
|
@unittest.mock.patch('qubesmanager.qube_manager.StartVMThread')
|
||||||
@unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question",
|
@unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question",
|
||||||
@ -1484,7 +1482,7 @@ class QubeManagerTest(unittest.TestCase):
|
|||||||
for row in range(self.dialog.table.model().rowCount()):
|
for row in range(self.dialog.table.model().rowCount()):
|
||||||
template = self._get_table_item(row, "Template")
|
template = self._get_table_item(row, "Template")
|
||||||
vm = self._get_table_vm(row)
|
vm = self._get_table_vm(row)
|
||||||
if template != 'AdminVM' and \
|
if template != 'AdminVM' and not vm.provides_network and \
|
||||||
(running is None
|
(running is None
|
||||||
or (running and vm.is_running())
|
or (running and vm.is_running())
|
||||||
or (not running and not 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 = unittest.mock.Mock()
|
||||||
mock_vm.is_running.return_value = True
|
mock_vm.is_running.return_value = True
|
||||||
mock_vm.start_time = datetime.datetime.now().timestamp() - 3000
|
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)
|
time.sleep(3)
|
||||||
|
|
||||||
monitor.check_if_vm_has_shutdown()
|
monitor.check_if_vm_has_shutdown()
|
||||||
@ -1708,8 +1707,9 @@ class VMShutdownMonitorTest(unittest.TestCase):
|
|||||||
mock_vm = unittest.mock.Mock()
|
mock_vm = unittest.mock.Mock()
|
||||||
mock_vm.is_running.return_value = True
|
mock_vm.is_running.return_value = True
|
||||||
mock_vm.start_time = datetime.datetime.now().timestamp() - 3000
|
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)
|
time.sleep(3)
|
||||||
monitor.restart_vm_if_needed = unittest.mock.Mock()
|
monitor.restart_vm_if_needed = unittest.mock.Mock()
|
||||||
|
|
||||||
@ -1725,8 +1725,9 @@ class VMShutdownMonitorTest(unittest.TestCase):
|
|||||||
mock_vm = unittest.mock.Mock()
|
mock_vm = unittest.mock.Mock()
|
||||||
mock_vm.is_running.return_value = True
|
mock_vm.is_running.return_value = True
|
||||||
mock_vm.start_time = datetime.datetime.now().timestamp() - 3000
|
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)
|
time.sleep(1)
|
||||||
|
|
||||||
monitor.check_if_vm_has_shutdown()
|
monitor.check_if_vm_has_shutdown()
|
||||||
|
Loading…
Reference in New Issue
Block a user