From b9316bcd624d547862882741935ae378f11ce98b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Thu, 11 Apr 2019 22:58:49 +0200 Subject: [PATCH 1/6] Fixed bug in Global Settings Incorrect handling of Check dom0 updates being set to false. fixes QubesOS/qubes-issues#4988 --- qubesmanager/global_settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qubesmanager/global_settings.py b/qubesmanager/global_settings.py index 5482516a..6170a0a8 100644 --- a/qubesmanager/global_settings.py +++ b/qubesmanager/global_settings.py @@ -239,8 +239,8 @@ def __init_updates__(self): self.dom0_updates_file_path = '/var/lib/qubes/updates/disable-updates' try: - self.updates_dom0_val = self.qvm_collection.domains[ - 'dom0'].features['service.qubes-update-check'] + self.updates_dom0_val = bool(self.qvm_collection.domains[ + 'dom0'].features['service.qubes-update-check']) except KeyError: self.updates_dom0_val =\ not os.path.isfile(self.dom0_updates_file_path) From 733f00ddf2e86158292837c5dfcb93043fd5da8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Fri, 12 Apr 2019 00:30:12 +0200 Subject: [PATCH 2/6] Fixed unnecessary property set in Global Settings --- qubesmanager/global_settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qubesmanager/global_settings.py b/qubesmanager/global_settings.py index 6170a0a8..fdcee8a0 100644 --- a/qubesmanager/global_settings.py +++ b/qubesmanager/global_settings.py @@ -284,7 +284,8 @@ def __apply_updates__(self): 'service.qubes-update-check'] = \ self.updates_dom0.isChecked() - self.qvm_collection.check_updates_vm = self.updates_vm.isChecked() + if self.qvm_collection.check_updates_vm != self.updates_vm.isChecked(): + self.qvm_collection.check_updates_vm = self.updates_vm.isChecked() def reject(self): self.done(0) From ddb70fe8ead445a9af165c82f638587645ceb375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Tue, 30 Apr 2019 16:12:27 +0200 Subject: [PATCH 3/6] Added additional check for cloning a VM An attempt to clone a VM to a name that is already in use will fail more gracefully and with an explicit warning message. --- qubesmanager/qube_manager.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/qubesmanager/qube_manager.py b/qubesmanager/qube_manager.py index 000133d0..9ca7802d 100644 --- a/qubesmanager/qube_manager.py +++ b/qubesmanager/qube_manager.py @@ -504,7 +504,7 @@ def __init__(self, qt_app, qubes_app, dispatcher, parent=None): # Check Updates Timer timer = QtCore.QTimer(self) timer.timeout.connect(self.check_updates) - timer.start(1000 * 30) # 30s + timer.start(1000 * 30) # 30s self.check_updates() def keyPressEvent(self, event): # pylint: disable=invalid-name @@ -852,6 +852,15 @@ def action_clonevm_triggered(self): if not ok or clone_name == "": return + name_in_use = clone_name in self.qubes_app.domains + + if name_in_use: + QtGui.QMessageBox.warning( + None, self.tr("Name already in use!"), + self.tr("There already exists a qube called '{}'. " + "Cloning aborted.").format(clone_name)) + return + self.progress = QtGui.QProgressDialog( self.tr( "Cloning Qube..."), "", 0, 0) From 0bb92311bafb519af71584f275d16d51a384267a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Tue, 30 Apr 2019 16:24:30 +0200 Subject: [PATCH 4/6] Fixed bug with hiding last visible column Removed old buggy code, replaced it with disabling hiding the 'name' column (because manager is useless without VM name). --- qubesmanager/qube_manager.py | 31 ++++++++----------------------- ui/qubemanager.ui | 1 - 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/qubesmanager/qube_manager.py b/qubesmanager/qube_manager.py index 9ca7802d..a824b67f 100644 --- a/qubesmanager/qube_manager.py +++ b/qubesmanager/qube_manager.py @@ -604,15 +604,16 @@ def on_domain_changed(self, vm, event, **_kwargs): return # the VM was deleted before its status could be updated def load_manager_settings(self): - # visible columns - self.visible_columns_count = 0 for col in self.columns_indices: col_no = self.columns_indices[col] - visible = self.manager_settings.value( - 'columns/%s' % col, - defaultValue="true") - self.columns_actions[col_no].setChecked(visible == "true") - self.visible_columns_count += 1 + if col == 'Name': + # 'Name' column should be always visible + self.columns_actions[col_no].setChecked(True) + else: + visible = self.manager_settings.value( + 'columns/%s' % col, + defaultValue="true") + self.columns_actions[col_no].setChecked(visible == "true") self.sort_by_column = str( self.manager_settings.value("view/sort_column", @@ -1161,22 +1162,6 @@ def showhide_toolbar(self, checked): def showhide_column(self, col_num, show): self.table.setColumnHidden(col_num, not show) - val = 1 if show else -1 - self.visible_columns_count += val - - if self.visible_columns_count == 1: - # disable hiding the last one - for col in self.columns_actions: - if self.columns_actions[col].isChecked(): - self.columns_actions[col].setEnabled(False) - break - elif self.visible_columns_count == 2 and val == 1: - # enable hiding previously disabled column - for col in self.columns_actions: - if not self.columns_actions[col].isEnabled(): - self.columns_actions[col].setEnabled(True) - break - if self.settings_loaded: col_name = [name for name in self.columns_indices if self.columns_indices[name] == col_num][0] diff --git a/ui/qubemanager.ui b/ui/qubemanager.ui index e234aac3..3fbcea18 100644 --- a/ui/qubemanager.ui +++ b/ui/qubemanager.ui @@ -281,7 +281,6 @@ DisposableVMs - From f5586e770b6b4c8e12e2f0dfefff0eda0341f737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Tue, 30 Apr 2019 16:29:50 +0200 Subject: [PATCH 5/6] Protected loading manager settings from malformed config files Malformed config files will no longer prevent Qube Manager from starting. --- qubesmanager/qube_manager.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/qubesmanager/qube_manager.py b/qubesmanager/qube_manager.py index a824b67f..2d158388 100644 --- a/qubesmanager/qube_manager.py +++ b/qubesmanager/qube_manager.py @@ -466,7 +466,17 @@ def __init__(self, qt_app, qubes_app, dispatcher, parent=None): self.connect(self.action_toolbar, QtCore.SIGNAL("toggled(bool)"), self.showhide_toolbar) - self.load_manager_settings() + try: + self.load_manager_settings() + except Exception as ex: # pylint: disable=broad-except + QtGui.QMessageBox.warning( + None, + self.tr("Manager settings unreadable"), + self.tr("Qube Manager settings cannot be parsed. Previously " + "saved display settings may not be restored " + "correctly.\nError: {}".format(str(ex)))) + + self.settings_loaded = True self.fill_table() @@ -642,8 +652,6 @@ def load_manager_settings(self): self.resize(self.manager_settings.value("window_size", QtCore.QSize(1100, 600))) - self.settings_loaded = True - def get_vms_list(self): return [vm for vm in self.qubes_app.domains] @@ -1329,7 +1337,7 @@ def main(): asyncio.ensure_future(dispatcher.listen_for_events())) except asyncio.CancelledError: pass - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except loop_shutdown() exc_type, exc_value, exc_traceback = sys.exc_info()[:3] handle_exception(exc_type, exc_value, exc_traceback) From cb70b9bd65be53bc242fec1924976f2e9a882b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Tue, 30 Apr 2019 16:35:54 +0200 Subject: [PATCH 6/6] Fixed logs display in Qube Manager Logs menu was not updated correctly on all occassions. --- qubesmanager/qube_manager.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/qubesmanager/qube_manager.py b/qubesmanager/qube_manager.py index 2d158388..015bac8f 100644 --- a/qubesmanager/qube_manager.py +++ b/qubesmanager/qube_manager.py @@ -767,6 +767,8 @@ def table_selection_changed(self): self.action_run_command_in_vm.setEnabled(False) self.action_set_keyboard_layout.setEnabled(False) + self.update_logs_menu() + # noinspection PyArgumentList @QtCore.pyqtSlot(name='on_action_createvm_triggered') def action_createvm_triggered(self): # pylint: disable=no-self-use @@ -1233,8 +1235,7 @@ def createPopupMenu(self): # pylint: disable=invalid-name def open_tools_context_menu(self, widget, point): self.tools_context_menu.exec_(widget.mapToGlobal(point)) - @QtCore.pyqtSlot('const QPoint&') - def open_context_menu(self, point): + def update_logs_menu(self): try: vm = self.get_selected_vm() @@ -1260,15 +1261,21 @@ def open_context_menu(self, point): menu_empty = False self.logs_menu.setEnabled(not menu_empty) - if vm.qid == 0: - self.dom0_context_menu.exec_(self.table.mapToGlobal( - point + QtCore.QPoint(10, 0))) - else: - self.context_menu.exec_(self.table.mapToGlobal( - point + QtCore.QPoint(10, 0))) + except exc.QubesPropertyAccessError: pass + @QtCore.pyqtSlot('const QPoint&') + def open_context_menu(self, point): + vm = self.get_selected_vm() + + if vm.qid == 0: + self.dom0_context_menu.exec_(self.table.mapToGlobal( + point + QtCore.QPoint(10, 0))) + else: + self.context_menu.exec_(self.table.mapToGlobal( + point + QtCore.QPoint(10, 0))) + @QtCore.pyqtSlot('QAction *') def show_log(self, action): log = str(action.data())