diff --git a/cloudcontrol/node/hypervisor/__init__.py b/cloudcontrol/node/hypervisor/__init__.py index b82f39c8b90b9a662b18100eb5c52b058e3f2d95..bbbdafe000d1a43221bca4cd73cac7e311b612b6 100644 --- a/cloudcontrol/node/hypervisor/__init__.py +++ b/cloudcontrol/node/hypervisor/__init__.py @@ -36,7 +36,7 @@ from cloudcontrol.node.exc import ( UndefinedDomain, DRBDError, PoolStorageError ) from cloudcontrol.node.hypervisor.jobs import ( - ImportVolume, ExportVolume, TCPTunnel, DRBD, + ImportVolume, ExportVolume, TCPTunnel, DRBD ) from cloudcontrol.node.utils import execute @@ -318,6 +318,56 @@ class Handler(HostHandler): logger.error(msg) raise UndefinedDomain(msg) + @libvirt_handler + def vm_reset(self, name): + logger.debug('VM reset %s', name) + try: + self.hypervisor.domains[name].reset() + except libvirt.libvirtError: + logger.exception('Error while resetting VM %s', name) + raise + except KeyError: + msg = 'Cannot reset VM %s because it is not defined' % name + logger.error(msg) + raise UndefinedDomain(msg) + + @libvirt_handler + def vm_cycle(self, name): + logger.debug('VM cycle %s', name) + try: + self.hypervisor.domains[name].destroy() + time.sleep(1) + self.hypervisor.domains[name].start() + except libvirt.libvirtError: + logger.exception('Error while cycle VM %s', name) + raise + except KeyError: + msg = 'Cannot cycle VM %s because it is not defined' % name + logger.error(msg) + raise UndefinedDomain(msg) + + @libvirt_handler + def vm_change_title(self, name, new_title): + logger.debug('VM edit title %s', name) + try: + self.hypervisor.domains[name].title = new_title + except libvirt.libvirtError: + logger.exception('Error while changing VM title %s', name) + raise + except KeyError: + msg = 'Cannot change title open VM %s because it is not defined' % name + logger.error(msg) + raise UndefinedDomain(msg) + + @libvirt_handler + def vm_migrate(self, name, dest_uri, live=False): + try: + dom = self.hypervisor.domains[name] + except KeyError: + raise UndefinedDomain('Cannot migrate VM %s because it is not defined', name) + + dom.migrate(dest_uri, live=live) + @libvirt_handler def vm_migrate_tunneled(self, name, tun_res, migtun_res, unsafe=False, timeout=60.): diff --git a/cloudcontrol/node/hypervisor/domains/__init__.py b/cloudcontrol/node/hypervisor/domains/__init__.py index 5628e06378d82093a5461f62765eb3b7262c052e..7a0f2c33cdeae51aaeb83561dfd261e0820b826b 100644 --- a/cloudcontrol/node/hypervisor/domains/__init__.py +++ b/cloudcontrol/node/hypervisor/domains/__init__.py @@ -512,3 +512,27 @@ class VirtualMachine(object): self.from_tunnel = None self.from_stream = None + + def migrate(self, dest_uri, live=False): + volumes = list(self.iter_disks()) # Store volumes for future cleanup + + flags = (libvirt.VIR_MIGRATE_PEER2PEER + | libvirt.VIR_MIGRATE_PERSIST_DEST + | libvirt.VIR_MIGRATE_UNDEFINE_SOURCE) + + if live: + flags |= (libvirt.VIR_MIGRATE_LIVE + | libvirt.VIR_MIGRATE_NON_SHARED_DISK + | libvirt.VIR_MIGRATE_AUTO_CONVERGE) + else: + flags |= libvirt.VIR_MIGRATE_OFFLINE + + error = self.lv_dom.migrateToURI3(dest_uri, {}, flags) + + if error: + raise RuntimeError('Unable to migrate VM') + else: + if live: # In live mode, we are responsible for source volume cleaning + for volume in volumes: + # Delete VM storage after migration success: + self.hypervisor.storage.delete_volume(volume.storage, volume.name) diff --git a/cloudcontrol/node/hypervisor/jobs.py b/cloudcontrol/node/hypervisor/jobs.py index 6598daf3aff87f977fea46eabcbdd9b5b680721c..0dbe85a46b0ffcfebc157fa64c24c085d3003c02 100644 --- a/cloudcontrol/node/hypervisor/jobs.py +++ b/cloudcontrol/node/hypervisor/jobs.py @@ -30,6 +30,8 @@ from xml.etree import ElementTree as et import pyev +from cloudcontrol.common.jobs import Job + from cloudcontrol.node.exc import TunnelError, DRBDAllocationError, DRBDError from cloudcontrol.node.jobs import BaseIOJob, ForkedJob from cloudcontrol.node.utils import SocketBuffer, subproc_call, Singleton