Block devices attached and detached to/from VMs via combobox in Qubes Manager
This commit is contained in:
		
							parent
							
								
									59081c132b
								
							
						
					
					
						commit
						7113d74793
					
				| @ -398,21 +398,133 @@ class VmUpdateInfoWidget(QWidget): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class VmBlockDevicesWidget(QWidget): | class VmBlockDevicesWidget(QWidget): | ||||||
|     def __init__(self, vm, parent=None): |     def __init__(self, vm, block_manager,  parent=None): | ||||||
|         super(VmBlockDevicesWidget, self).__init__(parent) |         super(VmBlockDevicesWidget, self).__init__(parent) | ||||||
| 
 | 
 | ||||||
|         combo = QComboBox() |         self.vm = vm | ||||||
|         combo.addItem("USB dummy1") |         self.block_manager = block_manager | ||||||
|         combo.addItem("USB dummy2") |         self.free_devs = self.block_manager.free_devs | ||||||
|         combo.addItem("USB dummy3") |         self.att_devs = self.block_manager.attached_devs | ||||||
|  | 
 | ||||||
|  |         self.combo = QComboBox() | ||||||
| 
 | 
 | ||||||
|         layout = QVBoxLayout() |         layout = QVBoxLayout() | ||||||
|         layout.addWidget(combo) |         layout.addWidget(self.combo) | ||||||
|         self.setLayout(layout) |         self.setLayout(layout) | ||||||
|          |          | ||||||
|  |         self.connect(self.combo, SIGNAL("activated(int)"), self.combo_activated) | ||||||
|  | 
 | ||||||
|  |     def update(self, vm): | ||||||
|  |         self.combo.clear() | ||||||
|  |         self.combo.addItem("None") | ||||||
|  |         for a in self.att_devs: | ||||||
|  |             if self.att_devs[a]['attached_to']['vm'] == vm.name: | ||||||
|  |                 att = self.att_devs[a]['dev'] + ": " + unicode(self.att_devs[a]['size']) + " " + self.att_devs[a]['desc'] | ||||||
|  |                 self.combo.addItem(att, QVariant(a)) | ||||||
|  |                 self.combo.setCurrentIndex(1) | ||||||
|  |                 break | ||||||
|  |         if self.combo.count() == 1: | ||||||
|  |             for d in self.free_devs: | ||||||
|  |                 str = self.free_devs[d]['dev'] + ": " + unicode(self.free_devs[d]['size']) + " " + self.free_devs[d]['desc'] | ||||||
|  |                 self.combo.addItem(str, QVariant(d)) | ||||||
|  |         self.prev_idx = self.combo.currentIndex(); | ||||||
|  | 
 | ||||||
|  |     def combo_activated(self, idx): | ||||||
|  |         if idx == self.prev_idx:    #nothing has changed | ||||||
|  |             return | ||||||
|  |         #there was a change | ||||||
|  |         if self.combo.currentText() != "None": #device attached: | ||||||
|  |             self.prev_idx = idx | ||||||
|  |             dev_name = str(self.combo.itemData(idx).toString()) | ||||||
|  |             self.block_manager.attach_device(self.vm, dev_name) | ||||||
|  | 
 | ||||||
|  |         else: | ||||||
|  |             dev_name = str(self.combo.itemData(self.prev_idx).toString()) | ||||||
|  |             self.prev_idx = idx | ||||||
|  |             self.block_manager.detach_device(self.vm, dev_name) | ||||||
|  | 
 | ||||||
|  |     | ||||||
|  | 
 | ||||||
|  | class QubesBlockDevicesManager(): | ||||||
|  |     def __init__(self, qvm_collection): | ||||||
|  |         self.qvm_collection = qvm_collection | ||||||
|  |         self.attached_devs = {} | ||||||
|  |         self.free_devs = {} | ||||||
|  | 
 | ||||||
|  |         self.current_blk = {} | ||||||
|  |         self.current_attached = {} | ||||||
|  |         self.devs_changed = False | ||||||
|  | 
 | ||||||
|  |     def update(self): | ||||||
|  |         blk = qubesutils.block_list() | ||||||
|  |         for b in blk: | ||||||
|  |             att = qubesutils.block_check_attached(None, blk[b]['device'], backend_xid = blk[b]['xid']) | ||||||
|  |             if b in self.current_blk: | ||||||
|  |                 if blk[b] == self.current_blk[b]: | ||||||
|  |                     if self.current_attached[b] != att: #devices the same, sth with attaching changed | ||||||
|  |                         self.current_attached[b] = att | ||||||
|  |                         self.devs_changed = True | ||||||
|  |                 else:   #device changed ?! | ||||||
|  |                     self.current_blk[b] = blk[b] | ||||||
|  |                     self.current_attached[b] = att | ||||||
|  |                     self.devs_changed = True | ||||||
|  |             else: #new device | ||||||
|  |                 self.current_blk[b] = blk[b] | ||||||
|  |                 self.current_attached[b] = att | ||||||
|  |                 self.devs_changed = True | ||||||
|  | 
 | ||||||
|  |         for b in self.current_blk: | ||||||
|  |             if b not in blk: | ||||||
|  |                 del self.current_blk[b] | ||||||
|  |                 del current_attached[b] | ||||||
|  |                 self.devs_changed = True | ||||||
|  | 
 | ||||||
|  |         if self.devs_changed == True: | ||||||
|  |             self.devs_changed = False | ||||||
|  |             self.__update_blk_entries__() | ||||||
|  |             return True | ||||||
|  |         else: | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def __update_blk_entries__(self): | ||||||
|  |         self.free_devs.clear() | ||||||
|  |         self.attached_devs.clear() | ||||||
|  | 
 | ||||||
|  |         for b in self.current_attached: | ||||||
|  |             if self.current_attached[b]: | ||||||
|  |                 self.attached_devs[b] = self.__make_entry__(b, self.current_blk[b], self.current_attached[b]) | ||||||
|  |             else: | ||||||
|  |                 self.free_devs[b] = self.__make_entry__(b, self.current_blk[b], None) | ||||||
|  |                  | ||||||
|  |     def __make_entry__(self, k, dev, att): | ||||||
|  |         size_str = qubesutils.bytes_to_kmg(dev['size']) | ||||||
|  |         entry = {   'dev': dev['device'], | ||||||
|  |                     'backend_name': dev['vm'], | ||||||
|  |                     'desc': dev['desc'], | ||||||
|  |                     'size': size_str, | ||||||
|  |                     'attached_to': att, } | ||||||
|  |         return entry | ||||||
|  | 
 | ||||||
|  |     def attach_device(self, vm, dev): | ||||||
|  |         backend_vm_name = self.free_devs[dev]['backend_name'] | ||||||
|  |         dev_id = self.free_devs[dev]['dev'] | ||||||
|  |         backend_vm = self.qvm_collection.get_vm_by_name(backend_vm_name) | ||||||
|  |         trayIcon.showMessage ("Qubes Manager", "{0} - attaching {1}".format(vm.name, dev), msecs=3000) | ||||||
|  |         qubesutils.block_attach(vm, backend_vm, dev_id) | ||||||
|  |         self.devs_changed = True | ||||||
|  |        | ||||||
|  |     def detach_device(self, vm, dev_name): | ||||||
|  |         dev_id = self.attached_devs[dev_name]['attached_to']['devid'] | ||||||
|  |         vm_xid = self.attached_devs[dev_name]['attached_to']['xid'] | ||||||
|  |         trayIcon.showMessage ("Qubes Manager", "{0} - detaching {1}".format(vm.name, dev_name), msecs=3000) | ||||||
|  |         qubesutils.block_detach(None, dev_id, vm_xid) | ||||||
|  |         self.devs_changed = True | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class VmRowInTable(object): | class VmRowInTable(object): | ||||||
|     def __init__(self, vm, row_no, table): |     def __init__(self, vm, row_no, table, block_manager): | ||||||
|         self.vm = vm |         self.vm = vm | ||||||
|         self.row_no = row_no |         self.row_no = row_no | ||||||
| 
 | 
 | ||||||
| @ -456,12 +568,13 @@ class VmRowInTable(object): | |||||||
|         table.setCellWidget(row_no, 8, self.updateinfo_widget) |         table.setCellWidget(row_no, 8, self.updateinfo_widget) | ||||||
|         table.setItem(row_no, 8, self.updateinfo_widget.tableItem) |         table.setItem(row_no, 8, self.updateinfo_widget.tableItem) | ||||||
| 
 | 
 | ||||||
|         self.blockdevices_widget = VmBlockDevicesWidget(vm) |         self.blockdevices_widget = VmBlockDevicesWidget(vm, block_manager) | ||||||
|         table.setCellWidget(row_no, 9, self.blockdevices_widget) |         table.setCellWidget(row_no, 9, self.blockdevices_widget) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def update(self, counter, cpu_load = None): |     def update(self, counter, update_devs = False, cpu_load = None): | ||||||
|         self.info_widget.update_vm_state(self.vm) |         self.info_widget.update_vm_state(self.vm) | ||||||
|  |         self.blockdevices_widget.setEnabled(self.vm.is_running()) | ||||||
|         if cpu_load is not None: |         if cpu_load is not None: | ||||||
|             self.cpu_usage_widget.update_load(self.vm, cpu_load) |             self.cpu_usage_widget.update_load(self.vm, cpu_load) | ||||||
|             self.mem_usage_widget.update_load(self.vm, None) |             self.mem_usage_widget.update_load(self.vm, None) | ||||||
| @ -469,6 +582,8 @@ class VmRowInTable(object): | |||||||
|             self.mem_widget.update_load(self.vm, None) |             self.mem_widget.update_load(self.vm, None) | ||||||
|             self.updateinfo_widget.update_outdated(self.vm) |             self.updateinfo_widget.update_outdated(self.vm) | ||||||
|             self.upd_widget.update_outdated(self.vm) |             self.upd_widget.update_outdated(self.vm) | ||||||
|  |         if self.blockdevices_widget.isEnabled() and update_devs: | ||||||
|  |             self.blockdevices_widget.update(self.vm) | ||||||
| 
 | 
 | ||||||
| class NewAppVmDlg (QDialog, ui_newappvmdlg.Ui_NewAppVMDlg): | class NewAppVmDlg (QDialog, ui_newappvmdlg.Ui_NewAppVMDlg): | ||||||
|     def __init__(self, parent = None): |     def __init__(self, parent = None): | ||||||
| @ -541,6 +656,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|         self.toolbar = self.toolBar |         self.toolbar = self.toolBar | ||||||
|          |          | ||||||
|         self.qvm_collection = QubesVmCollection() |         self.qvm_collection = QubesVmCollection() | ||||||
|  |         self.blkManager = QubesBlockDevicesManager(self.qvm_collection) | ||||||
|          |          | ||||||
|         self.connect(self.table, SIGNAL("itemSelectionChanged()"), self.table_selection_changed) |         self.connect(self.table, SIGNAL("itemSelectionChanged()"), self.table_selection_changed) | ||||||
|          |          | ||||||
| @ -563,6 +679,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|         self.table.setColumnHidden( self.columns_indices["Block Device"], True) |         self.table.setColumnHidden( self.columns_indices["Block Device"], True) | ||||||
|         self.actionBlock_Devices.setChecked(False) |         self.actionBlock_Devices.setChecked(False) | ||||||
|         self.table.setColumnWidth(self.columns_indices["Upd"], 50) |         self.table.setColumnWidth(self.columns_indices["Upd"], 50) | ||||||
|  |         self.table.setColumnWidth(self.columns_indices["Block Device"], 250) | ||||||
| 
 | 
 | ||||||
|         self.table.sortItems(self.columns_indices["MEM"], Qt.DescendingOrder) |         self.table.sortItems(self.columns_indices["MEM"], Qt.DescendingOrder) | ||||||
| 
 | 
 | ||||||
| @ -659,7 +776,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|                 continue |                 continue | ||||||
|             if vm.internal: |             if vm.internal: | ||||||
|                 continue |                 continue | ||||||
|             vm_row = VmRowInTable (vm, row_no, self.table) |             vm_row = VmRowInTable (vm, row_no, self.table, self.blkManager) | ||||||
|             vms_in_table[vm.name] = vm_row |             vms_in_table[vm.name] = vm_row | ||||||
|             row_no += 1 |             row_no += 1 | ||||||
| 
 | 
 | ||||||
| @ -675,7 +792,6 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
| 
 | 
 | ||||||
|     # When calling update_table() directly, always use out_of_schedule=True! |     # When calling update_table() directly, always use out_of_schedule=True! | ||||||
|     def update_table(self, out_of_schedule=False): |     def update_table(self, out_of_schedule=False): | ||||||
| 
 |  | ||||||
|         if manager_window.isVisible(): |         if manager_window.isVisible(): | ||||||
|             some_vms_have_changed_power_state = False |             some_vms_have_changed_power_state = False | ||||||
|             for vm in self.vms_list: |             for vm in self.vms_list: | ||||||
| @ -684,8 +800,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|                     vm.last_power_state = state |                     vm.last_power_state = state | ||||||
|                     some_vms_have_changed_power_state = True |                     some_vms_have_changed_power_state = True | ||||||
| 
 | 
 | ||||||
|  |             update_devs = self.update_block_devices() | ||||||
|             if self.reload_table or ((not self.show_inactive_vms) and some_vms_have_changed_power_state):  |             if self.reload_table or ((not self.show_inactive_vms) and some_vms_have_changed_power_state):  | ||||||
|                 self.fill_table() |                 self.fill_table() | ||||||
|  |                 update_devs=True | ||||||
| 
 | 
 | ||||||
|             if self.counter % 3 == 0 or out_of_schedule: |             if self.counter % 3 == 0 or out_of_schedule: | ||||||
|                 (self.last_measure_time, self.last_measure_results) = \ |                 (self.last_measure_time, self.last_measure_results) = \ | ||||||
| @ -698,10 +816,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|                         cur_cpu_load = self.last_measure_results[vm_row.vm.xid]['cpu_usage'] |                         cur_cpu_load = self.last_measure_results[vm_row.vm.xid]['cpu_usage'] | ||||||
|                     else: |                     else: | ||||||
|                         cur_cpu_load = 0 |                         cur_cpu_load = 0 | ||||||
|                     vm_row.update(self.counter, cpu_load = cur_cpu_load) |                     vm_row.update(self.counter, update_devs=update_devs, cpu_load = cur_cpu_load) | ||||||
|             else: |             else: | ||||||
|                 for vm_row in self.vms_in_table.values(): |                 for vm_row in self.vms_in_table.values(): | ||||||
|                     vm_row.update(self.counter) |                     vm_row.update(self.counter, update_devs=update_devs) | ||||||
| 
 | 
 | ||||||
|             #self.table_selection_changed() |             #self.table_selection_changed() | ||||||
| 
 | 
 | ||||||
| @ -719,20 +837,40 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|         self.centralwidget.setFixedWidth(table_width) |         self.centralwidget.setFixedWidth(table_width) | ||||||
|         self.setFixedWidth(table_width) |         self.setFixedWidth(table_width) | ||||||
| 
 | 
 | ||||||
|  |     def update_block_devices(self): | ||||||
|  |         if self.table.isColumnHidden( self.columns_indices['Block Device']): | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
|  |         if self.blkManager.update(): | ||||||
|  |             return True | ||||||
|  |         else: | ||||||
|  |             return False | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     def table_selection_changed (self): |     def table_selection_changed (self): | ||||||
| 
 | 
 | ||||||
|         vm = self.get_selected_vm() |         vm = self.get_selected_vm() | ||||||
| 
 | 
 | ||||||
|         # Update available actions: |         if vm != None: | ||||||
|         self.action_settings.setEnabled(True) |             # Update available actions: | ||||||
|         self.action_removevm.setEnabled(not vm.installed_by_rpm and not vm.last_power_state) |             self.action_settings.setEnabled(True) | ||||||
|         self.action_resumevm.setEnabled(not vm.last_power_state) |             self.action_removevm.setEnabled(not vm.installed_by_rpm and not vm.last_power_state) | ||||||
|         self.action_pausevm.setEnabled(vm.last_power_state and vm.qid != 0) |             self.action_resumevm.setEnabled(not vm.last_power_state) | ||||||
|         self.action_shutdownvm.setEnabled(not vm.is_netvm() and vm.last_power_state and vm.qid != 0) |             self.action_pausevm.setEnabled(vm.last_power_state and vm.qid != 0) | ||||||
|         self.action_appmenus.setEnabled(not vm.is_netvm()) |             self.action_shutdownvm.setEnabled(not vm.is_netvm() and vm.last_power_state and vm.qid != 0) | ||||||
|         self.action_editfwrules.setEnabled(vm.is_networked() and not (vm.is_netvm() and not vm.is_proxyvm())) |             self.action_appmenus.setEnabled(not vm.is_netvm()) | ||||||
|         self.action_updatevm.setEnabled(vm.is_updateable() or vm.qid == 0) |             self.action_editfwrules.setEnabled(vm.is_networked() and not (vm.is_netvm() and not vm.is_proxyvm())) | ||||||
|  |             self.action_updatevm.setEnabled(vm.is_updateable() or vm.qid == 0) | ||||||
|  |         else: | ||||||
|  |             self.action_settings.setEnabled(False) | ||||||
|  |             self.action_removevm.setEnabled(False) | ||||||
|  |             self.action_resumevm.setEnabled(False) | ||||||
|  |             self.action_pausevm.setEnabled(False) | ||||||
|  |             self.action_shutdownvm.setEnabled(False) | ||||||
|  |             self.action_appmenus.setEnabled(False) | ||||||
|  |             self.action_editfwrules.setEnabled(False) | ||||||
|  |             self.action_updatevm.setEnabled(False) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def closeEvent (self, event): |     def closeEvent (self, event): | ||||||
| @ -744,8 +882,6 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|     def action_createvm_triggered(self): |     def action_createvm_triggered(self): | ||||||
|         dialog = NewAppVmDlg() |         dialog = NewAppVmDlg() | ||||||
| 
 | 
 | ||||||
|         print "Create VM triggered!\n" |  | ||||||
| 
 |  | ||||||
|         # Theoretically we should be locking for writing here and unlock |         # Theoretically we should be locking for writing here and unlock | ||||||
|         # only after the VM creation finished. But the code would be more messy... |         # only after the VM creation finished. But the code would be more messy... | ||||||
|         # Instead we lock for writing in the actual worker thread |         # Instead we lock for writing in the actual worker thread | ||||||
| @ -833,10 +969,13 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|     def get_selected_vm(self): |     def get_selected_vm(self): | ||||||
|         #vm selection relies on the VmInfo widget's value used for sorting by VM name |         #vm selection relies on the VmInfo widget's value used for sorting by VM name | ||||||
|         row_index = self.table.currentRow() |         row_index = self.table.currentRow() | ||||||
|         vm_name = self.table.item(row_index, self.columns_indices["Name"]).value |         if row_index != None: | ||||||
|         assert self.vms_in_table[vm_name] is not None |             vm_name = self.table.item(row_index, self.columns_indices["Name"]).value | ||||||
|         vm = self.vms_in_table[vm_name].vm |             assert self.vms_in_table[vm_name] is not None | ||||||
|         return vm |             vm = self.vms_in_table[vm_name].vm | ||||||
|  |             return vm | ||||||
|  |         else: | ||||||
|  |             return None | ||||||
| 
 | 
 | ||||||
|     @pyqtSlot(name='on_action_removevm_triggered') |     @pyqtSlot(name='on_action_removevm_triggered') | ||||||
|     def action_removevm_triggered(self): |     def action_removevm_triggered(self): | ||||||
| @ -1112,6 +1251,8 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): | |||||||
|         self.showhide_collumn( self.columns_indices['Block Device'], checked) |         self.showhide_collumn( self.columns_indices['Block Device'], checked) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class QubesTrayIcon(QSystemTrayIcon): | class QubesTrayIcon(QSystemTrayIcon): | ||||||
|     def __init__(self, icon): |     def __init__(self, icon): | ||||||
|         QSystemTrayIcon.__init__(self, icon) |         QSystemTrayIcon.__init__(self, icon) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Agnieszka Kostrzewa
						Agnieszka Kostrzewa