Add "Clone VM" action (#613)

This commit is contained in:
Marek Marczykowski 2012-07-12 13:32:45 +02:00
parent 7472c3a98b
commit e8a0461bac
2 changed files with 80 additions and 1 deletions

View File

@ -229,7 +229,7 @@
<x>0</x>
<y>0</y>
<width>769</width>
<height>25</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menu_system">
@ -285,6 +285,7 @@
</widget>
<addaction name="action_createvm"/>
<addaction name="action_removevm"/>
<addaction name="action_clonevm"/>
<addaction name="separator"/>
<addaction name="action_resumevm"/>
<addaction name="action_pausevm"/>
@ -738,6 +739,18 @@
<string>Run command in the specified VM</string>
</property>
</action>
<action name="action_clonevm">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/templatevm.png</normaloff>:/templatevm.png</iconset>
</property>
<property name="text">
<string>Clone VM</string>
</property>
</action>
</widget>
<resources>
<include location="resources.qrc"/>

View File

@ -39,6 +39,7 @@ from qubes.qubes import dry_run
from qubes.qubes import qubes_guid_path
from qubes.qubes import QubesDaemonPidfile
from qubes.qubes import QubesHost
from qubes import qubes
from qubes import qubesutils
import qubesmanager.resources_rc
@ -754,6 +755,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.context_menu = QMenu(self)
self.context_menu.addAction(self.action_removevm)
self.context_menu.addAction(self.action_resumevm)
self.context_menu.addAction(self.action_clonevm)
self.context_menu.addAction(self.action_pausevm)
self.context_menu.addAction(self.action_shutdownvm)
self.context_menu.addAction(self.action_killvm)
@ -1073,6 +1075,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
# Update available actions:
self.action_settings.setEnabled(vm.qid != 0)
self.action_removevm.setEnabled(not vm.installed_by_rpm and not (vm.last_running))
self.action_clonevm.setEnabled(not vm.installed_by_rpm and not (vm.last_running) and not vm.is_netvm())
self.action_resumevm.setEnabled(not vm.last_running)
self.action_pausevm.setEnabled(vm.last_running and vm.qid != 0)
self.action_shutdownvm.setEnabled(vm.last_running and vm.qid != 0)
@ -1085,6 +1088,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
else:
self.action_settings.setEnabled(False)
self.action_removevm.setEnabled(False)
self.action_clonevm.setEnabled(False)
self.action_resumevm.setEnabled(False)
self.action_pausevm.setEnabled(False)
self.action_shutdownvm.setEnabled(False)
@ -1213,6 +1217,68 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
thread_monitor.set_finished()
@pyqtSlot(name='on_action_clonevm_triggered')
def action_clonevm_triggered(self):
vm = self.get_selected_vm()
name_number = 1
name_format = vm.name + '-clone-%d'
while self.qvm_collection.get_vm_by_name(name_format % name_number):
name_number += 1
cmd = ['kdialog', '--title', 'Qubes clone VM', '--inputbox', 'Enter name for VM <b>'+vm.name+'</b> clone:', name_format % name_number]
kdialog = subprocess.Popen(cmd, stdout = subprocess.PIPE)
clone_name = kdialog.stdout.read().strip()
if clone_name == "":
return
thread_monitor = ThreadMonitor()
thread = threading.Thread (target=self.do_clone_vm, args=(vm, clone_name, thread_monitor))
thread.daemon = True
thread.start()
progress = QProgressDialog ("Cloning VM <b>{0}</b> to <b>{1}</b>...".format(vm.name, clone_name), "", 0, 0)
progress.setCancelButton(None)
progress.setModal(True)
progress.show()
while not thread_monitor.is_finished():
app.processEvents()
time.sleep (0.2)
progress.hide()
if not thread_monitor.success:
QMessageBox.warning (None, "Error while cloning VM", "Exception while cloning:<br>{0}".format(thread_monitor.error_msg))
def do_clone_vm(self, vm, dst_name, thread_monitor):
try:
self.qvm_collection.lock_db_for_writing()
self.qvm_collection.load()
src_vm = self.qvm_collection[vm.qid]
dst_vm = None
if isinstance(src_vm, qubes.QubesTemplateVm):
dst_vm = self.qvm_collection.add_new_templatevm(name=dst_name,
installed_by_rpm=False)
elif isinstance(src_vm, qubes.QubesAppVm):
dst_vm = self.qvm_collection.add_new_appvm(name=dst_name, template=src_vm.template,
label=src_vm.label)
elif hasattr(qubes, 'QubesHVm') and isinstance(src_vm, qubes.QubesHVm):
dst_vm = self.qvm_collection.add_new_hvm(name=dst_name, label=src_vm.label)
dst_vm.clone_attrs(src_vm)
dst_vm.clone_disk_files (src_vm=src_vm, verbose=False)
self.qvm_collection.save()
self.qvm_collection.unlock_db()
except Exception as ex:
if dst_vm:
self.qvm_collection.pop(dst_vm.qid)
self.qvm_collection.unlock_db()
thread_monitor.set_error_msg(str(ex))
thread_monitor.set_finished()
@pyqtSlot(name='on_action_resumevm_triggered')
def action_resumevm_triggered(self):
vm = self.get_selected_vm()