From d4673d540e58fec42ac9d672870f40470045ec2a Mon Sep 17 00:00:00 2001 From: Agnieszka Kostrzewa Date: Fri, 11 May 2012 22:52:27 +0200 Subject: [PATCH] Allow to specify type of the VM being created (#559) --- newappvmdlg.ui | 309 +++++++++++----------------------- qubesmanager/create_new_vm.py | 194 +++++++++++++++++++++ qubesmanager/main.py | 95 +---------- 3 files changed, 298 insertions(+), 300 deletions(-) create mode 100644 qubesmanager/create_new_vm.py diff --git a/newappvmdlg.ui b/newappvmdlg.ui index 4ba6904..c8a86be 100644 --- a/newappvmdlg.ui +++ b/newappvmdlg.ui @@ -1,229 +1,116 @@ - NewAppVMDlg - + NewVMDlg + 0 0 - 507 - 209 + 500 + 200 - Create New AppVM + Create New VM :/qubes.png:/qubes.png - - - - - 0 + + + + + + + true + + + + + + + + + + Use this template: + + + + + + + ProxyVM + + + + + + + NetVM + + + + + + + my-new-vm + + + + + + + AppVM + + + true + + + + + + + false + + + HVM + + + + + + + Name & label: + + + + + + + + + Allow networking + + + true - - - Basic - - - - - - myappvm - - - - - - - true - - - - - - - Name & label: - - - - - - - - - - Use this template: - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Allow networking - - - true - - - - - - - - Advanced - - - - - - Disk storage - - - - - - false - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 10000 - - - 2 - - - - - - - false - - - Allow to grow - - - - - - - GB - - - - - - - Private storage max. size - - - - - - - false - - - Include in backups - - - true - - - - - - - - - - Memory/CPU - - - - - - false - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 10000 - - - 100 - - - 400 - - - - - - - MB - - - - - - - false - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - - - - - VCPUs - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - + + + + Qt::Vertical + + + + 20 + 40 + + + + + Qt::Horizontal @@ -240,7 +127,7 @@ buttonBox accepted() - NewAppVMDlg + NewVMDlg accept() @@ -256,7 +143,7 @@ buttonBox rejected() - NewAppVMDlg + NewVMDlg reject() diff --git a/qubesmanager/create_new_vm.py b/qubesmanager/create_new_vm.py new file mode 100644 index 0000000..7ec8b2b --- /dev/null +++ b/qubesmanager/create_new_vm.py @@ -0,0 +1,194 @@ +#!/usr/bin/python2.6 +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2012 Agnieszka Kostrzewa +# Copyright (C) 2012 Marek Marczykowski +# +# 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. +# +# + +import sys +import os +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +from qubes.qubes import QubesVmCollection +from qubes.qubes import QubesVmLabels +from qubes.qubes import QubesException + +import qubesmanager.resources_rc + +from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent + +import subprocess +import time +import threading + +from ui_newappvmdlg import * +from thread_monitor import * + + +class NewVmDlg (QDialog, Ui_NewVMDlg): + def __init__(self, app, qvm_collection, trayIcon, parent = None): + super (NewVmDlg, self).__init__(parent) + self.setupUi(self) + + self.app = app + self.trayIcon = trayIcon + self.qvm_collection = qvm_collection + + # Theoretically we should be locking for writing here and unlock + # only after the VM creation finished. But the code would be more messy... + # Instead we lock for writing in the actual worker thread + + try: + from qubes.qubes import QubesHVM + except ImportError: + pass + else: + self.hvm_radio.setEnabled(True) + + self.qvm_collection.lock_db_for_reading() + self.qvm_collection.load() + self.qvm_collection.unlock_db() + + self.label_list = QubesVmLabels.values() + self.label_list.sort(key=lambda l: l.index) + for (i, label) in enumerate(self.label_list): + self.vmlabel.insertItem(i, label.name) + self.vmlabel.setItemIcon (i, QIcon(label.icon_path)) + + self.template_vm_list = [vm for vm in self.qvm_collection.values() if not vm.internal and vm.is_template()] + + default_index = 0 + for (i, vm) in enumerate(self.template_vm_list): + if vm is self.qvm_collection.get_default_template(): + default_index = i + self.template_name.insertItem(i, vm.name + " (default)") + else: + self.template_name.insertItem(i, vm.name) + self.template_name.setCurrentIndex(default_index) + + self.vmname.selectAll() + self.vmname.setFocus() + + def on_appvm_radio_toggled(self, checked): + if checked: + self.template_name.setEnabled(True) + self.allow_networking.setEnabled(True) + def on_netvm_radio_toggled(self, checked): + if checked: + self.template_name.setEnabled(True) + self.allow_networking.setEnabled(False) + def on_proxyvm_radio_toggled(self, checked): + if checked: + self.template_name.setEnabled(True) + self.allow_networking.setEnabled(True) + def on_hvm_radio_toggled(self, checked): + if checked: + self.template_name.setEnabled(False) + self.allow_networking.setEnabled(True) + + + def reject(self): + self.done(0) + + def accept(self): + vmname = str(self.vmname.text()) + if self.qvm_collection.get_vm_by_name(vmname) is not None: + QMessageBox.warning (None, "Incorrect AppVM Name!", "A VM with the name {0} already exists in the system!".format(vmname)) + return + + label = self.label_list[self.vmlabel.currentIndex()] + + template_vm = None + if self.template_name.isEnabled(): + template_vm = self.template_vm_list[self.template_name.currentIndex()] + + allow_networking = None + if self.allow_networking.isEnabled(): + allow_networking = self.allow_networking.isChecked() + + if self.appvm_radio.isChecked(): + createvm_method = self.qvm_collection.add_new_appvm + vmtype = "AppVM" + elif self.netvm_radio.isChecked(): + createvm_method = self.qvm_collection.add_new_netvm + vmtype = "NetVM" + elif self.proxyvm_radio.isChecked(): + createvm_method = self.qvm_collection.add_new_proxyvm + vmtype = "ProxyVM" + else: #hvm_radio.isChecked() + createvm_method = self.qvm_collection.add_new_hvm + vmtype = "HVM" + + + thread_monitor = ThreadMonitor() + thread = threading.Thread (target=self.do_create_vm, args=(createvm_method, vmname, label, template_vm, allow_networking, thread_monitor)) + thread.daemon = True + thread.start() + + progress = QProgressDialog ("Creating new {0} {1}...".format(vmtype, vmname), "", 0, 0) + progress.setCancelButton(None) + progress.setModal(True) + progress.show() + + while not thread_monitor.is_finished(): + self.app.processEvents() + time.sleep (0.1) + + progress.hide() + + if thread_monitor.success: + self.trayIcon.showMessage ("Qubes VM Manager", "VM '{0}' has been created.".format(vmname), msecs=3000) + else: + QMessageBox.warning (None, "Error creating AppVM!", "ERROR: {0}".format(thread_monitor.error_msg)) + + self.done(0) + + + + def do_create_vm (self, createvm_method, vmname, label, template_vm, allow_networking, thread_monitor): + vm = None + try: + self.qvm_collection.lock_db_for_writing() + self.qvm_collection.load() + + if template_vm is not None: + vm = createvm_method(vmname, template_vm, label = label) + vm.create_on_disk(verbose=False, source_template = template_vm) + else: + vm = createvm_method(vmname, label = label) + vm.create_on_disk(verbose=False) + + if allow_networking is not None: + firewall = vm.get_firewall_conf() + firewall["allow"] = allow_networking + firewall["allowDns"] = allow_networking + vm.write_firewall_conf(firewall) + self.qvm_collection.save() + + except Exception as ex: + thread_monitor.set_error_msg (str(ex)) + if vm: + vm.remove_from_disk() + finally: + self.qvm_collection.unlock_db() + + thread_monitor.set_finished() + + diff --git a/qubesmanager/main.py b/qubesmanager/main.py index f99340b..3977b2b 100755 --- a/qubesmanager/main.py +++ b/qubesmanager/main.py @@ -41,6 +41,7 @@ from qubes import qubesutils import qubesmanager.resources_rc import ui_newappvmdlg from ui_mainwindow import * +from create_new_vm import NewVmDlg from settings import VMSettingsWindow from restore import RestoreVMsWindow from backup import BackupVMsWindow @@ -607,10 +608,8 @@ class VmRowInTable(object): if update_size_on_disk == True: self.size_widget.update() -class NewAppVmDlg (QDialog, ui_newappvmdlg.Ui_NewAppVMDlg): - def __init__(self, parent = None): - super (NewAppVmDlg, self).__init__(parent) - self.setupUi(self) + + vm_shutdown_timeout = 15000 # in msec @@ -1067,92 +1066,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): @pyqtSlot(name='on_action_createvm_triggered') def action_createvm_triggered(self): - dialog = NewAppVmDlg() - - # Theoretically we should be locking for writing here and unlock - # only after the VM creation finished. But the code would be more messy... - # Instead we lock for writing in the actual worker thread - - self.qvm_collection.lock_db_for_reading() - self.qvm_collection.load() - self.qvm_collection.unlock_db() - - label_list = QubesVmLabels.values() - label_list.sort(key=lambda l: l.index) - for (i, label) in enumerate(label_list): - dialog.vmlabel.insertItem(i, label.name) - dialog.vmlabel.setItemIcon (i, QIcon(label.icon_path)) - - template_vm_list = [vm for vm in self.qvm_collection.values() if not vm.internal and vm.is_template()] - - default_index = 0 - for (i, vm) in enumerate(template_vm_list): - if vm is self.qvm_collection.get_default_template(): - default_index = i - dialog.template_name.insertItem(i, vm.name + " (default)") - else: - dialog.template_name.insertItem(i, vm.name) - dialog.template_name.setCurrentIndex(default_index) - - dialog.vmname.selectAll() - dialog.vmname.setFocus() - - if dialog.exec_(): - vmname = str(dialog.vmname.text()) - if self.qvm_collection.get_vm_by_name(vmname) is not None: - QMessageBox.warning (None, "Incorrect AppVM Name!", "A VM with the name {0} already exists in the system!".format(vmname)) - return - - label = label_list[dialog.vmlabel.currentIndex()] - template_vm = template_vm_list[dialog.template_name.currentIndex()] - - allow_networking = dialog.allow_networking.isChecked() - - thread_monitor = ThreadMonitor() - thread = threading.Thread (target=self.do_create_appvm, args=(vmname, label, template_vm, allow_networking, thread_monitor)) - thread.daemon = True - thread.start() - - progress = QProgressDialog ("Creating new AppVM {0}...".format(vmname), "", 0, 0) - progress.setCancelButton(None) - progress.setModal(True) - progress.show() - - while not thread_monitor.is_finished(): - app.processEvents() - time.sleep (0.1) - - progress.hide() - - if thread_monitor.success: - trayIcon.showMessage ("Qubes VM Manager", "VM '{0}' has been created.".format(vmname), msecs=3000) - else: - QMessageBox.warning (None, "Error creating AppVM!", "ERROR: {0}".format(thread_monitor.error_msg)) - - - def do_create_appvm (self, vmname, label, template_vm, allow_networking, thread_monitor): - vm = None - try: - self.qvm_collection.lock_db_for_writing() - self.qvm_collection.load() - - vm = self.qvm_collection.add_new_appvm(vmname, template_vm, label = label) - vm.create_on_disk(verbose=False) - firewall = vm.get_firewall_conf() - firewall["allow"] = allow_networking - firewall["allowDns"] = allow_networking - vm.write_firewall_conf(firewall) - self.qvm_collection.save() - except Exception as ex: - thread_monitor.set_error_msg (str(ex)) - if vm: - vm.remove_from_disk() - finally: - self.qvm_collection.unlock_db() - - thread_monitor.set_finished() - + dialog = NewVmDlg(app, self.qvm_collection, trayIcon) + dialog.exec_() + def get_selected_vm(self): #vm selection relies on the VmInfo widget's value used for sorting by VM name row_index = self.table.currentRow()