Browse Source

qubesmanager/utils

Wojtek Porczyk 7 years ago
parent
commit
6462ae88b7
3 changed files with 182 additions and 91 deletions
  1. 42 91
      qubesmanager/settings.py
  2. 137 0
      qubesmanager/utils.py
  3. 3 0
      rpm_spec/qmgr.spec

+ 42 - 91
qubesmanager/settings.py

@@ -32,6 +32,7 @@ import subprocess
 import qubesadmin
 import qubesadmin.tools
 
+from . import utils
 
 from .ui_settingsdlg import *
 from .appmenu_select import *
@@ -186,7 +187,7 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
         if len(ret) > 0 :
             thread_monitor.set_error_msg('\n'.join(ret))
 
-        thread_monitor.set_finished()
+        utils.debug('\n'.join(ret))
 
 
     def current_tab_changed(self, idx):
@@ -201,11 +202,10 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
                     "a working Firewall VM.").format(vm=self.vm.name))
 
 
-
     ######### basic tab
 
     # TODO LISTENERS
-    # - vm start/shutdown -> setEnabled on fields: template
+    # - vm start/shutdown -> setEnabled on fields: template labels
     # - vm create/delete -> choices lists, whole window deactiv (if self.vm)
     # - property-set -> individual fields
 
@@ -213,45 +213,8 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
     # netvm -> networking_groupbox
     # hvm -> include_in_balancing
 
-    def setup_vm_choice(self, widget, propname, default, filter_function,
-            allow_internal=False, allow_none=False):
-        # some basic information
-        oldvalue = getattr(self.vm, propname)
-        is_default = self.vm.property_is_default(propname)
-        idx = -1
-
-        vmlist = filter(filter_function, self.app.domains)
-        if not allow_internal:
-            vmlist = filter((lambda vm: not vm.features.get('internal', False)),
-                vmlist)
-        vmlist = list(vmlist)
-        vmlist.insert(0, qubesadmin.DEFAULT)
-        if allow_none:
-            vmlist.append(None)
-
-        for i, vm in enumerate(vmlist):
-            # 0: default (unset)
-            if vm is qubesadmin.DEFAULT:
-                text = 'default ({})'.format(
-                    default.name if default else 'none')
-            # N+1: explicit None
-            elif vm is None:
-                text = 'none'
-            # 1..N: choices
-            else:
-                text = vm.name
-
-            if vm is qubesadmin.DEFAULT and is_default \
-            or vm is oldvalue:
-                text += self.tr(' (current)')
-                idx = i
-
-            widget.insertItem(i, text)
-
-        setattr(self, propname + '_idx', idx)
-        setattr(self, propname + '_list', list)
-        widget.setCurrentIndex(idx)
-
+    # TODO REMOVE
+    # other_groupbox
 
     def __init_basic_tab__(self):
         self.vmname.setText(self.vm.name)
@@ -261,27 +224,32 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
         if self.vm.qid == 0:
             self.vmlabel.setVisible(False)
         else:
+            self.label_list, self.label_idx = utils.prepare_label_choice(
+                self.vmlabel,
+                self.vm, 'label',
+                None,
+                allow_default=False
+                )
             self.vmlabel.setVisible(True)
-            self.label_list = list(self.vm.app.labels)
-            self.label_list.sort(key=lambda l: l.index)
-            self.label_idx = 0
-            for i, label in enumerate(self.label_list):
-                if label == self.vm.label:
-                    self.label_idx = i
-                self.vmlabel.insertItem(i, label.name)
-                self.vmlabel.setItemIcon(i, QIcon.fromTheme(label.icon))
-            self.vmlabel.setCurrentIndex(self.label_idx)
-        self.vmlabel.setEnabled(not self.vm.is_running())
+            self.vmlabel.setEnabled(not self.vm.is_running())
 
         if isinstance(self.vm, qubesadmin.vm.AppVM):
-            self.setup_vm_choice(self.template_name, 'template',
-                (lambda vm: isinstance(vm, qubesadmin.vm.TemplateVM)))
+            self.template_list, self.template_idx = utils.prepare_vm_choice(
+                self.template_name,
+                self.vm, 'template',
+                self.vm.app.default_template,
+                (lambda vm: isinstance(vm, qubesadmin.vm.TemplateVM)),
+                allow_default=True, allow_none=False)
         else:
             self.template_name.setEnabled(False)
             self.template_idx = -1
 
-        self.setup_vm_choice(self.netVM, 'netvm',
-            (lambda vm: vm.provides_network))
+        self.netvm_list, self.netvm_idx = utils.prepare_vm_choice(
+            self.netVM,
+            self.vm, 'netvm',
+            self.vm.app.default_netvm,
+            (lambda vm: vm.provides_network),
+            allow_default=True, allow_none=True)
 
         self.include_in_backups.setChecked(self.vm.include_in_backups)
 
@@ -463,47 +431,30 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
         except AttributeError:
             pass
         try:
-            self.root_img_path.setText(self.vm.storage.root_img)
+            self.root_img_path.setText('{volume.pool}:{volume.vid}'.format(
+                volume=self.vm.volumes['root']))
         except AttributeError:
             self.root_img_path.setText("n/a")
         try:
-            self.volatile_img_path.setText(self.vm.storage.volatile_img)
+            self.volatile_img_path.setText('{volume.pool}:{volume.vid}'.format(
+                volume=self.vm.volumes['volatile']))
         except AttributeError:
             self.volatile_img_path.setText('n/a')
-        self.private_img_path.setText(self.vm.storage.private_img)
+        self.private_img_path.setText('{volume.pool}:{volume.vid}'.format(
+            volume=self.vm.volumes['private']))
 
 
         #kernel
 
         #in case VM is HVM
-        if not hasattr(self.vm, "kernel"):
-            self.kernel_groupbox.setVisible(False)
-        else:
+        if hasattr(self.vm, "kernel"):
             self.kernel_groupbox.setVisible(True)
-            # construct available kernels list
-            text = "default (" + self.app.get_default_kernel() +")"
-            kernel_list = [text]
-            for k in os.listdir(system_path["qubes_kernels_base_dir"]):
-                kernel_list.append(k)
-            kernel_list.append("none")
-
-            self.kernel_idx = 0
-
-            # put available kernels to a combobox
-            for (i, k) in enumerate(kernel_list):
-                text = k
-                # and mark the current choice
-                if (text.startswith("default") and self.vm.uses_default_kernel) or ( self.vm.kernel == k and not self.vm.uses_default_kernel) or (k=="none" and self.vm.kernel==None):
-                    text += " (current)"
-                    self.kernel_idx = i
-                self.kernel.insertItem(i,text)
-            self.kernel.setCurrentIndex(self.kernel_idx)
-
-            #kernel opts
-            if self.vm.uses_default_kernelopts:
-                self.kernel_opts.setText(self.vm.kernelopts + " (default)")
-            else:
-                self.kernel_opts.setText(self.vm.kernelopts)
+            self.kernel_list, self.kernel_idx = utils.prepare_kernel_choice(
+                self.kernel, self.vm, 'kernel',
+                self.vm.app.default_kernel,
+                allow_default=True, allow_none=True)
+        else:
+            self.kernel_groupbox.setVisible(False)
 
         if not hasattr(self.vm, "drive"):
             self.drive_groupbox.setVisible(False)
@@ -660,6 +611,8 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
                     self.vm.dispvm_netvm = dispvm_netvm
                 self.anything_changed = True
         except Exception as ex:
+            if utils.is_debug():
+                traceback.print_exc()
             msg.append(str(ex))
 
         return msg
@@ -742,6 +695,8 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
                 self.vm.pcidevs = pcidevs
                 self.anything_changed = True
         except Exception as ex:
+            if utils.is_debug():
+                traceback.print_exc()
             msg.append(str(ex))
 
         return msg
@@ -1005,13 +960,9 @@ parser = qubesadmin.tools.QubesArgumentParser(vmname_nargs=1)
 parser.add_argument('--tab', metavar='TAB',
     action='store',
     choices=VMSettingsWindow.tabs_indices.keys())
-parser.add_argument('--debug',
-    action='store_true',
-    help='debug mode')
 
 parser.set_defaults(
     tab='basic',
-    debug=os.getenv('QUBES_MANAGER_DEBUG', '0') != '0',
 )
 
 def main(args=None):
@@ -1025,7 +976,7 @@ def main(args=None):
     qapp.setOrganizationDomain("https://www.qubes-os.org/")
     qapp.setApplicationName("Qubes VM Settings")
 
-    if not args.debug:
+    if not utils.is_debug():
         sys.excepthook = handle_exception
 
     settings_window = VMSettingsWindow(vm, qapp, args.tab)

+ 137 - 0
qubesmanager/utils.py

@@ -0,0 +1,137 @@
+#
+# The Qubes OS Project, https://www.qubes-os.org
+#
+# Copyright (C) 2012  Agnieszka Kostrzewa <agnieszka.kostrzewa@gmail.com>
+# Copyright (C) 2012  Marek Marczykowski-Górecki
+#                       <marmarek@invisiblethingslab.com>
+# Copyright (C) 2017  Wojtek Porczyk <woju@invisiblethingslab.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import functools
+import os
+
+import qubesadmin
+
+from PyQt4.QtGui import QIcon
+
+def _filter_internal(vm):
+    return (not isinstance(vm, qubesadmin.vm.AdminVM)
+        and not vm.features.get('internal', False))
+
+def prepare_choice(widget, holder, propname, choice, default,
+        filter_function=None, *,
+        icon_getter=None, allow_internal=None, allow_default=False,
+        allow_none=False):
+
+    # for newly created vms, set propname to None
+
+    debug(
+        'prepare_choice(widget={widget!r}, '
+        'holder={holder!r}, '
+        'propname={propname!r}, '
+        'choice={choice!r}, '
+        'default={default!r}, '
+        'filter_function={filter_function!r}, '
+        'icon_getter={icon_getter!r}, '
+        'allow_internal={allow_internal!r}, '
+        'allow_default={allow_default!r}, '
+        'allow_none={allow_none!r})'.format(**locals()))
+
+    if allow_internal is None:
+        allow_internal = propname is None or not propname.endswith('vm')
+
+    if propname is not None:
+        oldvalue = getattr(holder, propname)
+        is_default = holder.property_is_default(propname)
+    else:
+        oldvalue = object()  # won't match for identity
+        is_default = False
+    idx = 0
+
+    choice_list = list(choice)[:]
+    if not allow_internal:
+        choice_list = filter(_filter_internal, choice_list)
+    if filter_function is not None:
+        choice_list = filter(filter_function, choice_list)
+    choice_list = list(choice_list)
+
+    if allow_default:
+        choice_list.insert(0, qubesadmin.DEFAULT)
+    if allow_none:
+        choice_list.append(None)
+
+    for i, item in enumerate(choice_list):
+        debug('i={} item={}'.format(i, item))
+        # 0: default (unset)
+        if item is qubesadmin.DEFAULT:
+            text = 'default ({})'.format(
+                str(default) if default is not None else 'none')
+        # N+1: explicit None
+        elif item is None:
+            text = 'none'
+        # 1..N: choices
+        else:
+            text = str(item)
+
+        if item is qubesadmin.DEFAULT and is_default \
+        or item is not qubesadmin.DEFAULT and item is oldvalue:
+            text += ' (current)'
+            idx = i
+
+        widget.insertItem(i, text)
+
+        if icon_getter is not None:
+            icon = icon_getter(item)
+            if icon is not None:
+                widget.setItemIcon(i, icon)
+
+    widget.setCurrentIndex(idx)
+
+    return choice_list, idx
+
+def prepare_kernel_choice(widget, holder, propname, default, *args, **kwargs):
+    # TODO get from storage API (pool 'linux-kernel') (suggested by @marmarta)
+    return prepare_choice(widget, holder, propname,
+        os.listdir('/var/lib/qubes/vm-kernels'), default, *args, **kwargs)
+
+def prepare_label_choice(widget, holder, propname, default, *args, **kwargs):
+    try:
+        app = holder.app
+    except AttributeError:
+        app = holder
+
+    return prepare_choice(widget, holder, propname,
+        sorted(app.labels, key=lambda l: l.index),
+        default, *args,
+        icon_getter=(lambda label: QIcon.fromTheme(label.icon)),
+        **kwargs)
+
+def prepare_vm_choice(widget, holder, propname, default, *args, **kwargs):
+    try:
+        app = holder.app
+    except AttributeError:
+        app = holder
+
+    return prepare_choice(widget, holder, propname, app.domains, default,
+        *args, **kwargs)
+
+def is_debug():
+    return os.getenv('QUBES_MANAGER_DEBUG', '') not in ('', '0')
+
+def debug(*args, **kwargs):
+    if not is_debug():
+        return
+    print(*args, **kwargs)

+ 3 - 0
rpm_spec/qmgr.spec

@@ -85,7 +85,10 @@ rm -rf $RPM_BUILD_ROOT
 %{python3_sitelib}/qubesmanager/informationnotes.py
 %{python3_sitelib}/qubesmanager/create_new_vm.py
 %{python3_sitelib}/qubesmanager/thread_monitor.py
+%{python3_sitelib}/qubesmanager/utils.py
+
 %{python3_sitelib}/qubesmanager/resources_rc.py
+
 %{python3_sitelib}/qubesmanager/ui_backupdlg.py
 %{python3_sitelib}/qubesmanager/ui_globalsettingsdlg.py
 %{python3_sitelib}/qubesmanager/ui_multiselectwidget.py