2013-01-23 15:55:14 +01:00
#!/usr/bin/python2
2012-01-31 11:17:09 +01:00
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2012 Agnieszka Kostrzewa <agnieszka.kostrzewa@gmail.com>
2017-06-26 17:54:35 +02:00
# Copyright (C) 2012 Marek Marczykowski-Górecki
# <marmarek@invisiblethingslab.com>
# Copyright (C) 2017 Wojtek Porczyk <woju@invisiblethingslab.com>
2012-01-31 11:17:09 +01:00
#
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
2017-06-26 17:54:35 +02:00
import collections
import copy
2017-06-28 13:41:10 +02:00
import os
2017-07-12 14:35:59 +02:00
import os . path
2012-01-31 11:17:09 +01:00
import subprocess
2017-07-12 14:35:59 +02:00
import sys
import threading
import time
import traceback
2017-06-26 17:54:35 +02:00
import qubesadmin
import qubesadmin . tools
2017-07-12 14:08:34 +02:00
from . import utils
2017-07-12 14:09:07 +02:00
from . import multiselectwidget
2017-07-12 14:35:59 +02:00
from . import thread_monitor
2012-01-31 11:17:09 +01:00
2017-07-12 14:09:07 +02:00
from . appmenu_select import AppmenuSelectManager
2017-06-28 12:25:28 +02:00
from . backup_utils import get_path_for_vm
2017-07-12 14:47:37 +02:00
from . firewall import *
2012-01-31 11:17:09 +01:00
2017-07-12 14:35:59 +02:00
from . ui_settingsdlg import *
2012-01-31 11:17:09 +01:00
class VMSettingsWindow ( Ui_SettingsDialog , QDialog ) :
2017-06-26 17:54:35 +02:00
tabs_indices = collections . OrderedDict ( (
( ' basic ' , 0 ) ,
( ' advanced ' , 1 ) ,
( ' firewall ' , 2 ) ,
( ' devices ' , 3 ) ,
( ' applications ' , 4 ) ,
( ' services ' , 5 ) ,
) )
def __init__ ( self , vm , qapp , init_page = " basic " , parent = None ) :
2012-01-31 11:17:09 +01:00
super ( VMSettingsWindow , self ) . __init__ ( parent )
2012-02-10 00:30:45 +01:00
self . vm = vm
2017-06-26 17:54:35 +02:00
self . qapp = qapp
2012-03-12 12:53:07 +01:00
if self . vm . template :
self . source_vm = self . vm . template
2012-02-10 00:30:45 +01:00
else :
self . source_vm = self . vm
2014-02-17 00:35:45 +01:00
2012-01-31 11:17:09 +01:00
self . setupUi ( self )
2017-06-28 12:25:28 +02:00
self . setWindowTitle ( self . tr ( " Settings: {vm} " ) . format ( vm = self . vm . name ) )
2012-02-09 19:47:21 +01:00
if init_page in self . tabs_indices :
idx = self . tabs_indices [ init_page ]
assert ( idx in range ( self . tabWidget . count ( ) ) )
self . tabWidget . setCurrentIndex ( idx )
2012-01-31 11:17:09 +01:00
self . connect ( self . buttonBox , SIGNAL ( " accepted() " ) , self . save_and_apply )
self . connect ( self . buttonBox , SIGNAL ( " rejected() " ) , self . reject )
2012-02-10 00:30:45 +01:00
self . tabWidget . currentChanged . connect ( self . current_tab_changed )
2017-07-12 14:47:37 +02:00
# self.tabWidget.setTabEnabled(self.tabs_indices["firewall"], vm.is_networked() and not vm.provides_network)
2012-03-08 15:40:02 +01:00
2012-02-13 13:50:30 +01:00
###### basic tab
self . __init_basic_tab__ ( )
2012-03-12 21:08:32 +01:00
###### advanced tab
self . __init_advanced_tab__ ( )
2012-03-19 16:02:05 +01:00
self . include_in_balancing . stateChanged . connect ( self . include_in_balancing_state_changed )
2014-09-16 21:25:52 +02:00
self . connect ( self . init_mem , SIGNAL ( " editingFinished() " ) , self . check_mem_changes )
self . connect ( self . max_mem_size , SIGNAL ( " editingFinished() " ) , self . check_mem_changes )
2014-02-17 00:53:47 +01:00
self . drive_path_button . clicked . connect ( self . drive_path_button_pressed )
2012-03-12 21:08:32 +01:00
2012-02-10 00:30:45 +01:00
###### firewall tab
2017-07-12 14:47:37 +02:00
if self . tabWidget . isTabEnabled ( self . tabs_indices [ ' firewall ' ] ) :
2012-03-08 15:40:02 +01:00
model = QubesFirewallRulesModel ( )
model . set_vm ( vm )
self . set_fw_model ( model )
2012-02-10 00:30:45 +01:00
2012-03-08 15:40:02 +01:00
self . newRuleButton . clicked . connect ( self . new_rule_button_pressed )
self . editRuleButton . clicked . connect ( self . edit_rule_button_pressed )
self . deleteRuleButton . clicked . connect ( self . delete_rule_button_pressed )
2014-03-28 05:19:07 +01:00
self . policyDenyRadioButton . clicked . connect ( self . policy_changed )
self . policyAllowRadioButton . clicked . connect ( self . policy_changed )
2012-02-10 00:30:45 +01:00
####### devices tab
2012-03-13 20:06:41 +01:00
self . __init_devices_tab__ ( )
2012-03-19 16:02:05 +01:00
self . connect ( self . dev_list , SIGNAL ( " selected_changed() " ) , self . devices_selection_changed )
2014-02-17 00:35:45 +01:00
2012-03-14 11:54:50 +01:00
####### services tab
self . __init_services_tab__ ( )
self . add_srv_button . clicked . connect ( self . __add_service__ )
self . remove_srv_button . clicked . connect ( self . __remove_service__ )
2012-02-10 00:30:45 +01:00
####### apps tab
2012-03-08 15:40:02 +01:00
if self . tabWidget . isTabEnabled ( self . tabs_indices [ " applications " ] ) :
2017-07-12 14:09:07 +02:00
self . app_list = multiselectwidget . MultiSelectWidget ( self )
2012-02-13 13:50:30 +01:00
self . apps_layout . addWidget ( self . app_list )
self . AppListManager = AppmenuSelectManager ( self . vm , self . app_list )
2012-01-31 11:17:09 +01:00
def reject ( self ) :
self . done ( 0 )
2012-02-09 19:47:21 +01:00
#needed not to close the dialog before applying changes
def accept ( self ) :
2012-01-31 11:17:09 +01:00
pass
2012-02-09 19:47:21 +01:00
def save_and_apply ( self ) :
2017-07-12 14:35:59 +02:00
t_monitor = thread_monitor . ThreadMonitor ( )
thread = threading . Thread ( target = self . __save_changes__ , args = ( t_monitor , ) )
2012-02-09 19:47:21 +01:00
thread . daemon = True
thread . start ( )
2014-02-17 00:35:45 +01:00
2017-01-22 05:42:38 +01:00
progress = QProgressDialog (
2017-06-28 12:25:28 +02:00
self . tr ( " Applying settings to <b> {0} </b>... " ) . format ( self . vm . name ) , " " , 0 , 0 )
2012-02-09 19:47:21 +01:00
progress . setCancelButton ( None )
progress . setModal ( True )
progress . show ( )
2017-07-12 14:35:59 +02:00
while not t_monitor . is_finished ( ) :
2017-06-26 17:54:35 +02:00
self . qapp . processEvents ( )
2012-02-09 19:47:21 +01:00
time . sleep ( 0.1 )
progress . hide ( )
2014-02-17 00:35:45 +01:00
2017-07-12 14:35:59 +02:00
if not t_monitor . success :
2017-01-22 05:42:38 +01:00
QMessageBox . warning ( None ,
2017-06-28 12:25:28 +02:00
self . tr ( " Error while changing settings for {0} ! " ) . format ( self . vm . name ) ,
2017-07-12 14:35:59 +02:00
self . tr ( " ERROR: {0} " ) . format ( t_monitor . error_msg ) )
2012-02-09 19:47:21 +01:00
self . done ( 0 )
2017-07-12 14:35:59 +02:00
def __save_changes__ ( self , t_monitor ) :
2012-03-01 22:50:32 +01:00
2012-03-12 15:54:16 +01:00
self . anything_changed = False
2014-02-17 00:35:45 +01:00
2013-02-23 06:44:06 +01:00
ret = [ ]
try :
ret_tmp = self . __apply_basic_tab__ ( )
if len ( ret_tmp ) > 0 :
ret + = [ " Basic tab: " ] + ret_tmp
ret_tmp = self . __apply_advanced_tab__ ( )
if len ( ret_tmp ) > 0 :
ret + = [ " Advanced tab: " ] + ret_tmp
ret_tmp = self . __apply_devices_tab__ ( )
if len ( ret_tmp ) > 0 :
ret + = [ " Devices tab: " ] + ret_tmp
ret_tmp = self . __apply_services_tab__ ( )
if len ( ret_tmp ) > 0 :
ret + = [ " Sevices tab: " ] + ret_tmp
except Exception as ex :
2017-01-22 05:42:38 +01:00
ret . append ( self . tr ( ' Error while saving changes: ' ) + str ( ex ) )
2012-03-12 15:54:16 +01:00
2013-02-23 06:44:06 +01:00
try :
if self . tabWidget . isTabEnabled ( self . tabs_indices [ " firewall " ] ) :
self . fw_model . apply_rules ( self . policyAllowRadioButton . isChecked ( ) ,
self . dnsCheckBox . isChecked ( ) ,
self . icmpCheckBox . isChecked ( ) ,
2014-03-28 05:19:07 +01:00
self . yumproxyCheckBox . isChecked ( ) ,
self . tempFullAccess . isChecked ( ) ,
self . tempFullAccessTime . value ( ) )
2017-04-24 01:59:00 +02:00
if self . fw_model . fw_changed :
# might modified vm.services
self . anything_changed = True
2013-02-23 06:44:06 +01:00
except Exception as ex :
2017-01-22 05:42:38 +01:00
ret + = [ self . tr ( " Firewall tab: " ) , str ( ex ) ]
2013-02-23 06:44:06 +01:00
try :
if self . tabWidget . isTabEnabled ( self . tabs_indices [ " applications " ] ) :
self . AppListManager . save_appmenu_select_changes ( )
except Exception as ex :
2017-01-22 05:42:38 +01:00
ret + = [ self . tr ( " Applications tab: " ) , str ( ex ) ]
2012-03-12 15:54:16 +01:00
2013-02-23 06:44:06 +01:00
if len ( ret ) > 0 :
2017-07-12 14:35:59 +02:00
t_monitor . set_error_msg ( ' \n ' . join ( ret ) )
2012-03-01 22:50:32 +01:00
2017-07-12 14:08:34 +02:00
utils . debug ( ' \n ' . join ( ret ) )
2012-02-09 19:47:21 +01:00
2017-07-12 14:35:59 +02:00
t_monitor . set_finished ( )
2012-03-01 22:50:32 +01:00
2012-02-10 00:30:45 +01:00
def current_tab_changed ( self , idx ) :
if idx == self . tabs_indices [ " firewall " ] :
2017-07-16 10:50:07 +02:00
netvm = self . vm . netvm
if netvm is not None and \
not netvm . features . check_with_template ( ' qubes-firewall ' , False ) :
2017-01-22 05:42:38 +01:00
QMessageBox . warning ( None ,
self . tr ( " VM configuration problem! " ) ,
2017-07-16 10:50:07 +02:00
self . tr ( " The ' {vm} ' AppVM is network connected to "
" ' {netvm} ' , which does not support firewall!<br/> "
" You may edit the ' {vm} ' VM firewall rules, but these "
" will not take any effect until you connect it to "
" a working Firewall VM. " ) . format (
vm = self . vm . name , netvm = netvm . name ) )
2012-02-10 00:30:45 +01:00
2012-02-13 13:50:30 +01:00
######### basic tab
2017-06-26 17:54:35 +02:00
# TODO LISTENERS
2017-07-12 14:08:34 +02:00
# - vm start/shutdown -> setEnabled on fields: template labels
2017-06-26 17:54:35 +02:00
# - vm create/delete -> choices lists, whole window deactiv (if self.vm)
# - property-set -> individual fields
# TODO INTERACTIONS
# netvm -> networking_groupbox
# hvm -> include_in_balancing
2017-07-12 14:08:34 +02:00
# TODO REMOVE
# other_groupbox
2017-06-26 17:54:35 +02:00
2012-02-13 13:50:30 +01:00
def __init_basic_tab__ ( self ) :
self . vmname . setText ( self . vm . name )
2012-08-23 03:57:19 +02:00
self . vmname . setValidator ( QRegExpValidator ( QRegExp ( " [a-zA-Z0-9-]* " , Qt . CaseInsensitive ) , None ) )
2017-06-26 17:54:35 +02:00
self . vmname . setEnabled ( False )
2014-02-17 00:35:45 +01:00
2012-04-27 11:54:53 +02:00
if self . vm . qid == 0 :
self . vmlabel . setVisible ( False )
2014-02-17 00:35:45 +01:00
else :
2017-07-12 14:08:34 +02:00
self . label_list , self . label_idx = utils . prepare_label_choice (
self . vmlabel ,
self . vm , ' label ' ,
None ,
allow_default = False
)
2012-04-27 11:54:53 +02:00
self . vmlabel . setVisible ( True )
2017-07-12 14:08:34 +02:00
self . vmlabel . setEnabled ( not self . vm . is_running ( ) )
2012-02-13 13:50:30 +01:00
2017-06-26 17:54:35 +02:00
if isinstance ( self . vm , qubesadmin . vm . AppVM ) :
2017-07-12 14:08:34 +02:00
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 )
2012-02-13 13:50:30 +01:00
else :
self . template_name . setEnabled ( False )
2012-03-12 21:08:32 +01:00
self . template_idx = - 1
2012-02-13 13:50:30 +01:00
2017-07-12 14:08:34 +02:00
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 )
2012-02-13 13:50:30 +01:00
2012-03-07 20:42:18 +01:00
self . include_in_backups . setChecked ( self . vm . include_in_backups )
2017-06-26 17:54:35 +02:00
try :
2012-04-24 14:27:28 +02:00
self . run_in_debug_mode . setChecked ( self . vm . debug )
2017-06-26 17:54:35 +02:00
self . run_in_debug_mode . setVisible ( True )
except AttributeError :
2012-04-24 14:27:28 +02:00
self . run_in_debug_mode . setVisible ( False )
2017-06-26 17:54:35 +02:00
try :
2014-05-17 19:21:00 +02:00
self . autostart_vm . setChecked ( self . vm . autostart )
2017-06-26 17:54:35 +02:00
self . autostart_vm . setVisible ( True )
except AttributeError :
2014-05-17 19:21:00 +02:00
self . autostart_vm . setVisible ( False )
2012-03-07 20:42:18 +01:00
#type
2017-06-26 17:54:35 +02:00
self . type_label . setText ( type ( self . vm ) . __name__ )
2012-03-07 20:42:18 +01:00
#installed by rpm
2017-06-26 17:54:35 +02:00
self . rpm_label . setText ( ' Yes ' if self . vm . installed_by_rpm else ' No ' )
2012-03-07 20:42:18 +01:00
2012-03-09 08:43:42 +01:00
#networking info
2017-06-26 17:54:35 +02:00
if self . vm . netvm :
2014-02-23 00:44:08 +01:00
self . networking_groupbox . setEnabled ( True )
2017-07-12 14:47:37 +02:00
self . ip_label . setText ( self . vm . ip or " none " )
self . netmask_label . setText ( self . vm . visible_netmask or " none " )
self . gateway_label . setText ( self . vm . visible_gateway or " none " )
2012-03-09 08:43:42 +01:00
else :
2014-02-23 00:44:08 +01:00
self . networking_groupbox . setEnabled ( False )
2012-03-09 08:43:42 +01:00
2012-03-14 12:51:11 +01:00
#max priv storage
2017-07-12 14:50:40 +02:00
self . priv_img_size = self . vm . volumes [ ' private ' ] . size / 10 * * 6
self . max_priv_storage . setMinimum ( self . priv_img_size )
self . max_priv_storage . setValue ( self . priv_img_size )
2012-03-09 08:43:42 +01:00
2017-07-12 14:50:40 +02:00
self . root_img_size = self . vm . volumes [ ' root ' ] . size / 10 * * 6
self . root_resize . setValue ( self . root_img_size )
self . root_resize . setMinimum ( self . root_img_size )
2017-06-26 17:54:35 +02:00
# self.root_resize.setEnabled(hasattr(self.vm, 'resize_root_img') and
# not self.vm.template)
2017-07-12 14:50:40 +02:00
self . root_resize_label . setEnabled ( self . root_resize . isEnabled ( ) )
2012-02-13 13:50:30 +01:00
def __apply_basic_tab__ ( self ) :
msg = [ ]
#vm label changed
2013-02-23 06:44:06 +01:00
try :
if self . vmlabel . isVisible ( ) :
if self . vmlabel . currentIndex ( ) != self . label_idx :
label = self . label_list [ self . vmlabel . currentIndex ( ) ]
self . vm . label = label
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-02-13 13:50:30 +01:00
2012-03-07 17:03:19 +01:00
#vm template changed
2013-02-23 06:44:06 +01:00
try :
if self . template_name . currentIndex ( ) != self . template_idx :
2017-06-26 17:54:35 +02:00
self . vm . template = \
self . template_list [ self . template_name . currentIndex ( ) ]
2013-02-23 06:44:06 +01:00
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-02-13 13:50:30 +01:00
2012-03-07 18:15:59 +01:00
#vm netvm changed
2013-02-23 06:44:06 +01:00
try :
if self . netVM . currentIndex ( ) != self . netvm_idx :
2017-06-26 17:54:35 +02:00
self . vm . netvm = self . netvm_list [ self . netVM . currentIndex ( ) ]
2013-02-23 06:44:06 +01:00
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-03-07 20:42:18 +01:00
#include in backups
2013-02-23 06:44:06 +01:00
try :
if self . vm . include_in_backups != self . include_in_backups . isChecked ( ) :
self . vm . include_in_backups = self . include_in_backups . isChecked ( )
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-04-24 14:27:28 +02:00
#run_in_debug_mode
2013-02-23 06:44:06 +01:00
try :
if self . run_in_debug_mode . isVisible ( ) :
if self . vm . debug != self . run_in_debug_mode . isChecked ( ) :
self . vm . debug = self . run_in_debug_mode . isChecked ( )
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-03-07 18:15:59 +01:00
2014-05-17 19:21:00 +02:00
#autostart_vm
try :
if self . autostart_vm . isVisible ( ) :
if self . vm . autostart != self . autostart_vm . isChecked ( ) :
self . vm . autostart = self . autostart_vm . isChecked ( )
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-03-14 12:51:11 +01:00
#max priv storage
priv_size = self . max_priv_storage . value ( )
if self . priv_img_size != priv_size :
try :
2017-07-12 14:50:40 +02:00
self . vm . volumes [ ' private ' ] . resize ( priv_size * 10 * * 6 )
2012-03-14 12:51:11 +01:00
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2014-03-21 18:40:23 +01:00
#max sys storage
sys_size = self . root_resize . value ( )
if self . root_img_size != sys_size :
try :
2017-07-12 14:50:40 +02:00
self . vm . volumes [ ' root ' ] . resize ( priv_size * 10 * * 6 )
2014-03-21 18:40:23 +01:00
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-03-07 21:21:14 +01:00
2012-03-07 18:15:59 +01:00
return msg
2012-03-12 21:08:32 +01:00
2014-09-16 21:25:52 +02:00
def check_mem_changes ( self ) :
2013-10-29 13:41:46 +01:00
if self . max_mem_size . value ( ) < self . init_mem . value ( ) :
2017-01-22 05:42:38 +01:00
QMessageBox . warning ( None ,
self . tr ( " Warning! " ) ,
self . tr ( " Max memory can not be less than initial memory.<br> "
" Setting max memory to equal initial memory. " ) )
2013-10-29 13:41:46 +01:00
self . max_mem_size . setValue ( self . init_mem . value ( ) )
2014-09-16 21:25:52 +02:00
# Linux specific limit: init memory must not be below max_mem_size/10.79 in order to allow scaling up to max_mem_size (or else "add_memory() failed: -17" problem)
if self . init_mem . value ( ) * 10 < self . max_mem_size . value ( ) :
2017-01-22 05:42:38 +01:00
QMessageBox . warning ( None ,
self . tr ( " Warning! " ) ,
self . tr ( " Initial memory can not be less than one tenth "
" Max memory.<br>Setting initial memory to the minimum "
" allowed value. " ) )
2014-09-16 21:25:52 +02:00
self . init_mem . setValue ( self . max_mem_size . value ( ) / 10 )
2013-10-29 13:41:46 +01:00
2012-05-19 09:33:29 +02:00
2012-03-12 21:08:32 +01:00
######### advanced tab
def __init_advanced_tab__ ( self ) :
2012-03-13 22:05:50 +01:00
#mem/cpu
2017-06-26 17:54:35 +02:00
# qubes_memory = QubesHost().memory_total/1024
2012-05-19 09:33:29 +02:00
2012-03-14 12:51:11 +01:00
self . init_mem . setValue ( int ( self . vm . memory ) )
2017-06-26 17:54:35 +02:00
# self.init_mem.setMaximum(qubes_memory)
2012-03-13 22:05:50 +01:00
self . max_mem_size . setValue ( int ( self . vm . maxmem ) )
2017-06-26 17:54:35 +02:00
# self.max_mem_size.setMaximum(qubes_memory)
2012-03-13 22:05:50 +01:00
2014-02-23 00:44:08 +01:00
self . vcpus . setMinimum ( 1 )
2017-06-26 17:54:35 +02:00
# self.vcpus.setMaximum(QubesHost().no_cpus)
2012-03-13 22:05:50 +01:00
self . vcpus . setValue ( int ( self . vm . vcpus ) )
2017-07-14 02:19:24 +02:00
self . include_in_balancing . setEnabled ( True )
self . include_in_balancing . setChecked (
self . vm . features . get ( ' services.meminfo-writer ' , True ) )
2013-10-29 13:41:46 +01:00
self . max_mem_size . setEnabled ( self . include_in_balancing . isChecked ( ) )
2012-04-18 19:33:53 +02:00
2017-06-26 17:54:35 +02:00
try :
2017-07-12 14:08:34 +02:00
self . root_img_path . setText ( ' {volume.pool} : {volume.vid} ' . format (
volume = self . vm . volumes [ ' root ' ] ) )
2017-06-26 17:54:35 +02:00
except AttributeError :
2012-04-18 19:33:53 +02:00
self . root_img_path . setText ( " n/a " )
2017-06-26 17:54:35 +02:00
try :
2017-07-12 14:08:34 +02:00
self . volatile_img_path . setText ( ' {volume.pool} : {volume.vid} ' . format (
volume = self . vm . volumes [ ' volatile ' ] ) )
2017-06-26 17:54:35 +02:00
except AttributeError :
2012-04-24 19:05:15 +02:00
self . volatile_img_path . setText ( ' n/a ' )
2017-07-12 14:08:34 +02:00
self . private_img_path . setText ( ' {volume.pool} : {volume.vid} ' . format (
volume = self . vm . volumes [ ' private ' ] ) )
2012-04-18 19:33:53 +02:00
2012-03-12 21:08:32 +01:00
#kernel
2012-04-18 19:33:53 +02:00
2012-04-24 15:02:19 +02:00
#in case VM is HVM
2017-07-12 14:08:34 +02:00
if hasattr ( self . vm , " kernel " ) :
2014-02-17 00:40:28 +01:00
self . kernel_groupbox . setVisible ( True )
2017-07-12 14:08:34 +02:00
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 )
2012-03-12 21:08:32 +01:00
2014-02-17 00:53:47 +01:00
if not hasattr ( self . vm , " drive " ) :
self . drive_groupbox . setVisible ( False )
else :
self . drive_groupbox . setVisible ( True )
self . drive_groupbox . setChecked ( self . vm . drive is not None )
self . drive_running_warning . setVisible ( self . vm . is_running ( ) )
self . drive_type . addItems ( [ " hd " , " cdrom " ] )
self . drive_type . setCurrentIndex ( 0 )
2017-06-26 17:54:35 +02:00
vm_list = [ vm for vm in self . app . values ( ) if not vm
2014-02-17 00:53:47 +01:00
. internal and vm . qid != self . vm . qid ]
# default to dom0 (in case of nonexisting vm already set...)
self . drive_domain_idx = 0
for ( i , vm ) in enumerate ( sorted ( vm_list , key = lambda v : v . name ) ) :
if vm . qid == 0 :
self . drive_domain_idx = i
self . drive_domain . insertItem ( i , vm . name )
if self . vm . drive is not None :
( drv_type , drv_domain , drv_path ) = self . vm . drive . split ( " : " )
if drv_type == " cdrom " :
self . drive_type . setCurrentIndex ( 1 )
else :
self . drive_type . setCurrentIndex ( 0 )
for i in xrange ( self . drive_domain . count ( ) ) :
if drv_domain == self . drive_domain . itemText ( i ) :
self . drive_domain_idx = i
self . drive_path . setText ( drv_path )
self . drive_domain . setCurrentIndex ( self . drive_domain_idx )
2017-07-12 14:47:37 +02:00
self . other_groupbox . setVisible ( False )
2017-07-14 02:19:24 +02:00
if not hasattr ( self . vm , ' default_dispvm ' ) :
self . other_groupbox . setVisible ( False )
else :
self . other_groupbox . setVisible ( True )
self . default_dispvm_list , self . default_dispvm_idx = \
utils . prepare_vm_choice (
self . default_dispvm ,
self . vm , ' default_dispvm ' ,
self . vm . app . default_dispvm ,
( lambda vm : isinstance ( vm , qubesadmin . vm . DispVM ) ) ,
allow_default = True , allow_none = True )
2015-04-06 00:59:15 +02:00
2012-03-12 21:08:32 +01:00
def __apply_advanced_tab__ ( self ) :
2013-02-23 06:44:06 +01:00
msg = [ ]
2012-03-12 21:08:32 +01:00
2012-03-13 22:05:50 +01:00
#mem/cpu
2013-02-23 06:44:06 +01:00
try :
if self . init_mem . value ( ) != int ( self . vm . memory ) :
self . vm . memory = self . init_mem . value ( )
self . anything_changed = True
2012-03-14 12:51:11 +01:00
2013-02-23 06:44:06 +01:00
if self . max_mem_size . value ( ) != int ( self . vm . maxmem ) :
self . vm . maxmem = self . max_mem_size . value ( )
self . anything_changed = True
2012-03-13 22:05:50 +01:00
2013-02-23 06:44:06 +01:00
if self . vcpus . value ( ) != int ( self . vm . vcpus ) :
self . vm . vcpus = self . vcpus . value ( )
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2012-03-13 22:05:50 +01:00
2012-03-30 21:46:23 +02:00
#include_in_memory_balancing applied in services tab
2012-04-18 19:33:53 +02:00
#in case VM is not Linux
2014-02-17 00:40:28 +01:00
if hasattr ( self . vm , " kernel " ) and self . kernel_groupbox . isVisible ( ) :
try :
if self . kernel . currentIndex ( ) != self . kernel_idx :
2014-07-05 14:57:47 +02:00
new_kernel = str ( self . kernel . currentText ( ) )
2014-02-17 00:40:28 +01:00
new_kernel = new_kernel . split ( ' ' ) [ 0 ]
2017-05-26 07:40:14 +02:00
uses_default_kernel = False
2014-02-17 00:40:28 +01:00
if new_kernel == " default " :
2017-06-26 17:54:35 +02:00
kernel = self . app . get_default_kernel ( )
2017-05-26 07:40:14 +02:00
uses_default_kernel = True
2014-02-17 00:40:28 +01:00
elif new_kernel == " none " :
kernel = None
else :
kernel = new_kernel
self . vm . kernel = kernel
2017-05-26 07:40:14 +02:00
# Set self.vm.uses_default_kernel after self.vm.kernel to ensure that
# the correct value persists after QubesVm.kernel resets self.vm.uses_default_kernel
# to False.
self . vm . uses_default_kernel = uses_default_kernel
2014-02-17 00:40:28 +01:00
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2013-02-23 06:44:06 +01:00
2017-07-14 02:19:24 +02:00
#vm default_dispvm changed
try :
if self . default_dispvm . currentIndex ( ) != self . default_dispvm_idx :
self . vm . default_dispvm = \
self . default_dispvm_list [ self . default_dispvm . currentIndex ( ) ]
self . anything_changed = True
except Exception as ex :
msg . append ( str ( ex ) )
2013-02-23 06:44:06 +01:00
return msg
2012-03-12 21:08:32 +01:00
2014-02-17 00:53:47 +01:00
def drive_path_button_pressed ( self ) :
2014-07-05 14:57:47 +02:00
if str ( self . drive_domain . currentText ( ) ) in [ " dom0 " , " dom0 (current) " ] :
2014-02-17 00:53:47 +01:00
file_dialog = QFileDialog ( )
file_dialog . setReadOnly ( True )
new_path = file_dialog . getOpenFileName ( self , " Select drive image " ,
str ( self . drive_path . text ( ) ) )
else :
drv_domain = str ( self . drive_domain . currentText ( ) )
if drv_domain . count ( " (current) " ) > 0 :
drv_domain = drv_domain . split ( ' ' ) [ 0 ]
2017-06-26 17:54:35 +02:00
backend_vm = self . app . get_vm_by_name ( drv_domain )
2014-02-17 00:53:47 +01:00
if backend_vm :
new_path = get_path_for_vm ( backend_vm , " qubes.SelectFile " )
2014-09-09 21:59:54 +02:00
if new_path :
self . drive_path . setText ( new_path )
2014-02-17 00:53:47 +01:00
2012-03-13 20:06:41 +01:00
######## devices tab
def __init_devices_tab__ ( self ) :
2017-07-12 14:52:56 +02:00
self . dev_list = multiselectwidget . MultiSelectWidget ( self )
2014-11-01 19:57:17 +01:00
self . dev_list . add_all_button . setVisible ( False )
2012-03-13 20:06:41 +01:00
self . devices_layout . addWidget ( self . dev_list )
2014-02-17 00:35:45 +01:00
2012-03-13 20:06:41 +01:00
devs = [ ]
2017-07-12 14:52:56 +02:00
lspci = subprocess . check_output ( [ ' /usr/sbin/lspci ' ] ) . decode ( )
for dev in lspci . splitlines ( ) :
devs . append ( ( dev . rstrip ( ) , dev . split ( ' ' ) [ 0 ] ) )
2012-03-13 20:06:41 +01:00
class DevListWidgetItem ( QListWidgetItem ) :
2017-07-12 14:52:56 +02:00
def __init__ ( self , name , ident , parent = None ) :
2012-03-13 20:06:41 +01:00
super ( DevListWidgetItem , self ) . __init__ ( name , parent )
2017-07-12 14:52:56 +02:00
self . ident = ident
2014-11-01 19:57:17 +01:00
self . Type
2012-03-13 20:06:41 +01:00
2017-07-12 14:52:56 +02:00
persistent = [ ass . ident . replace ( ' _ ' , ' : ' )
for ass in self . vm . devices [ ' pci ' ] . persistent ( ) ]
for name , ident in devs :
if ident in persistent :
self . dev_list . selected_list . addItem (
DevListWidgetItem ( name , ident ) )
2012-03-13 20:06:41 +01:00
else :
2017-07-12 14:52:56 +02:00
self . dev_list . available_list . addItem (
DevListWidgetItem ( name , ident ) )
2012-03-13 20:06:41 +01:00
2012-03-19 21:07:27 +01:00
if self . dev_list . selected_list . count ( ) > 0 and self . include_in_balancing . isChecked ( ) :
self . dmm_warning_adv . show ( )
self . dmm_warning_dev . show ( )
else :
self . dmm_warning_adv . hide ( )
self . dmm_warning_dev . hide ( )
2012-04-17 13:15:18 +02:00
if self . vm . is_running ( ) :
self . dev_list . setEnabled ( False )
self . turn_off_vm_to_modify_devs . setVisible ( True )
else :
self . dev_list . setEnabled ( True )
self . turn_off_vm_to_modify_devs . setVisible ( False )
2012-03-13 20:06:41 +01:00
def __apply_devices_tab__ ( self ) :
2013-02-23 06:44:06 +01:00
msg = [ ]
2012-03-13 20:06:41 +01:00
2013-02-23 06:44:06 +01:00
try :
2017-07-12 14:52:56 +02:00
old = [ ass . ident . replace ( ' _ ' , ' : ' )
for ass in self . vm . devices [ ' pci ' ] . persistent ( ) ]
new = [ self . dev_list . selected_list . item ( i ) . ident
for i in range ( self . dev_list . selected_list . count ( ) ) ]
for ident in new :
if ident not in old :
ass = qubesadmin . devices . DeviceAssignment (
self . vm . app . domains [ ' dom0 ' ] ,
ident . replace ( ' : ' , ' _ ' ) ,
persistent = True )
self . vm . devices [ ' pci ' ] . attach ( ass )
for ass in self . vm . devices [ ' pci ' ] . assignments ( persistent = True ) :
if ass . ident . replace ( ' _ ' , ' : ' ) not in new :
self . vm . devices [ ' pci ' ] . detach ( ass )
self . anything_changed = True
2013-02-23 06:44:06 +01:00
except Exception as ex :
2017-07-12 14:08:34 +02:00
if utils . is_debug ( ) :
traceback . print_exc ( )
2013-02-23 06:44:06 +01:00
msg . append ( str ( ex ) )
return msg
2012-03-13 20:06:41 +01:00
2012-03-19 16:02:05 +01:00
def include_in_balancing_state_changed ( self , state ) :
2012-03-30 21:46:23 +02:00
for r in range ( self . services_list . count ( ) ) :
item = self . services_list . item ( r )
if str ( item . text ( ) ) == ' meminfo-writer ' :
item . setCheckState ( state )
2014-02-23 00:44:08 +01:00
break
2012-03-30 21:46:23 +02:00
2012-03-19 21:07:27 +01:00
if self . dev_list . selected_list . count ( ) > 0 :
if state == QtCore . Qt . Checked :
self . dmm_warning_adv . show ( )
self . dmm_warning_dev . show ( )
else :
self . dmm_warning_adv . hide ( )
self . dmm_warning_dev . hide ( )
2013-10-29 13:39:14 +01:00
self . max_mem_size . setEnabled ( self . include_in_balancing . isChecked ( ) )
2012-03-30 21:46:23 +02:00
2012-03-19 16:02:05 +01:00
def devices_selection_changed ( self ) :
2012-03-19 21:07:27 +01:00
if self . include_in_balancing . isChecked ( ) :
if self . dev_list . selected_list . count ( ) > 0 :
self . dmm_warning_adv . show ( )
self . dmm_warning_dev . show ( )
else :
self . dmm_warning_adv . hide ( )
self . dmm_warning_dev . hide ( )
2012-03-14 11:54:50 +01:00
######## services tab
def __init_services_tab__ ( self ) :
2017-07-12 14:52:05 +02:00
self . new_srv_dict = { }
for feature in self . vm . features :
if not feature . startswith ( ' service. ' ) :
continue
service = feature [ len ( ' service. ' ) : ]
item = QListWidgetItem ( service )
item . setCheckState ( QtCore . Qt . Checked
if self . vm . features [ feature ] else QtCore . Qt . Unchecked )
2012-03-14 11:54:50 +01:00
self . services_list . addItem ( item )
2017-07-12 14:52:05 +02:00
self . new_srv_dict [ service ] = self . vm . features [ feature ]
2013-02-23 06:44:06 +01:00
2012-03-30 21:46:23 +02:00
self . connect ( self . services_list , SIGNAL ( " itemClicked(QListWidgetItem *) " ) , self . services_item_clicked )
2012-03-14 11:54:50 +01:00
def __add_service__ ( self ) :
srv = str ( self . service_line_edit . text ( ) ) . strip ( )
2012-03-30 21:46:23 +02:00
if srv != " " :
if srv in self . new_srv_dict :
2017-07-12 14:52:05 +02:00
QMessageBox . information ( None , ' ' ,
self . tr ( ' Service already on the list! ' ) )
2012-03-30 21:46:23 +02:00
else :
item = QListWidgetItem ( srv )
item . setCheckState ( QtCore . Qt . Checked )
self . services_list . addItem ( item )
self . new_srv_dict [ srv ] = True
2012-03-14 11:54:50 +01:00
def __remove_service__ ( self ) :
2012-03-30 21:46:23 +02:00
item = self . services_list . currentItem ( )
2014-09-04 21:59:05 +02:00
if not item :
return
2014-02-17 00:35:45 +01:00
if str ( item . text ( ) ) == ' meminfo-writer ' :
2017-01-22 05:42:38 +01:00
QMessageBox . information ( None ,
2017-07-12 14:52:05 +02:00
self . tr ( ' Service can not be removed ' ) ,
self . tr ( ' Service meminfo-writer can not be removed from the list. ' ) )
2014-09-04 21:59:05 +02:00
return
row = self . services_list . currentRow ( )
item = self . services_list . takeItem ( row )
del self . new_srv_dict [ str ( item . text ( ) ) ]
2012-03-14 11:54:50 +01:00
2012-03-30 21:46:23 +02:00
def services_item_clicked ( self , item ) :
if str ( item . text ( ) ) == ' meminfo-writer ' :
if item . checkState ( ) == QtCore . Qt . Checked :
if not self . include_in_balancing . isChecked ( ) :
self . include_in_balancing . setChecked ( True )
elif item . checkState ( ) == QtCore . Qt . Unchecked :
if self . include_in_balancing . isChecked ( ) :
self . include_in_balancing . setChecked ( False )
2012-03-14 11:54:50 +01:00
def __apply_services_tab__ ( self ) :
2013-02-23 06:44:06 +01:00
msg = [ ]
2012-03-30 21:46:23 +02:00
2013-02-23 06:44:06 +01:00
try :
2017-07-12 14:52:05 +02:00
for r in range ( self . services_list . count ( ) ) :
2013-02-23 06:44:06 +01:00
item = self . services_list . item ( r )
self . new_srv_dict [ str ( item . text ( ) ) ] = ( item . checkState ( ) == QtCore . Qt . Checked )
2012-03-30 21:46:23 +02:00
2017-07-12 14:52:05 +02:00
balancing_was_checked = self . vm . features . get ( ' service.meminfo-writer ' , True )
balancing_is_checked = self . include_in_balancing . isChecked ( )
meminfo_writer_checked = self . new_srv_dict . get ( ' meminfo-writer ' , True )
2013-02-23 06:44:06 +01:00
if balancing_is_checked != meminfo_writer_checked :
if balancing_is_checked != balancing_was_checked :
self . new_srv_dict [ ' meminfo-writer ' ] = balancing_is_checked
2017-07-12 14:52:05 +02:00
for service , v in self . new_srv_dict . items ( ) :
feature = ' service. ' + service
if v != self . vm . features . get ( feature , object ( ) ) :
self . vm . features [ feature ] = v
self . anything_changed = True
for feature in self . vm . features :
if not feature . startswith ( ' service. ' ) :
continue
service = feature [ len ( ' service. ' ) : ]
if service not in self . new_srv_dict :
del self . vm . features [ feature ]
2013-02-23 06:44:06 +01:00
except Exception as ex :
msg . append ( str ( ex ) )
return msg
2012-03-14 11:54:50 +01:00
2012-02-10 00:30:45 +01:00
######### firewall tab related
def set_fw_model ( self , model ) :
self . fw_model = model
self . rulesTreeView . setModel ( model )
self . rulesTreeView . header ( ) . setResizeMode ( QHeaderView . ResizeToContents )
self . rulesTreeView . header ( ) . setResizeMode ( 0 , QHeaderView . Stretch )
self . set_allow ( model . allow )
self . dnsCheckBox . setChecked ( model . allowDns )
self . icmpCheckBox . setChecked ( model . allowIcmp )
2012-06-05 20:29:57 +02:00
self . yumproxyCheckBox . setChecked ( model . allowYumProxy )
2014-03-28 05:19:07 +01:00
if model . tempFullAccessExpireTime :
self . tempFullAccess . setChecked ( True )
self . tempFullAccessTime . setValue (
( model . tempFullAccessExpireTime -
int ( datetime . datetime . now ( ) . strftime ( " %s " ) ) ) / 60 )
2012-02-10 00:30:45 +01:00
def set_allow ( self , allow ) :
self . policyAllowRadioButton . setChecked ( allow )
self . policyDenyRadioButton . setChecked ( not allow )
2014-03-28 05:19:07 +01:00
self . policy_changed ( allow )
def policy_changed ( self , checked ) :
self . tempFullAccessWidget . setEnabled ( self . policyDenyRadioButton . isChecked ( ) )
2014-02-17 00:35:45 +01:00
2012-02-10 00:30:45 +01:00
def new_rule_button_pressed ( self ) :
dialog = NewFwRuleDlg ( )
self . run_rule_dialog ( dialog )
def edit_rule_button_pressed ( self ) :
dialog = NewFwRuleDlg ( )
dialog . set_ok_enabled ( True )
selected = self . rulesTreeView . selectedIndexes ( )
if len ( selected ) > 0 :
row = self . rulesTreeView . selectedIndexes ( ) . pop ( ) . row ( )
address = self . fw_model . get_column_string ( 0 , row ) . replace ( ' ' , ' ' )
dialog . addressComboBox . setItemText ( 0 , address )
dialog . addressComboBox . setCurrentIndex ( 0 )
service = self . fw_model . get_column_string ( 1 , row )
2012-03-04 17:36:25 +01:00
if service == " any " :
service = " "
2012-02-10 00:30:45 +01:00
dialog . serviceComboBox . setItemText ( 0 , service )
dialog . serviceComboBox . setCurrentIndex ( 0 )
2012-03-04 17:36:25 +01:00
protocol = self . fw_model . get_column_string ( 2 , row )
if protocol == " tcp " :
dialog . tcp_radio . setChecked ( True )
elif protocol == " udp " :
dialog . udp_radio . setChecked ( True )
else :
dialog . any_radio . setChecked ( True )
2012-02-10 00:30:45 +01:00
self . run_rule_dialog ( dialog , row )
def delete_rule_button_pressed ( self ) :
for i in set ( [ index . row ( ) for index in self . rulesTreeView . selectedIndexes ( ) ] ) :
self . fw_model . removeChild ( i )
def run_rule_dialog ( self , dialog , row = None ) :
if dialog . exec_ ( ) :
address = str ( dialog . addressComboBox . currentText ( ) )
service = str ( dialog . serviceComboBox . currentText ( ) )
port = None
port2 = None
unmask = address . split ( " / " , 1 )
if len ( unmask ) == 2 :
address = unmask [ 0 ]
netmask = int ( unmask [ 1 ] )
else :
netmask = 32
if address == " * " :
address = " 0.0.0.0 "
netmask = 0
2012-03-04 17:36:25 +01:00
if dialog . any_radio . isChecked ( ) :
protocol = " any "
port = 0
else :
if dialog . tcp_radio . isChecked ( ) :
protocol = " tcp "
elif dialog . udp_radio . isChecked ( ) :
protocol = " udp "
2014-03-28 05:15:52 +01:00
else :
protocol = " any "
2014-02-17 00:35:45 +01:00
2012-03-04 17:36:25 +01:00
try :
range = service . split ( " - " , 1 )
if len ( range ) == 2 :
port = int ( range [ 0 ] )
port2 = int ( range [ 1 ] )
else :
port = int ( service )
except ( TypeError , ValueError ) as ex :
port = self . fw_model . get_service_port ( service )
2012-02-10 00:30:45 +01:00
if port is not None :
if port2 is not None and port2 < = port :
2017-01-22 05:42:38 +01:00
QMessageBox . warning ( None , self . tr ( " Invalid service ports range " ) ,
2017-06-28 12:25:28 +02:00
self . tr ( " Port {0} is lower than port {1} . " ) . format (
2017-01-22 05:42:38 +01:00
port2 , port ) )
2012-02-10 00:30:45 +01:00
else :
2014-03-28 05:15:52 +01:00
item = { " address " : address ,
" netmask " : netmask ,
" portBegin " : port ,
" portEnd " : port2 ,
" proto " : protocol ,
}
2012-02-10 00:30:45 +01:00
if row is not None :
self . fw_model . setChild ( row , item )
else :
self . fw_model . appendChild ( item )
else :
2017-01-22 05:42:38 +01:00
QMessageBox . warning ( None , self . tr ( " Invalid service name " ) ,
2017-06-28 12:25:28 +02:00
self . tr ( " Service ' {0} ' is unknown. " ) . format ( service ) )
2012-02-10 00:30:45 +01:00
2012-02-09 19:47:21 +01:00
2012-01-31 11:17:09 +01:00
# Bases on the original code by:
# Copyright (c) 2002-2007 Pascal Varet <p.varet@gmail.com>
2017-06-26 17:54:35 +02:00
def handle_exception ( exc_type , exc_value , exc_traceback ) :
2012-01-31 11:17:09 +01:00
2017-06-26 17:54:35 +02:00
filename , line , dummy , dummy = traceback . extract_tb ( exc_traceback ) . pop ( )
filename = os . path . basename ( filename )
error = " %s : %s " % ( exc_type . __name__ , exc_value )
2012-01-31 11:17:09 +01:00
2012-03-14 14:00:49 +01:00
strace = " "
2017-06-26 17:54:35 +02:00
stacktrace = traceback . extract_tb ( exc_traceback )
2012-03-14 14:00:49 +01:00
while len ( stacktrace ) > 0 :
( filename , line , func , txt ) = stacktrace . pop ( )
strace + = " ---- \n "
strace + = " line: %s \n " % txt
strace + = " func: %s \n " % func
strace + = " line no.: %d \n " % line
strace + = " file: %s \n " % filename
msg_box = QMessageBox ( )
msg_box . setDetailedText ( strace )
msg_box . setIcon ( QMessageBox . Critical )
2017-06-26 17:54:35 +02:00
msg_box . setWindowTitle ( " Houston, we have a problem... " )
2012-03-14 14:00:49 +01:00
msg_box . setText ( " Whoops. A critical error has occured. This is most likely a bug "
" in Qubes Manager.<br><br> "
" <b><i> %s </i></b> " % error +
" <br/>at line <b> %d </b><br/>of file %s .<br/><br/> "
% ( line , filename ) )
2014-02-17 00:35:45 +01:00
2012-03-14 14:00:49 +01:00
msg_box . exec_ ( )
2012-01-31 11:17:09 +01:00
2017-06-26 17:54:35 +02:00
parser = qubesadmin . tools . QubesArgumentParser ( vmname_nargs = 1 )
2017-06-28 13:41:10 +02:00
2017-06-26 17:54:35 +02:00
parser . add_argument ( ' --tab ' , metavar = ' TAB ' ,
action = ' store ' ,
choices = VMSettingsWindow . tabs_indices . keys ( ) )
2017-06-28 13:41:10 +02:00
parser . set_defaults (
tab = ' basic ' ,
)
2012-01-31 11:17:09 +01:00
2017-06-26 17:54:35 +02:00
def main ( args = None ) :
global settings_window
2012-01-31 11:17:09 +01:00
2017-06-26 17:54:35 +02:00
args = parser . parse_args ( args )
vm = args . domains . pop ( )
2012-01-31 11:17:09 +01:00
2017-06-26 17:54:35 +02:00
qapp = QApplication ( sys . argv )
qapp . setOrganizationName ( ' Invisible Things Lab ' )
qapp . setOrganizationDomain ( " https://www.qubes-os.org/ " )
qapp . setApplicationName ( " Qubes VM Settings " )
2012-02-09 19:47:21 +01:00
2017-07-12 14:08:34 +02:00
if not utils . is_debug ( ) :
2017-06-28 13:41:10 +02:00
sys . excepthook = handle_exception
2012-01-31 11:17:09 +01:00
2017-06-26 17:54:35 +02:00
settings_window = VMSettingsWindow ( vm , qapp , args . tab )
2012-01-31 11:17:09 +01:00
settings_window . show ( )
2017-06-26 17:54:35 +02:00
qapp . exec_ ( )
qapp . exit ( )
2012-01-31 11:17:09 +01:00
if __name__ == " __main__ " :
main ( )
2012-05-19 09:33:29 +02:00
# vim:sw=4:et: