Misc qubesmanager tools modified to be more resilient to insufficient permissions
Create New Qubes, Backup and Restore, Boot from Device and Template Manager are now more resilient to insufficient permissions.
This commit is contained in:
parent
7cbc7d9db1
commit
39129bd804
@ -49,6 +49,11 @@ class BackupThread(QtCore.QThread):
|
|||||||
try:
|
try:
|
||||||
if not self.vm.is_running():
|
if not self.vm.is_running():
|
||||||
self.vm.start()
|
self.vm.start()
|
||||||
|
except exc.QubesException:
|
||||||
|
# we may have insufficient exceptions to ensure the qube is running
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
self.vm.app.qubesd_call(
|
self.vm.app.qubesd_call(
|
||||||
'dom0', 'admin.backup.Execute',
|
'dom0', 'admin.backup.Execute',
|
||||||
backup_utils.get_profile_name(True))
|
backup_utils.get_profile_name(True))
|
||||||
@ -103,8 +108,8 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, QtWidgets.QWizard):
|
|||||||
qubes_app=self.qubes_app,
|
qubes_app=self.qubes_app,
|
||||||
filter_function=(lambda vm:
|
filter_function=(lambda vm:
|
||||||
vm.klass != 'TemplateVM'
|
vm.klass != 'TemplateVM'
|
||||||
and vm.is_running()
|
and utils.is_running(vm, False)
|
||||||
and not vm.features.get('internal', False)),
|
and not utils.get_feature(vm, 'internal', False)),
|
||||||
allow_internal=True,
|
allow_internal=True,
|
||||||
)
|
)
|
||||||
self.appvm_combobox.setCurrentIndex(
|
self.appvm_combobox.setCurrentIndex(
|
||||||
@ -215,7 +220,7 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, QtWidgets.QWizard):
|
|||||||
|
|
||||||
def __fill_vms_list__(self, selected=None):
|
def __fill_vms_list__(self, selected=None):
|
||||||
for vm in self.qubes_app.domains:
|
for vm in self.qubes_app.domains:
|
||||||
if vm.features.get('internal', False):
|
if utils.get_feature(vm, 'internal', False):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
item = BackupVMsWindow.VmListItem(vm)
|
item = BackupVMsWindow.VmListItem(vm)
|
||||||
@ -298,13 +303,17 @@ class BackupVMsWindow(ui_backupdlg.Ui_Backup, QtWidgets.QWizard):
|
|||||||
if self.currentPage() is self.confirm_page:
|
if self.currentPage() is self.confirm_page:
|
||||||
|
|
||||||
self.save_settings(use_temp=True)
|
self.save_settings(use_temp=True)
|
||||||
backup_summary = self.qubes_app.qubesd_call(
|
try:
|
||||||
'dom0', 'admin.backup.Info',
|
backup_summary = self.qubes_app.qubesd_call(
|
||||||
backup_utils.get_profile_name(True))
|
'dom0', 'admin.backup.Info',
|
||||||
|
backup_utils.get_profile_name(True)).decode()
|
||||||
|
except exc.QubesDaemonCommunicationError:
|
||||||
|
backup_summary = "Failed to get backup summary: " \
|
||||||
|
"insufficient permissions"
|
||||||
|
|
||||||
self.textEdit.setReadOnly(True)
|
self.textEdit.setReadOnly(True)
|
||||||
self.textEdit.setFontFamily("Monospace")
|
self.textEdit.setFontFamily("Monospace")
|
||||||
self.textEdit.setText(backup_summary.decode())
|
self.textEdit.setText(backup_summary)
|
||||||
|
|
||||||
elif self.currentPage() is self.commit_page:
|
elif self.currentPage() is self.commit_page:
|
||||||
|
|
||||||
|
@ -43,10 +43,10 @@ def fill_appvms_list(dialog):
|
|||||||
dialog.appvm_combobox.setCurrentIndex(0) # current selected is null ""
|
dialog.appvm_combobox.setCurrentIndex(0) # current selected is null ""
|
||||||
|
|
||||||
for vm in dialog.qubes_app.domains:
|
for vm in dialog.qubes_app.domains:
|
||||||
if vm.features.get('internal', False) or vm.klass == 'TemplateVM':
|
if utils.get_feature(vm, 'internal', False) or vm.klass == 'TemplateVM':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if vm.is_running() and vm.qid != 0:
|
if utils.is_running(vm, False) and vm.qid != 0:
|
||||||
dialog.appvm_combobox.addItem(vm.name)
|
dialog.appvm_combobox.addItem(vm.name)
|
||||||
|
|
||||||
|
|
||||||
@ -101,6 +101,11 @@ def select_path_button_clicked(dialog, select_file=False, read_only=False):
|
|||||||
dialog.tr("Unexpected characters in path!"),
|
dialog.tr("Unexpected characters in path!"),
|
||||||
dialog.tr("Backup path can only contain the following "
|
dialog.tr("Backup path can only contain the following "
|
||||||
"special characters: /:.,_+=() -"))
|
"special characters: /:.,_+=() -"))
|
||||||
|
except Exception as ex:
|
||||||
|
QtWidgets.QMessageBox.warning(
|
||||||
|
dialog,
|
||||||
|
dialog.tr("Failed to select path!"),
|
||||||
|
dialog.tr("Error {} occurred.".format(str(ex))))
|
||||||
|
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
if not read_only:
|
if not read_only:
|
||||||
|
@ -24,6 +24,7 @@ from . import ui_bootfromdevice # pylint: disable=no-name-in-module
|
|||||||
from PyQt5 import QtWidgets, QtGui # pylint: disable=import-error
|
from PyQt5 import QtWidgets, QtGui # pylint: disable=import-error
|
||||||
from qubesadmin import tools
|
from qubesadmin import tools
|
||||||
from qubesadmin.tools import qvm_start
|
from qubesadmin.tools import qvm_start
|
||||||
|
from qubesadmin import exc
|
||||||
|
|
||||||
|
|
||||||
class VMBootFromDeviceWindow(ui_bootfromdevice.Ui_BootDialog,
|
class VMBootFromDeviceWindow(ui_bootfromdevice.Ui_BootDialog,
|
||||||
@ -75,13 +76,20 @@ class VMBootFromDeviceWindow(ui_bootfromdevice.Ui_BootDialog,
|
|||||||
self.done(0)
|
self.done(0)
|
||||||
|
|
||||||
def __warn_if_running__(self):
|
def __warn_if_running__(self):
|
||||||
if self.vm.is_running():
|
try:
|
||||||
|
if self.vm.is_running():
|
||||||
|
QtWidgets.QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
self.tr("Warning!"),
|
||||||
|
self.tr("Qube must be turned off before booting it from "
|
||||||
|
"device. Please turn off the qube."))
|
||||||
|
except exc.QubesPropertyAccessError:
|
||||||
QtWidgets.QMessageBox.warning(
|
QtWidgets.QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
self.tr("Warning!"),
|
self.tr("Warning!"),
|
||||||
self.tr("Qube must be turned off before booting it from "
|
self.tr("Insufficient permissions to determine if qube is "
|
||||||
"device. Please turn off the qube.")
|
"running. It must be turned off before booting it from "
|
||||||
)
|
"device."))
|
||||||
|
|
||||||
def __init_buttons__(self):
|
def __init_buttons__(self):
|
||||||
self.fileVM.setEnabled(False)
|
self.fileVM.setEnabled(False)
|
||||||
@ -98,8 +106,14 @@ class VMBootFromDeviceWindow(ui_bootfromdevice.Ui_BootDialog,
|
|||||||
allow_internal=True
|
allow_internal=True
|
||||||
)
|
)
|
||||||
|
|
||||||
device_choice = [(str(device), device) for domain in self.vm.app.domains
|
device_choice = []
|
||||||
for device in domain.devices["block"]]
|
for domain in self.vm.app.domains:
|
||||||
|
try:
|
||||||
|
for device in domain.devices["block"]:
|
||||||
|
device_choice.append((str(device), device))
|
||||||
|
except exc.QubesException:
|
||||||
|
# insufficient permissions
|
||||||
|
pass
|
||||||
|
|
||||||
utils.initialize_widget(
|
utils.initialize_widget(
|
||||||
widget=self.blockDeviceComboBox,
|
widget=self.blockDeviceComboBox,
|
||||||
|
@ -105,22 +105,27 @@ class NewVmDlg(QtWidgets.QDialog, Ui_NewVMDlg):
|
|||||||
choices=[(vm.name, vm) for vm in self.app.domains
|
choices=[(vm.name, vm) for vm in self.app.domains
|
||||||
if not utils.is_internal(vm) and vm.klass == 'TemplateVM'],
|
if not utils.is_internal(vm) and vm.klass == 'TemplateVM'],
|
||||||
mark_existing_as_default=True,
|
mark_existing_as_default=True,
|
||||||
default_value=self.app.default_template)
|
default_value=getattr(self.app, 'default_template', None))
|
||||||
|
|
||||||
utils.initialize_widget_with_default(
|
utils.initialize_widget_with_default(
|
||||||
widget=self.netvm,
|
widget=self.netvm,
|
||||||
choices=[(vm.name, vm) for vm in self.app.domains
|
choices=[(vm.name, vm) for vm in self.app.domains
|
||||||
if not utils.is_internal(vm) and vm.provides_network],
|
if not utils.is_internal(vm) and
|
||||||
|
getattr(vm, 'provides_network', False)],
|
||||||
add_none=True,
|
add_none=True,
|
||||||
add_qubes_default=True,
|
add_qubes_default=True,
|
||||||
default_value=self.app.default_netvm)
|
default_value=getattr(self.app, 'default_netvm', None))
|
||||||
|
|
||||||
utils.initialize_widget_with_default(
|
try:
|
||||||
widget=self.storage_pool,
|
utils.initialize_widget_with_default(
|
||||||
choices=[(str(pool), pool) for pool in self.app.pools.values()],
|
widget=self.storage_pool,
|
||||||
add_qubes_default=True,
|
choices=[(str(pool), pool) for pool in self.app.pools.values()],
|
||||||
mark_existing_as_default=True,
|
add_qubes_default=True,
|
||||||
default_value=self.app.default_pool)
|
mark_existing_as_default=True,
|
||||||
|
default_value=self.app.default_pool)
|
||||||
|
except qubesadmin.exc.QubesPropertyAccessError:
|
||||||
|
self.storage_pool.clear()
|
||||||
|
self.storage_pool.addItem("(default)", qubesadmin.DEFAULT)
|
||||||
|
|
||||||
self.name.setValidator(QtGui.QRegExpValidator(
|
self.name.setValidator(QtGui.QRegExpValidator(
|
||||||
QtCore.QRegExp("[a-zA-Z0-9_-]*", QtCore.Qt.CaseInsensitive), None))
|
QtCore.QRegExp("[a-zA-Z0-9_-]*", QtCore.Qt.CaseInsensitive), None))
|
||||||
@ -133,8 +138,6 @@ class NewVmDlg(QtWidgets.QDialog, Ui_NewVMDlg):
|
|||||||
self.tr('No template available!'),
|
self.tr('No template available!'),
|
||||||
self.tr('Cannot create a qube when no template exists.'))
|
self.tr('Cannot create a qube when no template exists.'))
|
||||||
|
|
||||||
# Order of types is important and used elsewhere; if it's changed
|
|
||||||
# check for changes needed in self.type_change
|
|
||||||
type_list = [
|
type_list = [
|
||||||
(self.tr("Qube based on a template (AppVM)"), 'AppVM'),
|
(self.tr("Qube based on a template (AppVM)"), 'AppVM'),
|
||||||
(self.tr("Standalone qube copied from a template"),
|
(self.tr("Standalone qube copied from a template"),
|
||||||
|
@ -345,7 +345,7 @@ class VMRow:
|
|||||||
table_widget.setItem(row_no, columns.index('New template'),
|
table_widget.setItem(row_no, columns.index('New template'),
|
||||||
self.dummy_new_item)
|
self.dummy_new_item)
|
||||||
|
|
||||||
self.vm_state_change(self.vm.is_running(), row_no)
|
self.vm_state_change(is_vm_running(self.vm), row_no)
|
||||||
|
|
||||||
def vm_state_change(self, is_running, row=None):
|
def vm_state_change(self, is_running, row=None):
|
||||||
self.state_item.set_state(is_running)
|
self.state_item.set_state(is_running)
|
||||||
@ -385,6 +385,13 @@ class VMRow:
|
|||||||
self.checkbox = None
|
self.checkbox = None
|
||||||
|
|
||||||
|
|
||||||
|
def is_vm_running(vm):
|
||||||
|
try:
|
||||||
|
return vm.is_running()
|
||||||
|
except exc.QubesPropertyAccessError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
utils.run_asynchronous(TemplateManagerWindow)
|
utils.run_asynchronous(TemplateManagerWindow)
|
||||||
|
|
||||||
|
@ -51,8 +51,20 @@ from PyQt5 import QtWidgets, QtCore, QtGui # pylint: disable=import-error
|
|||||||
|
|
||||||
def is_internal(vm):
|
def is_internal(vm):
|
||||||
"""checks if the VM is either an AdminVM or has the 'internal' features"""
|
"""checks if the VM is either an AdminVM or has the 'internal' features"""
|
||||||
return (vm.klass == 'AdminVM'
|
try:
|
||||||
or vm.features.get('internal', False))
|
return (vm.klass == 'AdminVM'
|
||||||
|
or vm.features.get('internal', False))
|
||||||
|
except exc.QubesDaemonCommunicationError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_running(vm, default_state):
|
||||||
|
"""Checks if the VM is running, returns default_state if we have
|
||||||
|
insufficient permissions to deteremine that."""
|
||||||
|
try:
|
||||||
|
return vm.is_running()
|
||||||
|
except exc.QubesPropertyAccessError:
|
||||||
|
return default_state
|
||||||
|
|
||||||
|
|
||||||
def translate(string):
|
def translate(string):
|
||||||
|
Loading…
Reference in New Issue
Block a user