Browse Source

Use the new QubesDaemonAccessError

Replaces the old, unified approach.
Marta Marczykowska-Górecka 3 years ago
parent
commit
ee5625b65c

+ 20 - 8
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"
 

+ 1 - 1
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)
 
 

+ 2 - 2
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
 

+ 10 - 6
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()
 

+ 1 - 1
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)
 

+ 34 - 24
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.")
 

+ 62 - 42
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 <b>'{0}'</b> is not running. Are you "
                                "absolutely sure you want to try to kill it?<br>"
                                "<small>This will end <b>(not shutdown!)</b> "
@@ -1213,8 +1233,8 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
                     QMessageBox.critical(
                         self, self.tr("Error while killing Qube!"),
                         self.tr(
-                            "<b>An exception ocurred while killing {0}.</b><br>"
-                            "ERROR: {1}").format(vm.name, ex))
+                            "<b>An exception occurred while killing {0}.</b>"
+                            "<br>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&')

+ 21 - 18
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):

+ 1 - 8
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)
 

+ 13 - 5
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)

+ 3 - 0
test-packages/qubesadmin/exc.py

@@ -11,6 +11,9 @@ class QubesVMNotStartedError(BaseException):
 class QubesPropertyAccessError(BaseException):
     pass
 
+class QubesDaemonAccessError(BaseException):
+    pass
+
 class QubesNoSuchPropertyError(BaseException):
     pass