Merge branch 'master' of git://git.qubes-os.org/aga/qubes-manager

This commit is contained in:
Marek Marczykowski 2012-04-04 10:01:29 +02:00
commit 33b97aa8a7
5 changed files with 231 additions and 53 deletions

View File

@ -22,20 +22,80 @@
<widget class="QWizardPage" name="select_vms_page">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
<underline>false</underline>
</font>
</property>
<property name="text">
<string>Select VMs to backup:</string>
</property>
</widget>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QPushButton" name="shutdown_running_vms_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Shutdown all running selected VMs</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/shutdownvm.png</normaloff>:/shutdownvm.png</iconset>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="refresh_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Refresh running states.</string>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="2">
<widget class="QLabel" name="running_vms_warning">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color:rgb(255, 0, 0)</string>
</property>
<property name="text">
<string>Some of the selected VMs are running (red). Running VMs can not be backuped!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
<underline>false</underline>
</font>
</property>
<property name="text">
<string>Select VMs to backup:</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -187,6 +247,8 @@ p, li { white-space: pre-wrap; }
</layout>
</widget>
</widget>
<resources/>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -54,12 +54,13 @@ class BackupVMsWindow(Ui_Backup, QWizard):
__pyqtSignals__ = ("backup_progress(int)",)
def __init__(self, app, qvm_collection, blk_manager, parent=None):
def __init__(self, app, qvm_collection, blk_manager, shutdown_vm_func, parent=None):
super(BackupVMsWindow, self).__init__(parent)
self.app = app
self.qvm_collection = qvm_collection
self.blk_manager = blk_manager
self.shutdown_vm_func = shutdown_vm_func
self.dev_mount_path = None
self.backup_dir = None
@ -75,12 +76,16 @@ class BackupVMsWindow(Ui_Backup, QWizard):
self.setupUi(self)
self.show_running_vms_warning(False)
self.dir_line_edit.setReadOnly(True)
self.select_vms_widget = MultiSelectWidget(self)
self.verticalLayout.insertWidget(1, self.select_vms_widget)
self.connect(self, SIGNAL("currentIdChanged(int)"), self.current_page_changed)
self.connect(self.select_vms_widget, SIGNAL("selected_changed()"), self.check_running)
self.refresh_button.clicked.connect(self.check_running)
self.shutdown_running_vms_button.clicked.connect(self.shutdown_all_running_selected)
self.connect(self.dev_combobox, SIGNAL("activated(int)"), self.dev_combobox_activated)
self.connect(self, SIGNAL("backup_progress(int)"), self.progress_bar.setValue)
@ -93,26 +98,92 @@ class BackupVMsWindow(Ui_Backup, QWizard):
self.__fill_vms_list__()
fill_devs_list(self)
def show_running_vms_warning(self, show):
self.running_vms_warning.setVisible(show)
self.shutdown_running_vms_button.setVisible(show)
self.refresh_button.setVisible(show)
class VmListItem(QListWidgetItem):
def __init__(self, vm):
super(BackupVMsWindow.VmListItem, self).__init__(vm.name)
self.vm = vm
def __fill_vms_list__(self):
for vm in self.qvm_collection.values():
if vm.is_running() and vm.qid != 0:
self.excluded.append(vm.name)
continue
if vm.is_appvm() and vm.internal:
self.excluded.append(vm.name)
continue
if vm.is_template() and vm.installed_by_rpm:
self.excluded.append(vm.name)
continue
item = BackupVMsWindow.VmListItem(vm)
if vm.include_in_backups == True:
self.select_vms_widget.selected_list.addItem(vm.name)
self.select_vms_widget.selected_list.addItem(item)
else:
self.select_vms_widget.available_list.addItem(vm.name)
self.select_vms_widget.available_list.addItem(item)
self.check_running()
def check_running(self):
some_selected_vms_running = False
for i in range(self.select_vms_widget.selected_list.count()):
item = self.select_vms_widget.selected_list.item(i)
if item.vm.is_running() and item.vm.qid != 0:
item.setForeground(QBrush(QColor(255, 0, 0)))
some_selected_vms_running = True
else:
item.setForeground(QBrush(QColor(0, 0, 0)))
self.show_running_vms_warning(some_selected_vms_running)
for i in range(self.select_vms_widget.available_list.count()):
item = self.select_vms_widget.available_list.item(i)
if item.vm.is_running() and item.vm.qid != 0:
item.setForeground(QBrush(QColor(255, 0, 0)))
else:
item.setForeground(QBrush(QColor(0, 0, 0)))
return some_selected_vms_running
def shutdown_all_running_selected(self):
names = []
vms = []
for i in range(self.select_vms_widget.selected_list.count()):
item = self.select_vms_widget.selected_list.item(i)
if item.vm.is_running() and item.vm.qid != 0:
names.append(item.vm.name)
vms.append(item.vm)
if len(vms) == 0:
return;
reply = QMessageBox.question(None, "VM Shutdown Confirmation",
"Are you sure you want to power down the following VMs: <b>{0}</b>?<br>"
"<small>This will shutdown all the running applications within them.</small>".format(', '.join(names)),
QMessageBox.Yes | QMessageBox.Cancel)
self.app.processEvents()
if reply == QMessageBox.Yes:
for vm in vms:
self.shutdown_vm_func(vm)
progress = QProgressDialog ("Shutting down VMs <b>{0}</b>...".format(', '.join(names)), "", 0, 0)
progress.setModal(True)
progress.show()
wait_time = 15.0
wait_for = wait_time
while self.check_running() and wait_for > 0:
self.app.processEvents()
time.sleep (0.1)
wait_for -= 0.1
progress.hide()
if self.check_running():
QMessageBox.information(None, "Strange", "Could not power down the VMs in {0} seconds...".format(wait_time))
def dev_combobox_activated(self, idx):
dev_combobox_activated(self, idx)
@ -123,9 +194,16 @@ class BackupVMsWindow(Ui_Backup, QWizard):
def validateCurrentPage(self):
if self.currentPage() is self.select_vms_page:
for i in range(self.select_vms_widget.selected_list.count()):
if self.check_running() == True:
QMessageBox.information(None, "Wait!", "Some selected VMs are running. Running VMs can not be backuped. Please shut them down or remove them from the list.")
return False
del self.excluded[:]
for i in range(self.select_vms_widget.available_list.count()):
vmname = self.select_vms_widget.available_list.item(i).text()
vmname = str(self.select_vms_widget.available_list.item(i).text())
self.excluded.append(vmname)
return True
def gather_output(self, s):
@ -152,7 +230,10 @@ class BackupVMsWindow(Ui_Backup, QWizard):
def current_page_changed(self, id):
if self.currentPage() is self.confirm_page:
del self.func_output[:]
self.files_to_backup = qubesutils.backup_prepare(str(self.backup_dir), exclude_list = self.excluded, print_callback = self.gather_output)
try:
self.files_to_backup = qubesutils.backup_prepare(str(self.backup_dir), exclude_list = self.excluded, print_callback = self.gather_output)
except Exception as ex:
QMessageBox.critical(None, "Error while prepering backup.", "ERROR: {0}".format(ex))
self.textEdit.setReadOnly(True)
self.textEdit.setFontFamily("Monospace")
@ -213,8 +294,6 @@ def handle_exception( exc_type, exc_value, exc_traceback ):
% ( line, filename ))
def main():
global qubes_host

View File

@ -1142,16 +1142,22 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
app.processEvents()
if reply == QMessageBox.Yes:
try:
subprocess.check_call (["/usr/sbin/xl", "shutdown", vm.name])
except Exception as ex:
QMessageBox.warning (None, "Error shutting down VM!", "ERROR: {0}".format(ex))
return
self.shutdown_vm(vm)
def shutdown_vm(self, vm):
try:
subprocess.check_call (["/usr/sbin/xl", "shutdown", vm.name])
except Exception as ex:
QMessageBox.warning (None, "Error shutting down VM!", "ERROR: {0}".format(ex))
return
trayIcon.showMessage ("Qubes Manager", "VM '{0}' is shutting down...".format(vm.name), msecs=3000)
self.shutdown_monitor[vm.qid] = VmShutdownMonitor (vm)
QTimer.singleShot (vm_shutdown_timeout, self.shutdown_monitor[vm.qid].check_if_vm_has_shutdown)
trayIcon.showMessage ("Qubes Manager", "VM '{0}' is shutting down...".format(vm.name), msecs=3000)
self.shutdown_monitor[vm.qid] = VmShutdownMonitor (vm)
QTimer.singleShot (vm_shutdown_timeout, self.shutdown_monitor[vm.qid].check_if_vm_has_shutdown)
@pyqtSlot(name='on_action_settings_triggered')
def action_settings_triggered(self):
@ -1235,7 +1241,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
@pyqtSlot(name='on_action_backup_triggered')
def action_backup_triggered(self):
backup_window = BackupVMsWindow(app, self.qvm_collection, self.blk_manager)
backup_window = BackupVMsWindow(app, self.qvm_collection, self.blk_manager, self.shutdown_vm)
backup_window.exec_()

View File

@ -358,7 +358,7 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
self.vcpus.setMaximum(QubesHost().no_cpus)
self.vcpus.setValue(int(self.vm.vcpus))
self.include_in_balancing.setChecked('meminfo-writer' in self.vm.services and self.vm.services['meminfo-writer']==True)
self.include_in_balancing.setChecked(self.vm.services['meminfo-writer']==True)
#kernel
if self.vm.template is not None:
@ -415,10 +415,8 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
self.vm.vcpus = self.vcpus.value()
self.anything_changed = True
balancing_was_checked = ('meminfo-writer' in self.vm.services and self.vm.services['meminfo-writer']==True)
if self.include_in_balancing.isChecked() != balancing_was_checked:
self.new_srv_dict['meminfo-writer'] = self.include_in_balancing.isChecked()
self.anything_changed = True
#include_in_memory_balancing applied in services tab
#kernel changed
if self.kernel.currentIndex() != self.kernel_idx:
@ -489,6 +487,12 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
self.anything_changed = True
def include_in_balancing_state_changed(self, state):
for r in range (self.services_list.count()):
item = self.services_list.item(r)
if str(item.text()) == 'meminfo-writer':
item.setCheckState(state)
break;
if self.dev_list.selected_list.count() > 0:
if state == QtCore.Qt.Checked:
self.dmm_warning_adv.show()
@ -496,6 +500,7 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
else:
self.dmm_warning_adv.hide()
self.dmm_warning_dev.hide()
def devices_selection_changed(self):
if self.include_in_balancing.isChecked():
if self.dev_list.selected_list.count() > 0 :
@ -515,28 +520,54 @@ class VMSettingsWindow(Ui_SettingsDialog, QDialog):
else:
item.setCheckState(QtCore.Qt.Unchecked)
self.services_list.addItem(item)
self.connect(self.services_list, SIGNAL("itemClicked(QListWidgetItem *)"), self.services_item_clicked)
self.new_srv_dict = copy(self.vm.services)
def __add_service__(self):
srv = str(self.service_line_edit.text()).strip()
if srv != "" and srv not in self.new_srv_dict:
item = QListWidgetItem(srv)
item.setCheckState(QtCore.Qt.Checked)
self.services_list.addItem(item)
self.new_srv_dict[srv] = True
if srv != "":
if srv in self.new_srv_dict:
QMessageBox.information(None, "", "Service already on the list!")
else:
item = QListWidgetItem(srv)
item.setCheckState(QtCore.Qt.Checked)
self.services_list.addItem(item)
self.new_srv_dict[srv] = True
def __remove_service__(self):
row = self.services_list.currentRow()
if row:
item = self.services_list.currentItem()
if str(item.text()) == 'meminfo-writer':
QMessageBox.information(None, "Service can not be removed", "Service meminfo-writer can not be removed from the list.")
else:
row = self.services_list.currentRow()
item = self.services_list.takeItem(row)
del self.new_srv_dict[str(item.text())]
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)
def __apply_services_tab__(self):
new_dict = {}
for r in range (self.services_list.count()):
item = self.services_list.item(r)
self.new_srv_dict[str(item.text())] = (item.checkState() == QtCore.Qt.Checked)
balancing_was_checked = (self.vm.services['meminfo-writer']==True)
balancing_is_checked = self.include_in_balancing.isChecked()
meminfo_writer_checked = (self.new_srv_dict['meminfo-writer'] == True)
if balancing_is_checked != meminfo_writer_checked:
if balancing_is_checked != balancing_was_checked:
self.new_srv_dict['meminfo-writer'] = balancing_is_checked
if self.new_srv_dict != self.vm.services:
self.vm.services = self.new_srv_dict
self.anything_changed = True

View File

@ -11,7 +11,7 @@ Group: Qubes
Vendor: Invisible Things Lab
License: GPL
URL: http://fixme
Requires: python, PyQt4, qubes-core-dom0 >= 1.7.15, kdebase
Requires: python, PyQt4, qubes-core-dom0 > 1.7.17, kdebase
Requires: pmount, cryptsetup
BuildRequires: PyQt4-devel
AutoReq: 0