#!/usr/bin/python3 # # The Qubes OS Project, http://www.qubes-os.org # # Copyright (C) 2012 Agnieszka Kostrzewa # Copyright (C) 2012 Marek Marczykowski # Copyright (C) 2017 Wojtek Porczyk # # 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 Lesser General Public License along # with this program; if not, see . # # import os import sys import subprocess from PyQt5 import QtCore, QtWidgets, QtGui # pylint: disable=import-error import qubesadmin import qubesadmin.tools import qubesadmin.exc from . import utils from .ui_newappvmdlg import Ui_NewVMDlg # pylint: disable=import-error # pylint: disable=too-few-public-methods class CreateVMThread(QtCore.QThread): def __init__(self, app, vmclass, name, label, template, properties, pool): QtCore.QThread.__init__(self) self.app = app self.vmclass = vmclass self.name = name self.label = label self.template = template self.properties = properties self.pool = pool self.msg = None def run(self): try: if self.vmclass == 'StandaloneVM' and self.template is not None: args = { 'ignore_volumes': ['private'] } if self.pool: args['pool'] = self.pool vm = self.app.clone_vm(self.template, self.name, self.vmclass, **args) vm.label = self.label for k, v in self.properties.items(): setattr(vm, k, v) else: args = { "name": self.name, "label": self.label, "template": self.template } if self.pool: args['pool'] = self.pool vm = self.app.add_new_vm(self.vmclass, **args) for k, v in self.properties.items(): setattr(vm, k, v) except qubesadmin.exc.QubesException as qex: self.msg = str(qex) except Exception as ex: # pylint: disable=broad-except self.msg = repr(ex) class NewVmDlg(QtWidgets.QDialog, Ui_NewVMDlg): def __init__(self, qtapp, app, parent=None): super().__init__(parent) self.setupUi(self) self.qtapp = qtapp self.app = app self.thread = None self.progress = None utils.initialize_widget_with_labels( widget=self.label, qubes_app=self.app) utils.initialize_widget_with_default( widget=self.template_vm, choices=[(vm.name, vm) for vm in self.app.domains if not utils.is_internal(vm) and vm.klass == 'TemplateVM'], mark_existing_as_default=True, default_value=getattr(self.app, 'default_template', None)) utils.initialize_widget_with_default( widget=self.netvm, choices=[(vm.name, vm) for vm in self.app.domains if not utils.is_internal(vm) and getattr(vm, 'provides_network', False)], add_none=True, add_qubes_default=True, default_value=getattr(self.app, 'default_netvm', None)) try: utils.initialize_widget_with_default( widget=self.storage_pool, choices=[(str(pool), pool) for pool in self.app.pools.values()], add_qubes_default=True, mark_existing_as_default=True, default_value=self.app.default_pool) except qubesadmin.exc.QubesDaemonAccessError: self.storage_pool.clear() self.storage_pool.addItem("(default)", qubesadmin.DEFAULT) self.name.setValidator(QtGui.QRegExpValidator( QtCore.QRegExp("[a-zA-Z0-9_-]*", QtCore.Qt.CaseInsensitive), None)) self.name.selectAll() self.name.setFocus() if self.template_vm.count() < 1: QtWidgets.QMessageBox.warning( self, self.tr('No template available!'), self.tr('Cannot create a qube when no template exists.')) type_list = [ (self.tr("Qube based on a template (AppVM)"), 'AppVM'), (self.tr("Standalone qube copied from a template"), 'StandaloneVM-copy'), (self.tr("Empty standalone qube (install your own OS)"), 'StandaloneVM-empty')] utils.initialize_widget(widget=self.vm_type, choices=type_list, selected_value='AppVM', add_current_label=False) self.vm_type.currentIndexChanged.connect(self.type_change) self.launch_settings.stateChanged.connect(self.settings_change) self.install_system.stateChanged.connect(self.install_change) def reject(self): self.done(0) def accept(self): selected_type = self.vm_type.currentData() vmclass = selected_type.split('-')[0] name = str(self.name.text()) if name in self.app.domains: QtWidgets.QMessageBox.warning( self, self.tr('Incorrect qube name!'), self.tr('A qube with the name {} already exists in the ' 'system!').format(name)) return label = self.label.currentData() template = self.template_vm.currentData() properties = {'provides_network': self.provides_network.isChecked()} if self.netvm.currentIndex() != 0: properties['netvm'] = self.netvm.currentData() # Standalone - not based on a template if selected_type == 'StandaloneVM-empty': properties['virt_mode'] = 'hvm' properties['kernel'] = None if self.storage_pool.currentData() is not qubesadmin.DEFAULT: pool = self.storage_pool.currentData() else: pool = None if self.init_ram.value() > 0: properties['memory'] = self.init_ram.value() self.thread = CreateVMThread( self.app, vmclass, name, label, template, properties, pool) self.thread.finished.connect(self.create_finished) self.thread.start() self.progress = QtWidgets.QProgressDialog( self.tr("Creating new qube {0}...").format(name), "", 0, 0) self.progress.setCancelButton(None) self.progress.setModal(True) self.progress.show() def create_finished(self): self.progress.hide() if self.thread.msg: QtWidgets.QMessageBox.warning( self, self.tr("Error creating the qube!"), self.tr("ERROR: {0}").format(self.thread.msg)) self.done(0) if not self.thread.msg: if self.launch_settings.isChecked(): subprocess.check_call(['qubes-vm-settings', str(self.name.text())]) if self.install_system.isChecked(): subprocess.check_call( ['qubes-vm-boot-from-device', str(self.name.text())]) def type_change(self): if self.vm_type.currentData() == 'AppVM': self.template_vm.setEnabled(True) if self.template_vm.currentIndex() == -1: self.template_vm.setCurrentIndex(0) self.install_system.setEnabled(False) self.install_system.setChecked(False) if self.vm_type.currentData() == 'StandaloneVM-copy': self.template_vm.setEnabled(True) if self.template_vm.currentIndex() == -1: self.template_vm.setCurrentIndex(0) self.install_system.setEnabled(False) self.install_system.setChecked(False) if self.vm_type.currentData() == 'StandaloneVM-empty': self.template_vm.setEnabled(False) self.template_vm.setCurrentIndex(-1) self.install_system.setEnabled(True) self.install_system.setChecked(True) def install_change(self): if self.install_system.isChecked(): self.launch_settings.setChecked(False) def settings_change(self): if self.launch_settings.isChecked() and self.install_system.isEnabled(): self.install_system.setChecked(False) parser = qubesadmin.tools.QubesArgumentParser() def main(args=None): args = parser.parse_args(args) qtapp = QtWidgets.QApplication(sys.argv) translator = QtCore.QTranslator(qtapp) locale = QtCore.QLocale.system().name() i18n_dir = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'i18n') translator.load("qubesmanager_{!s}.qm".format(locale), i18n_dir) qtapp.installTranslator(translator) QtCore.QCoreApplication.installTranslator(translator) qtapp.setOrganizationName('Invisible Things Lab') qtapp.setOrganizationDomain('https://www.qubes-os.org/') qtapp.setApplicationName(QtCore.QCoreApplication.translate( "appname", 'Create qube')) dialog = NewVmDlg(qtapp, args.app) dialog.exec_()