From ee5625b65c1f5d4a8e3c69855c6aef13c15943e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Tue, 11 Aug 2020 01:08:48 +0200 Subject: [PATCH] Use the new QubesDaemonAccessError Replaces the old, unified approach. --- qubesmanager/backup.py | 28 ++++++--- qubesmanager/backup_utils.py | 2 +- qubesmanager/bootfromdevice.py | 4 +- qubesmanager/clone_vm.py | 16 +++-- qubesmanager/create_new_vm.py | 2 +- qubesmanager/global_settings.py | 58 ++++++++++------- qubesmanager/qube_manager.py | 104 ++++++++++++++++++------------- qubesmanager/settings.py | 39 ++++++------ qubesmanager/template_manager.py | 9 +-- qubesmanager/utils.py | 18 ++++-- test-packages/qubesadmin/exc.py | 3 + 11 files changed, 168 insertions(+), 115 deletions(-) diff --git a/qubesmanager/backup.py b/qubesmanager/backup.py index 8539208..646ac8d 100644 --- a/qubesmanager/backup.py +++ b/qubesmanager/backup.py @@ -36,7 +36,6 @@ import pwd import os import shutil - # pylint: disable=too-few-public-methods class BackupThread(QtCore.QThread): def __init__(self, vm): @@ -50,7 +49,9 @@ class BackupThread(QtCore.QThread): if not self.vm.is_running(): self.vm.start() except exc.QubesException: - # we may have insufficient exceptions to ensure the qube is running + # we may have insufficient permissions to ensure the qube is running + # let us hope for the best (worst case scenario, we will fail at the + # next step pass try: @@ -94,6 +95,8 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, QtWidgets.QWizard): self.select_dir_page.isComplete = self.has_selected_dir_and_pass # FIXME # this causes to run isComplete() twice, I don't know why + # update 2020-08: selectedChanged is emitted once, + # but completeChanged twice. Somehow. self.select_vms_widget.selectedChanged.connect( self.select_vms_page.completeChanged.emit) self.passphrase_line_edit.textChanged.connect( @@ -144,7 +147,7 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, QtWidgets.QWizard): result = [] for domain in self.qubes_app.domains: - if getattr(domain, 'include_in_backups', None): + if getattr(domain, 'include_in_backups', False): result.append(domain.name) return result @@ -209,14 +212,23 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, QtWidgets.QWizard): # pylint: disable=too-few-public-methods def __init__(self, vm): self.vm = vm - if vm.qid == 0: + if vm.klass == 'AdminVM': local_user = grp.getgrnam('qubes').gr_mem[0] home_dir = pwd.getpwnam(local_user).pw_dir self.size = shutil.disk_usage(home_dir)[1] else: - self.size = vm.get_disk_utilization() - super(BackupVMsWindow.VmListItem, self).__init__( - vm.name + " (" + admin_utils.size_to_human(self.size) + ")") + try: + self.size = vm.get_disk_utilization() + except exc.QubesDaemonAccessError: + self.size = None + + if self.size is not None: + text = vm.name + " (" + admin_utils.size_to_human( + self.size) + ")" + else: + text = vm.name + " (size unavailable)" + self.size = 0 + super(BackupVMsWindow.VmListItem, self).__init__(text) def __fill_vms_list__(self, selected=None): for vm in self.qubes_app.domains: @@ -307,7 +319,7 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, QtWidgets.QWizard): backup_summary = self.qubes_app.qubesd_call( 'dom0', 'admin.backup.Info', backup_utils.get_profile_name(True)).decode() - except exc.QubesDaemonCommunicationError: + except exc.QubesDaemonAccessError: backup_summary = "Failed to get backup summary: " \ "insufficient permissions" diff --git a/qubesmanager/backup_utils.py b/qubesmanager/backup_utils.py index a754417..a791064 100644 --- a/qubesmanager/backup_utils.py +++ b/qubesmanager/backup_utils.py @@ -46,7 +46,7 @@ def fill_appvms_list(dialog): if utils.get_feature(vm, 'internal', False) or vm.klass == 'TemplateVM': continue - if utils.is_running(vm, False) and vm.qid != 0: + if utils.is_running(vm, False) and vm.klass != 'AdminVM': dialog.appvm_combobox.addItem(vm.name) diff --git a/qubesmanager/bootfromdevice.py b/qubesmanager/bootfromdevice.py index bd6344c..0ee48ff 100644 --- a/qubesmanager/bootfromdevice.py +++ b/qubesmanager/bootfromdevice.py @@ -83,7 +83,7 @@ class VMBootFromDeviceWindow(ui_bootfromdevice.Ui_BootDialog, self.tr("Warning!"), self.tr("Qube must be turned off before booting it from " "device. Please turn off the qube.")) - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: QtWidgets.QMessageBox.warning( self, self.tr("Warning!"), @@ -111,7 +111,7 @@ class VMBootFromDeviceWindow(ui_bootfromdevice.Ui_BootDialog, try: for device in domain.devices["block"]: device_choice.append((str(device), device)) - except exc.QubesException: + except exc.QubesDaemonAccessError: # insufficient permissions pass diff --git a/qubesmanager/clone_vm.py b/qubesmanager/clone_vm.py index f88216c..df91646 100644 --- a/qubesmanager/clone_vm.py +++ b/qubesmanager/clone_vm.py @@ -60,12 +60,16 @@ class CloneVMDlg(QtWidgets.QDialog, Ui_CloneVMDlg): self.update_label() - utils.initialize_widget_with_default( - widget=self.storage_pool, - choices=[(str(pool), pool) for pool in self.app.pools.values()], - add_qubes_default=True, - mark_existing_as_default=True, - default_value=self.app.default_pool) + try: + utils.initialize_widget_with_default( + widget=self.storage_pool, + choices=[(str(pool), pool) for pool in self.app.pools.values()], + add_qubes_default=True, + mark_existing_as_default=True, + default_value=self.app.default_pool) + except qubesadmin.exc.QubesDaemonAccessError: + self.storage_pool.clear() + self.storage_pool.addItem("(default)", qubesadmin.DEFAULT) self.set_clone_name() diff --git a/qubesmanager/create_new_vm.py b/qubesmanager/create_new_vm.py index d643973..b1be32a 100644 --- a/qubesmanager/create_new_vm.py +++ b/qubesmanager/create_new_vm.py @@ -123,7 +123,7 @@ class NewVmDlg(QtWidgets.QDialog, Ui_NewVMDlg): add_qubes_default=True, mark_existing_as_default=True, default_value=self.app.default_pool) - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.storage_pool.clear() self.storage_pool.addItem("(default)", qubesadmin.DEFAULT) diff --git a/qubesmanager/global_settings.py b/qubesmanager/global_settings.py index 50be64a..067cf66 100644 --- a/qubesmanager/global_settings.py +++ b/qubesmanager/global_settings.py @@ -90,41 +90,51 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, self.app.setApplicationName(self.tr("Qubes Global Settings")) self.app.setWindowIcon(QtGui.QIcon.fromTheme("qubes-manager")) + def setup_widget_with_vms(self, widget, filter_function, + allow_none, holder, property_name): + try: + utils.initialize_widget_with_vms( + widget=widget, + qubes_app=self.qubes_app, + filter_function=filter_function, + allow_none=allow_none, + holder=holder, + property_name=property_name + ) + except exc.QubesDaemonAccessError: + widget.clear() + widget.setCurrentText("unavailable") + widget.setEnabled(False) + def __init_system_defaults__(self): # set up updatevm choice - utils.initialize_widget_with_vms( + self.setup_widget_with_vms( widget=self.update_vm_combo, - qubes_app=self.qubes_app, filter_function=(lambda vm: vm.klass != 'TemplateVM'), allow_none=True, holder=self.qubes_app, - property_name="updatevm" - ) + property_name="updatevm") # set up clockvm choice - utils.initialize_widget_with_vms( + self.setup_widget_with_vms( widget=self.clock_vm_combo, - qubes_app=self.qubes_app, filter_function=(lambda vm: vm.klass != 'TemplateVM'), allow_none=True, holder=self.qubes_app, - property_name="clockvm" - ) + property_name="clockvm") # set up default netvm - utils.initialize_widget_with_vms( + self.setup_widget_with_vms( widget=self.default_netvm_combo, - qubes_app=self.qubes_app, - filter_function=(lambda vm: getattr(vm, 'provides_network', False)), + filter_function=(lambda vm: getattr( + vm, 'provides_network', False)), allow_none=True, holder=self.qubes_app, - property_name="default_netvm" - ) + property_name="default_netvm") # default template - utils.initialize_widget_with_vms( + self.setup_widget_with_vms( widget=self.default_template_combo, - qubes_app=self.qubes_app, filter_function=(lambda vm: vm.klass == 'TemplateVM'), allow_none=True, holder=self.qubes_app, @@ -132,9 +142,8 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, ) # default dispvm - utils.initialize_widget_with_vms( + self.setup_widget_with_vms( widget=self.default_dispvm_combo, - qubes_app=self.qubes_app, filter_function=(lambda vm: getattr( vm, 'template_for_dispvms', False)), allow_none=True, @@ -194,8 +203,9 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, allow_none=True, holder=self.qubes_app, property_name='default_kernel') - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: self.default_kernel_combo.clear() + self.default_kernel_combo.setCurrentText("unavailable") self.default_kernel_combo.setEnabled(False) def __apply_kernel_defaults__(self): @@ -270,14 +280,14 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, if widget.currentData() is None: try: del self.vm.features[feature] - except exc.QubesDaemonCommunicationError: + except exc.QubesDaemonAccessError: self.errors.append( "Failed to set {} due to insufficient " "permissions".format(feature)) else: try: self.vm.features[feature] = widget.currentData() - except exc.QubesDaemonCommunicationError as ex: + except exc.QubesDaemonAccessError as ex: self.errors.append( "Failed to set {} due to insufficient " "permissions".format(feature)) @@ -411,7 +421,7 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, try: self.updates_vm.setChecked(self.qubes_app.check_updates_vm) - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: self.updates_vm.isEnabled(False) self.enable_updates_all.clicked.connect(self.__enable_updates_all) @@ -485,7 +495,7 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, if vm.klass != "AdminVM": try: vm.features['service.qubes-update-check'] = state - except exc.QubesDaemonCommunicationError: + except exc.QubesDaemonAccessError: errors.append(vm.name) if errors: @@ -501,7 +511,7 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, self.qubes_app.domains['dom0'].features[ 'service.qubes-update-check'] = \ self.updates_dom0.isChecked() - except exc.QubesDaemonCommunicationError: + except exc.QubesDaemonAccessError: self.errors.append("Failed to change dom0 update value due " "to insufficient permissions.") @@ -509,7 +519,7 @@ class GlobalSettingsWindow(ui_globalsettingsdlg.Ui_GlobalSettings, self.qubes_app.check_updates_vm != self.updates_vm.isChecked(): try: self.qubes_app.check_updates_vm = self.updates_vm.isChecked() - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: self.errors.append("Failed to set qube update checking due " "to insufficient permissions.") diff --git a/qubesmanager/qube_manager.py b/qubesmanager/qube_manager.py index 32333e9..a6e5c47 100644 --- a/qubesmanager/qube_manager.py +++ b/qubesmanager/qube_manager.py @@ -209,25 +209,29 @@ class VmInfo(): def update_power_state(self): try: self.state['power'] = self.vm.get_power_state() - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: self.state['power'] = "" self.state['outdated'] = "" try: - if self.vm.is_running(): + if manager_utils.is_running(self.vm, False): if hasattr(self.vm, 'template') and \ - self.vm.template.is_running(): + manager_utils.is_running(self.vm.template, False): self.state['outdated'] = "to-be-outdated" else: - for vol in self.vm.volumes.values(): - if vol.is_outdated(): - self.state['outdated'] = "outdated" - break + try: + for vol in self.vm.volumes.values(): + if vol.is_outdated(): + self.state['outdated'] = "outdated" + break + except exc.QubesDaemonAccessError: + pass if self.vm.klass in {'TemplateVM', 'StandaloneVM'} and \ - self.vm.features.get('updates-available', False): + manager_utils.get_feature( + self.vm, 'updates-available', False): self.state['outdated'] = 'update' - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: pass def update(self, update_size_on_disk=False, event=None): @@ -259,14 +263,12 @@ class VmInfo(): if hasattr(self.vm, 'netvm') \ and self.vm.property_is_default("netvm"): self.netvm = "default (" + self.netvm + ")" - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: pass if not event or event.endswith(':internal'): - try: - self.internal = self.vm.features.get('internal', False) - except exc.QubesPropertyAccessError: - self.internal = False + self.internal = manager_utils.get_boolean_feature( + self.vm, 'internal') if not event or event.endswith(':ip'): self.ip = getattr(self.vm, 'ip', "n/a") @@ -286,8 +288,9 @@ class VmInfo(): self.dvm = "default (" + str(self.dvm) + ")" elif self.dvm is not None: self.dvm = str(self.dvm) - except exc.QubesPropertyAccessError: - self.dvm = None + except exc.QubesDaemonAccessError: + if self.dvm is not None: + self.dvm = str(self.dvm) if not event or event.endswith(':template_for_dispvms'): self.dvm_template = getattr(self.vm, 'template_for_dispvms', None) @@ -296,7 +299,7 @@ class VmInfo(): try: self.disk_float = float(self.vm.get_disk_utilization()) self.disk = str(round(self.disk_float/(1024*1024), 2)) + " MiB" - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: self.disk_float = None self.disk = None @@ -422,7 +425,7 @@ class QubesTableModel(QAbstractTableModel): pixmap.load(icon_name) self.klass_pixmap[vm.klass] = pixmap.scaled(icon_size) return self.klass_pixmap[vm.klass] - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: return None if col_name == "Label": @@ -432,7 +435,7 @@ class QubesTableModel(QAbstractTableModel): icon = QIcon.fromTheme(vm.label.icon) self.label_pixmap[vm.label] = icon.pixmap(icon_size) return self.label_pixmap[vm.label] - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: return None if role == Qt.FontRole: @@ -507,7 +510,7 @@ class VmShutdownMonitor(QObject): def check_if_vm_has_shutdown(self): vm = self.vm - vm_is_running = vm.is_running() + vm_is_running = manager_utils.is_running(vm, False) try: vm_start_time = datetime.fromtimestamp(float(vm.start_time)) except (AttributeError, TypeError, ValueError): @@ -576,8 +579,12 @@ class UpdateVMThread(common_threads.QubesThread): subprocess.check_call( ["/usr/bin/qubes-dom0-update", "--clean", "--gui"]) else: - if not self.vm.is_running(): - self.vm.start() + if not manager_utils.is_running(self.vm, False): + try: + self.vm.start() + except exc.QubesDaemonAccessError: + # permission denied, let us hope for the best + pass # apply DSA-4371 with open('/usr/libexec/qubes-manager/dsa-4371-update', 'rb') \ as dsa4371update: @@ -848,9 +855,10 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): try: if info.vm.klass in {'TemplateVM', 'StandaloneVM'} and \ - info.vm.features.get('updates-available', False): + manager_utils.get_feature( + info.vm, 'updates-available', False): info.state['outdated'] = 'update' - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: return def on_domain_added(self, _submitter, _event, vm, **_kwargs): @@ -874,7 +882,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): update(event="outdated") self.proxy.invalidate() self.table_selection_changed() - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: return # the VM was deleted before its status could be updated except KeyError: # adding the VM failed for some reason self.on_domain_added(None, None, vm) @@ -895,7 +903,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): try: self.qubes_cache.get_vm(qid=vm.qid).update(event=event) self.proxy.invalidate() - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: return # the VM was deleted before its status could be updated def load_manager_settings(self): @@ -1092,19 +1100,19 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): def action_resumevm_triggered(self): for vm_info in self.get_selected_vms(): vm = vm_info.vm - if vm.get_power_state() in ["Paused", "Suspended"]: - try: + try: + if vm.get_power_state() in ["Paused", "Suspended"]: vm.unpause() - except exc.QubesException as ex: - QMessageBox.warning( - self, self.tr("Error unpausing Qube!"), - self.tr("ERROR: {0}").format(ex)) + except exc.QubesException as ex: + QMessageBox.warning( + self, self.tr("Error unpausing Qube!"), + self.tr("ERROR: {0}").format(ex)) return self.start_vm(vm) def start_vm(self, vm): - if vm.is_running(): + if manager_utils.is_running(vm, False): return thread = StartVMThread(vm) @@ -1179,17 +1187,29 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): if reply == QMessageBox.Yes: # in case the user shut down the VM in the meantime - if vm.is_running(): - self.shutdown_vm(vm, and_restart=True) - else: - self.start_vm(vm) + try: + if manager_utils.is_running(vm, False): + self.shutdown_vm(vm, and_restart=True) + else: + self.start_vm(vm) + except exc.QubesException as ex: + QMessageBox.warning( + self, + self.tr("Error restarting Qube!"), + self.tr("ERROR: {0}").format(ex)) # noinspection PyArgumentList @pyqtSlot(name='on_action_killvm_triggered') def action_killvm_triggered(self): for vm_info in self.get_selected_vms(): vm = vm_info.vm - if not (vm.is_running() or vm.is_paused()): + + try: + vm_not_running = not (vm.is_running() or vm.is_paused()) + except exc.QubesDaemonAccessError: + vm_not_running = False + + if vm_not_running: info = self.tr("Qube '{0}' is not running. Are you " "absolutely sure you want to try to kill it?
" "This will end (not shutdown!) " @@ -1213,8 +1233,8 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): QMessageBox.critical( self, self.tr("Error while killing Qube!"), self.tr( - "An exception ocurred while killing {0}.
" - "ERROR: {1}").format(vm.name, ex)) + "An exception occurred while killing {0}." + "
ERROR: {1}").format(vm.name, ex)) return def open_settings(self, vm, tab='basic'): @@ -1252,7 +1272,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): def action_updatevm_triggered(self): for vm_info in self.get_selected_vms(): vm = vm_info.vm - if not vm.is_running(): + if not manager_utils.is_running(vm, True): reply = QMessageBox.question( self, self.tr("Qube Update Confirmation"), self.tr( @@ -1417,7 +1437,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow): menu_empty = False self.logs_menu.setEnabled(not menu_empty) - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: pass @pyqtSlot('const QPoint&') diff --git a/qubesmanager/settings.py b/qubesmanager/settings.py index bb8a7fe..29120da 100644 --- a/qubesmanager/settings.py +++ b/qubesmanager/settings.py @@ -337,7 +337,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): no_firewall_state = \ netvm is not None and \ not netvm.features.check_with_template('qubes-firewall', False) - except qubesadmin.exc.QubesDaemonCommunicationError: + except qubesadmin.exc.QubesDaemonAccessError: no_firewall_state = False self.netvm_no_firewall_label.setVisible(no_firewall_state) @@ -372,7 +372,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): self.delete_vm_button.setText( self.tr('Delete qube (cannot delete a running qube)')) - if self.vm.qid == 0: + if self.vm.klass == 'AdminVM': self.vmlabel.setVisible(False) else: try: @@ -382,7 +382,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): holder=self.vm) self.vmlabel.setVisible(True) self.vmlabel.setEnabled(not utils.is_running(self.vm, False)) - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.vmlabel.setEnabled(False) if self.vm.klass == 'AppVM': @@ -393,7 +393,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): filter_function=(lambda vm: vm.klass == 'TemplateVM'), holder=self.vm, property_name='template') - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.template_name.setCurrentIndex(-1) self.template_name.setEnabled(False) @@ -402,11 +402,11 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): utils.initialize_widget_with_vms( widget=self.template_name, qubes_app=self.qubesapp, - filter_function=(lambda vm: - getattr(vm, 'template_for_dispvms', False)), + filter_function=( + lambda vm: getattr(vm, 'template_for_dispvms', False)), holder=self.vm, property_name='template') - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.template_name.setCurrentIndex(-1) self.template_name.setEnabled(False) @@ -426,7 +426,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): property_name='netvm', allow_default=True, allow_none=True) - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.netVM.setEnabled(False) self.netVM.setCurrentIndex(-1) @@ -434,13 +434,13 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): try: self.include_in_backups.setChecked(self.vm.include_in_backups) - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.include_in_backups.setEnabled(False) try: self.autostart_vm.setChecked(self.vm.autostart) self.autostart_vm.setVisible(True) - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.autostart_vm.setEnabled(False) except AttributeError: self.autostart_vm.setVisible(False) @@ -602,7 +602,10 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): own_netvm = self.netVM.currentData() if dispvm == qubesadmin.DEFAULT: - dispvm = self.vm.property_get_default('default_dispvm') + try: + dispvm = self.vm.property_get_default('default_dispvm') + except qubesadmin.exc.QubesDaemonAccessError: + pass if dispvm == self.vm: self.warn_netvm_dispvm.setVisible(False) @@ -613,7 +616,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): if own_netvm == qubesadmin.DEFAULT: try: own_netvm = self.vm.property_get_default('netvm') - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: # no point in warning if we don't know what we're warning about self.warn_netvm_dispvm.setVisible(False) return @@ -731,7 +734,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): else: try: maxmem = self.vm.property_get_default('maxmem') - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: maxmem = 0 if maxmem == 0: maxmem = vm_memory @@ -760,7 +763,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): property_name='kernel') self.kernel.currentIndexChanged.connect(self.kernel_changed) self.kernel_opts.setText(getattr(self.vm, 'kernelopts', '-')) - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.kernel_groupbox.setVisible(False) else: self.kernel_groupbox.setVisible(False) @@ -783,7 +786,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): ) self.default_dispvm.currentIndexChanged.connect( self.check_warn_dispvmnetvm) - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.other_groupbox.setVisible(False) self.check_warn_dispvmnetvm() @@ -1030,7 +1033,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): choices=choices, holder=self.vm, property_name='virt_mode') - except qubesadmin.exc.QubesPropertyAccessError: + except qubesadmin.exc.QubesDaemonAccessError: self.virt_mode.setEnabled(False) if self.virt_mode.isEnabled() and old_mode is not None: @@ -1255,7 +1258,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): else ui_settingsdlg.QtCore.Qt.Unchecked) self.services_list.addItem(item) self.new_srv_dict[service] = self.vm.features[feature] - except qubesadmin.exc.QubesDaemonCommunicationError: + except qubesadmin.exc.QubesDaemonAccessError: self.tabWidget.setTabEnabled(self.tabs_indices["services"], False) return @@ -1272,7 +1275,7 @@ class VMSettingsWindow(ui_settingsdlg.Ui_SettingsDialog, QtWidgets.QDialog): for feature in self.vm.template.features: if feature.startswith(service_prefix): supported_services.add(feature[len(service_prefix):]) - except qubesadmin.exc.QubesDaemonCommunicationError: + except qubesadmin.exc.QubesDaemonAccessError: pass for service in sorted(supported_services): diff --git a/qubesmanager/template_manager.py b/qubesmanager/template_manager.py index 7ce6e46..7664eed 100644 --- a/qubesmanager/template_manager.py +++ b/qubesmanager/template_manager.py @@ -345,7 +345,7 @@ class VMRow: table_widget.setItem(row_no, columns.index('New template'), self.dummy_new_item) - self.vm_state_change(is_vm_running(self.vm), row_no) + self.vm_state_change(utils.is_running(self.vm, False), row_no) def vm_state_change(self, is_running, row=None): self.state_item.set_state(is_running) @@ -385,13 +385,6 @@ class VMRow: self.checkbox = None -def is_vm_running(vm): - try: - return vm.is_running() - except exc.QubesPropertyAccessError: - return False - - def main(): utils.run_asynchronous(TemplateManagerWindow) diff --git a/qubesmanager/utils.py b/qubesmanager/utils.py index 3fa06ed..01cf041 100644 --- a/qubesmanager/utils.py +++ b/qubesmanager/utils.py @@ -54,7 +54,7 @@ def is_internal(vm): try: return (vm.klass == 'AdminVM' or vm.features.get('internal', False)) - except exc.QubesDaemonCommunicationError: + except exc.QubesDaemonAccessError: return False @@ -63,7 +63,7 @@ def is_running(vm, default_state): insufficient permissions to deteremine that.""" try: return vm.is_running() - except exc.QubesPropertyAccessError: + except exc.QubesDaemonAccessError: return default_state @@ -107,7 +107,7 @@ class SizeSpinBox(QtWidgets.QSpinBox): def get_feature(vm, feature_name, default_value): try: return vm.features.get(feature_name, default_value) - except exc.QubesDaemonCommunicationError: + except exc.QubesDaemonAccessError: return default_value @@ -186,7 +186,10 @@ def initialize_widget_for_property( :return: """ if allow_default: - default_property = holder.property_get_default(property_name) + try: + default_property = holder.property_get_default(property_name) + except exc.QubesDaemonAccessError: + default_property = "ERROR: unavailable" if default_property is None: default_property = "none" choices.append( @@ -194,7 +197,12 @@ def initialize_widget_for_property( qubesadmin.DEFAULT)) # calculate current (can be default) - if holder.property_is_default(property_name): + try: + is_default = holder.property_is_default(property_name) + except exc.QubesDaemonAccessError: + is_default = False + + if is_default: current_value = qubesadmin.DEFAULT else: current_value = getattr(holder, property_name) diff --git a/test-packages/qubesadmin/exc.py b/test-packages/qubesadmin/exc.py index 024342d..7e40d7a 100644 --- a/test-packages/qubesadmin/exc.py +++ b/test-packages/qubesadmin/exc.py @@ -11,6 +11,9 @@ class QubesVMNotStartedError(BaseException): class QubesPropertyAccessError(BaseException): pass +class QubesDaemonAccessError(BaseException): + pass + class QubesNoSuchPropertyError(BaseException): pass