def sync_with_hypervisor(vmachineguid, storagedriver_id=None): """ Updates a given vmachine with data retrieved from a given pmachine :param vmachineguid: Guid of the virtual machine :param storagedriver_id: Storage Driver hosting the vmachine """ try: vmachine = VMachine(vmachineguid) except Exception as ex: VMachineController._logger.info('Cannot get VMachine object: {0}'.format(str(ex))) raise vm_object = None if vmachine.pmachine.mgmtcenter and storagedriver_id is not None and vmachine.devicename is not None: try: mgmt_center = Factory.get_mgmtcenter(vmachine.pmachine) storagedriver = StorageDriverList.get_by_storagedriver_id(storagedriver_id) VMachineController._logger.info('Syncing vMachine (name {0}) with Management center {1}'.format(vmachine.name, vmachine.pmachine.mgmtcenter.name)) vm_object = mgmt_center.get_vm_agnostic_object(devicename=vmachine.devicename, ip=storagedriver.storage_ip, mountpoint=storagedriver.mountpoint) except Exception as ex: VMachineController._logger.info('Error while fetching vMachine info from management center: {0}'.format(str(ex))) if vm_object is None and storagedriver_id is None and vmachine.hypervisor_id is not None and vmachine.pmachine is not None: try: # Only the vmachine was received, so base the sync on hypervisor id and pmachine hypervisor = Factory.get(vmachine.pmachine) VMachineController._logger.info('Syncing vMachine (name {0})'.format(vmachine.name)) vm_object = hypervisor.get_vm_agnostic_object(vmid=vmachine.hypervisor_id) except Exception as ex: VMachineController._logger.info('Error while fetching vMachine info from hypervisor: {0}'.format(str(ex))) if vm_object is None and storagedriver_id is not None and vmachine.devicename is not None: try: # Storage Driver id was given, using the devicename instead (to allow hypervisor id updates # which can be caused by re-adding a vm to the inventory) pmachine = PMachineList.get_by_storagedriver_id(storagedriver_id) storagedriver = StorageDriverList.get_by_storagedriver_id(storagedriver_id) hypervisor = Factory.get(pmachine) if not hypervisor.file_exists(storagedriver, hypervisor.clean_vmachine_filename(vmachine.devicename)): return vmachine.pmachine = pmachine vmachine.save() VMachineController._logger.info('Syncing vMachine (device {0}, ip {1}, mountpoint {2})'.format(vmachine.devicename, storagedriver.storage_ip, storagedriver.mountpoint)) vm_object = hypervisor.get_vm_object_by_devicename(devicename=vmachine.devicename, ip=storagedriver.storage_ip, mountpoint=storagedriver.mountpoint) except Exception as ex: VMachineController._logger.info('Error while fetching vMachine info from hypervisor using devicename: {0}'.format(str(ex))) if vm_object is None: message = 'Not enough information to sync vmachine' VMachineController._logger.info('Error: {0}'.format(message)) raise RuntimeError(message) VMachineController.update_vmachine_config(vmachine, vm_object)
def rollback(machineguid, timestamp): """ Rolls back a VM based on a given disk snapshot timestamp :param machineguid: Guid of the machine to rollback :param timestamp: Timestamp to rollback to """ vmachine = VMachine(machineguid) if vmachine.hypervisor_status == 'RUNNING': raise RuntimeError( 'vMachine {0} may not be running to set it as vTemplate'. format(vmachine.name)) snapshots = [ snap for snap in vmachine.snapshots if snap['timestamp'] == timestamp ] if not snapshots: raise ValueError( 'No vmachine snapshots found for timestamp {0}'.format( timestamp)) for disk in vmachine.vdisks: VDiskController.rollback(diskguid=disk.guid, timestamp=timestamp) vmachine.invalidate_dynamics(['snapshots'])
def snapshot(machineguid, label=None, is_consistent=False, timestamp=None, is_automatic=False): """ Snapshot VMachine disks @param machineguid: guid of the machine @param label: label to give the snapshots @param is_consistent: flag indicating the snapshot was consistent or not @param timestamp: override timestamp, if required. Should be a unix timestamp """ timestamp = timestamp if timestamp is not None else time.time() timestamp = str(int(float(timestamp))) metadata = { 'label': label, 'is_consistent': is_consistent, 'timestamp': timestamp, 'machineguid': machineguid, 'is_automatic': is_automatic } machine = VMachine(machineguid) # @todo: we now skip creating a snapshot when a vmachine's disks # is missing a mandatory property: volume_id # subtask will now raise an exception earlier in the workflow for disk in machine.vdisks: if not disk.volume_id: message = 'Missing volume_id on disk {0} - unable to create snapshot for vm {1}'.format( disk.guid, machine.guid) logger.info('Error: {0}'.format(message)) raise RuntimeError(message) snapshots = {} success = True try: for disk in machine.vdisks: snapshots[disk.guid] = VDiskController.create_snapshot( diskguid=disk.guid, metadata=metadata) except Exception as ex: logger.info('Error snapshotting disk {0}: {1}'.format( disk.name, str(ex))) success = False for diskguid, snapshotid in snapshots.iteritems(): VDiskController.delete_snapshot(diskguid=diskguid, snapshotid=snapshotid) logger.info('Create snapshot for vMachine {0}: {1}'.format( machine.name, 'Success' if success else 'Failure')) machine.invalidate_dynamics(['snapshots']) if not success: raise RuntimeError('Failed to snapshot vMachine {0}'.format( machine.name))
def snapshot(machineguid, label=None, is_consistent=False, timestamp=None, is_automatic=False, is_sticky=False): """ Snapshot VMachine disks :param machineguid: guid of the machine :param label: label to give the snapshots :param is_consistent: flag indicating the snapshot was consistent or not :param timestamp: override timestamp, if required. Should be a unix timestamp :param is_automatic: Flag to determine automated snapshots :param is_sticky: Flag indicating the snapshot is not to be deleted automatically """ timestamp = timestamp if timestamp is not None else time.time() timestamp = str(int(float(timestamp))) if is_automatic is True and is_sticky is True: raise ValueError('Snapshot {0} cannot be both automatic and sticky'.format(label)) metadata = {'label': label, 'is_consistent': is_consistent, 'timestamp': timestamp, 'machineguid': machineguid, 'is_automatic': is_automatic, 'is_sticky': is_sticky} machine = VMachine(machineguid) # @todo: we now skip creating a snapshot when a vmachine's disks # is missing a mandatory property: volume_id # sub-task will now raise an exception earlier in the workflow for disk in machine.vdisks: if not disk.volume_id: message = 'Missing volume_id on disk {0} - unable to create snapshot for vm {1}'.format( disk.guid, machine.guid ) VMachineController._logger.info('Error: {0}'.format(message)) raise RuntimeError(message) snapshots = {} success = True for disk in machine.vdisks: try: snapshots[disk.guid] = VDiskController.create_snapshot(diskguid=disk.guid, metadata=metadata) except Exception as ex: VMachineController._logger.info('Error taking snapshot of disk {0}: {1}'.format(disk.name, str(ex))) success = False for diskguid, snapshotid in snapshots.iteritems(): VDiskController.delete_snapshot(diskguid=diskguid, snapshotid=snapshotid) VMachineController._logger.info('Create snapshot for vMachine {0}: {1}'.format( machine.name, 'Success' if success else 'Failure' )) machine.invalidate_dynamics(['snapshots']) if not success: raise RuntimeError('Failed to snapshot vMachine {0}'.format(machine.name))
def delete(machineguid): """ Delete a vmachine @param machineguid: guid of the machine """ machine = VMachine(machineguid) storagedriver_mountpoint, storagedriver_storage_ip = None, None try: storagedriver = [ storagedriver for storagedriver in machine.vpool.storagedrivers if storagedriver.storagerouter.pmachine_guid == machine.pmachine_guid ][0] storagedriver_mountpoint = storagedriver.mountpoint storagedriver_storage_ip = storagedriver.storage_ip except Exception as ex: logger.debug( 'No mountpoint info could be retrieved. Reason: {0}'.format( str(ex))) storagedriver_mountpoint = None disks_info = [] for vd in machine.vdisks: for storagedriver in vd.vpool.storagedrivers: if storagedriver.storagerouter.pmachine_guid == machine.pmachine_guid: disks_info.append( (storagedriver.mountpoint, vd.devicename)) if machine.pmachine: # Allow hypervisor id node, lookup strategy is hypervisor dependent try: hypervisor_id = machine.hypervisor_id if machine.pmachine.hvtype == 'KVM': hypervisor_id = machine.name # On KVM we can lookup the machine by name, not by id hv = Factory.get(machine.pmachine) hv.delete_vm(hypervisor_id, storagedriver_mountpoint, storagedriver_storage_ip, machine.devicename, disks_info, True) except Exception as exception: logger.error('Deletion of vm on hypervisor failed: {0}'.format( str(exception)), print_msg=True) for disk in machine.vdisks: logger.debug('Deleting disk {0} with guid: {1}'.format( disk.name, disk.guid)) for junction in disk.mds_services: junction.delete() disk.delete() logger.debug('Deleting vmachine {0} with guid {1}'.format( machine.name, machine.guid)) machine.delete()
def sync_with_hypervisor(vmachineguid, storagedriver_id=None): """ Updates a given vmachine with data retreived from a given pmachine """ try: vmachine = VMachine(vmachineguid) if storagedriver_id is None and vmachine.hypervisor_id is not None and vmachine.pmachine is not None: # Only the vmachine was received, so base the sync on hypervisorid and pmachine hypervisor = Factory.get(vmachine.pmachine) logger.info('Syncing vMachine (name {})'.format(vmachine.name)) vm_object = hypervisor.get_vm_agnostic_object( vmid=vmachine.hypervisor_id) elif storagedriver_id is not None and vmachine.devicename is not None: # Storage Driver id was given, using the devicename instead (to allow hypervisorid updates # which can be caused by re-adding a vm to the inventory) pmachine = PMachineList.get_by_storagedriver_id( storagedriver_id) storagedriver = StorageDriverList.get_by_storagedriver_id( storagedriver_id) hypervisor = Factory.get(pmachine) if not hypervisor.file_exists( vmachine.vpool, hypervisor.clean_vmachine_filename( vmachine.devicename)): return vmachine.pmachine = pmachine vmachine.save() logger.info( 'Syncing vMachine (device {}, ip {}, mtpt {})'.format( vmachine.devicename, storagedriver.storage_ip, storagedriver.mountpoint)) vm_object = hypervisor.get_vm_object_by_devicename( devicename=vmachine.devicename, ip=storagedriver.storage_ip, mountpoint=storagedriver.mountpoint) else: message = 'Not enough information to sync vmachine' logger.info('Error: {0}'.format(message)) raise RuntimeError(message) except Exception as ex: logger.info('Error while fetching vMachine info: {0}'.format( str(ex))) raise if vm_object is None: message = 'Could not retreive hypervisor vmachine object' logger.info('Error: {0}'.format(message)) raise RuntimeError(message) else: VMachineController.update_vmachine_config(vmachine, vm_object)
def clone(machineguid, timestamp, name): """ Clone a vmachine using the disk snapshot based on a snapshot timestamp @param machineguid: guid of the machine to clone @param timestamp: timestamp of the disk snapshots to use for the clone @param name: name for the new machine """ machine = VMachine(machineguid) disks = {} for snapshot in machine.snapshots: if snapshot['timestamp'] == timestamp: for diskguid, snapshotguid in snapshot['snapshots'].iteritems(): disks[diskguid] = snapshotguid new_machine = VMachine() new_machine.copy(machine) new_machine.name = name new_machine.pmachine = machine.pmachine new_machine.save() new_disk_guids = [] disks_by_order = sorted(machine.vdisks, key=lambda x: x.order) for currentDisk in disks_by_order: if machine.is_vtemplate and currentDisk.templatesnapshot: snapshotid = currentDisk.templatesnapshot else: snapshotid = disks[currentDisk.guid] prefix = '%s-clone' % currentDisk.name result = VDiskController.clone(diskguid=currentDisk.guid, snapshotid=snapshotid, devicename=prefix, pmachineguid=new_machine.pmachine_guid, machinename=new_machine.name, machineguid=new_machine.guid) new_disk_guids.append(result['diskguid']) hv = Factory.get(machine.pmachine) try: result = hv.clone_vm(machine.hypervisor_id, name, disks, None, True) except: VMachineController.delete(machineguid=new_machine.guid) raise new_machine.hypervisor_id = result new_machine.save() return new_machine.guid
def setUpClass(cls): """ Sets up the unittest, mocking a certain set of 3rd party libraries and extensions. This makes sure the unittests can be executed without those libraries installed """ # Load dummy stores PersistentFactory.store = DummyPersistentStore() VolatileFactory.store = DummyVolatileStore() # Replace mocked classes sys.modules[ 'ovs.extensions.storageserver.storagedriver'] = StorageDriver # Import required modules/classes after mocking is done from ovs.dal.hybrids.vmachine import VMachine from ovs.dal.hybrids.vdisk import VDisk from ovs.extensions.generic.volatilemutex import VolatileMutex from ovs.lib.vmachine import VMachineController from ovs.lib.vdisk import VDiskController from ovs.lib.scheduledtask import ScheduledTaskController # Globalize mocked classes global VDisk global VMachine global VolatileMutex global VMachineController global VDiskController global ScheduledTaskController _ = VDisk(), VolatileMutex('dummy'), VMachine( ), VMachineController, VDiskController, ScheduledTaskController # Cleaning storage VolatileFactory.store.clean() PersistentFactory.store.clean()
def delete_snapshot(vmachineguid, timestamp): """ Remove a snapshot from the vmachine @param vmachineguid: Guid of the virtual machine @param timestamp: timestamp of the snapshot """ vmachine = VMachine(vmachineguid) vmachine_snapshots = [snap for snap in vmachine.snapshots if snap['timestamp'] == str(timestamp)] if len(vmachine_snapshots) != 1: raise RuntimeError('Snapshot {0} does not belong to vmachine {1}'.format(timestamp, vmachine.name)) vmachine_snapshot = vmachine_snapshots[0] VMachineController._logger.info('Deleting snapshot {0} from vmachine {1}'.format(timestamp, vmachine.name)) for diskguid, snapshotid in vmachine_snapshot['snapshots'].items(): VDiskController.delete_snapshot(diskguid, snapshotid) VMachineController._logger.info('Deleted snapshot {0}'.format(timestamp)) vmachine.invalidate_dynamics(['snapshots'])
def set_as_template(machineguid): """ Set a vmachine as template @param machineguid: guid of the machine @return: vmachine template conversion successful: True|False """ # Do some magic on the storage layer? # This is most likely required as extra security measure # Suppose the template is set back to a real machine # it can be deleted within vmware which should be blocked. # This might also require a storagerouter internal check # to be implemented to discourage volumes from being deleted # when clones were made from it. vmachine = VMachine(machineguid) if vmachine.hypervisor_status == 'RUNNING': raise RuntimeError( 'vMachine {0} may not be running to set it as vTemplate'. format(vmachine.name)) for disk in vmachine.vdisks: VDiskController.set_as_template(diskguid=disk.guid) vmachine.is_vtemplate = True vmachine.invalidate_dynamics(['snapshots']) vmachine.save()
def rollback(machineguid, timestamp): """ Rolls back a VM based on a given disk snapshot timestamp """ vmachine = VMachine(machineguid) if vmachine.hypervisor_status == 'RUNNING': raise RuntimeError('vMachine {0} may not be running to set it as vTemplate'.format( vmachine.name )) snapshots = [snap for snap in vmachine.snapshots if snap['timestamp'] == timestamp] if not snapshots: raise ValueError('No vmachine snapshots found for timestamp {0}'.format(timestamp)) for disk in vmachine.vdisks: VDiskController.rollback(diskguid=disk.guid, timestamp=timestamp) vmachine.invalidate_dynamics(['snapshots'])
def sync_with_hypervisor(vmachineguid, storagedriver_id=None): """ Updates a given vmachine with data retreived from a given pmachine """ try: vmachine = VMachine(vmachineguid) if storagedriver_id is None and vmachine.hypervisor_id is not None and vmachine.pmachine is not None: # Only the vmachine was received, so base the sync on hypervisorid and pmachine hypervisor = Factory.get(vmachine.pmachine) logger.info('Syncing vMachine (name {})'.format(vmachine.name)) vm_object = hypervisor.get_vm_agnostic_object(vmid=vmachine.hypervisor_id) elif storagedriver_id is not None and vmachine.devicename is not None: # Storage Driver id was given, using the devicename instead (to allow hypervisorid updates # which can be caused by re-adding a vm to the inventory) pmachine = PMachineList.get_by_storagedriver_id(storagedriver_id) storagedriver = StorageDriverList.get_by_storagedriver_id(storagedriver_id) hypervisor = Factory.get(pmachine) if not hypervisor.file_exists(vmachine.vpool, hypervisor.clean_vmachine_filename(vmachine.devicename)): return vmachine.pmachine = pmachine vmachine.save() logger.info('Syncing vMachine (device {}, ip {}, mtpt {})'.format(vmachine.devicename, storagedriver.storage_ip, storagedriver.mountpoint)) vm_object = hypervisor.get_vm_object_by_devicename(devicename=vmachine.devicename, ip=storagedriver.storage_ip, mountpoint=storagedriver.mountpoint) else: message = 'Not enough information to sync vmachine' logger.info('Error: {0}'.format(message)) raise RuntimeError(message) except Exception as ex: logger.info('Error while fetching vMachine info: {0}'.format(str(ex))) raise if vm_object is None: message = 'Could not retreive hypervisor vmachine object' logger.info('Error: {0}'.format(message)) raise RuntimeError(message) else: VMachineController.update_vmachine_config(vmachine, vm_object)
def list(self, vmachineguid=None, vpoolguid=None): """ Overview of all vDisks """ if vmachineguid is not None: vmachine = VMachine(vmachineguid) return vmachine.vdisks elif vpoolguid is not None: vpool = VPool(vpoolguid) return vpool.vdisks return VDiskList.get_vdisks()
def set_as_template(machineguid): """ Set a vmachine as template @param machineguid: guid of the machine @return: vmachine template conversion successful: True|False """ # Do some magic on the storage layer? # This is most likely required as extra security measure # Suppose the template is set back to a real machine # it can be deleted within vmware which should be blocked. # This might also require a storagerouter internal check # to be implemented to discourage volumes from being deleted # when clones were made from it. vmachine = VMachine(machineguid) if vmachine.hypervisor_status == 'RUNNING': raise RuntimeError('vMachine {0} may not be running to set it as vTemplate'.format(vmachine.name)) for disk in vmachine.vdisks: VDiskController.set_as_template(diskguid=disk.guid) vmachine.is_vtemplate = True vmachine.invalidate_dynamics(['snapshots']) vmachine.save()
def delete(machineguid): """ Delete a vmachine @param machineguid: guid of the machine """ machine = VMachine(machineguid) storagedriver_mountpoint, storagedriver_storage_ip = None, None try: storagedriver = [storagedriver for storagedriver in machine.vpool.storagedrivers if storagedriver.storagerouter.pmachine_guid == machine.pmachine_guid][0] storagedriver_mountpoint = storagedriver.mountpoint storagedriver_storage_ip = storagedriver.storage_ip except Exception as ex: VMachineController._logger.debug('No mountpoint info could be retrieved. Reason: {0}'.format(str(ex))) storagedriver_mountpoint = None disks_info = [] for vd in machine.vdisks: for storagedriver in vd.vpool.storagedrivers: if storagedriver.storagerouter.pmachine_guid == machine.pmachine_guid: disks_info.append((storagedriver.mountpoint, vd.devicename)) if machine.pmachine: # Allow hypervisor id node, lookup strategy is hypervisor dependent try: hypervisor_id = machine.hypervisor_id if machine.pmachine.hvtype == 'KVM': hypervisor_id = machine.name # On KVM we can lookup the machine by name, not by id hv = Factory.get(machine.pmachine) hv.delete_vm(hypervisor_id, storagedriver_mountpoint, storagedriver_storage_ip, machine.devicename, disks_info, True) except Exception as exception: VMachineController._logger.error('Deletion of vm on hypervisor failed: {0}'.format(str(exception)), print_msg=True) for disk in machine.vdisks: VMachineController._logger.debug('Deleting disk {0} with guid: {1}'.format(disk.name, disk.guid)) for junction in disk.mds_services: junction.delete() disk.delete() VMachineController._logger.debug('Deleting vmachine {0} with guid {1}'.format(machine.name, machine.guid)) machine.delete()
def setUpClass(cls): """ Sets up the unittest, mocking a certain set of 3rd party libraries and extensions. This makes sure the unittests can be executed without those libraries installed """ # Load dummy stores PersistentFactory.store = DummyPersistentStore() VolatileFactory.store = DummyVolatileStore() # Replace mocked classes sys.modules[ 'ovs.extensions.storageserver.storagedriver'] = StorageDriverModule sys.modules['ovs.extensions.hypervisor.hypervisors.kvm'] = KVMModule # Import required modules/classes after mocking is done from ovs.dal.hybrids.backendtype import BackendType from ovs.dal.hybrids.vdisk import VDisk from ovs.dal.hybrids.j_mdsservice import MDSService from ovs.dal.hybrids.j_mdsservicevdisk import MDSServiceVDisk from ovs.lib.vdisk import VDiskController from ovs.dal.hybrids.pmachine import PMachine from ovs.dal.hybrids.vmachine import VMachine from ovs.dal.hybrids.vpool import VPool from ovs.dal.hybrids.storagedriver import StorageDriver from ovs.dal.hybrids.storagerouter import StorageRouter from ovs.dal.hybrids.failuredomain import FailureDomain from ovs.dal.hybrids.service import Service from ovs.dal.hybrids.servicetype import ServiceType from ovs.dal.lists.vdisklist import VDiskList from ovs.lib.mdsservice import MDSServiceController # Globalize mocked classes global VDisk global VDiskController global PMachine global VMachine global BackendType global VPool global StorageDriver global StorageRouter global FailureDomain global MDSService global MDSServiceVDisk global Service global ServiceType global VDiskList global MDSServiceController _ = VDisk(), PMachine(), VMachine(), VDiskController, VPool(), BackendType(), StorageDriver(), StorageRouter(), \ FailureDomain(), MDSService(), MDSServiceVDisk(), Service(), ServiceType(), VDiskList, MDSServiceController # Cleaning storage VolatileFactory.store.clean() PersistentFactory.store.clean()
def list(self, vmachineguid=None, vpoolguid=None): """ Overview of all vDisks :param vmachineguid: Guid of the virtual machine to retrieve its disks :param vpoolguid: Guid of the vPool to retrieve its disks """ if vmachineguid is not None: vmachine = VMachine(vmachineguid) return vmachine.vdisks elif vpoolguid is not None: vpool = VPool(vpoolguid) return vpool.vdisks return VDiskList.get_vdisks()
def clone(diskguid, snapshotid, devicename, pmachineguid, machinename, machineguid=None, **kwargs): """ Clone a disk @param location: location where virtual device should be created (eg: myVM) @param devicename: device file name for the disk (eg: mydisk-flat.vmdk) @param parentdiskguid: guid of the disk @param snapshotid: guid of the snapshot @param machineguid: guid of the machine to assign disk to """ _ = kwargs pmachine = PMachine(pmachineguid) hypervisor = Factory.get(pmachine) description = '{} {}'.format(machinename, devicename) properties_to_clone = [ 'description', 'size', 'type', 'retentionpolicyguid', 'snapshotpolicyguid', 'autobackup' ] new_disk = VDisk() disk = VDisk(diskguid) _log = 'Clone snapshot {} of disk {} to location {}' _location = hypervisor.get_backing_disk_path(machinename, devicename) _id = '{}'.format(disk.volume_id) _snap = '{}'.format(snapshotid) logger.info(_log.format(_snap, disk.name, _location)) volume_id = disk.storagedriver_client.create_clone( _location, _id, _snap) new_disk.copy(disk, include=properties_to_clone) new_disk.parent_vdisk = disk new_disk.name = '{}-clone'.format(disk.name) new_disk.description = description new_disk.volume_id = volume_id new_disk.devicename = hypervisor.clean_backing_disk_filename(_location) new_disk.parentsnapshot = snapshotid new_disk.vmachine = VMachine( machineguid) if machineguid else disk.vmachine new_disk.vpool = disk.vpool new_disk.save() return { 'diskguid': new_disk.guid, 'name': new_disk.name, 'backingdevice': _location }
def setUpClass(cls): """ Sets up the unittest, mocking a certain set of 3rd party libraries and extensions. This makes sure the unittests can be executed without those libraries installed """ # Load dummy stores PersistentFactory.store = DummyPersistentStore() VolatileFactory.store = DummyVolatileStore() # Replace mocked classes sys.modules[ 'ovs.extensions.storageserver.storagedriver'] = StorageDriverModule # Import required modules/classes after mocking is done from ovs.dal.hybrids.backendtype import BackendType from ovs.dal.hybrids.disk import Disk from ovs.dal.hybrids.diskpartition import DiskPartition from ovs.dal.hybrids.failuredomain import FailureDomain from ovs.dal.hybrids.pmachine import PMachine from ovs.dal.hybrids.storagerouter import StorageRouter from ovs.dal.hybrids.vdisk import VDisk from ovs.dal.hybrids.vmachine import VMachine from ovs.dal.hybrids.vpool import VPool from ovs.extensions.generic.volatilemutex import VolatileMutex from ovs.lib.vmachine import VMachineController from ovs.lib.vdisk import VDiskController from ovs.lib.scheduledtask import ScheduledTaskController # Globalize mocked classes global Disk global VDisk global VMachine global PMachine global VPool global BackendType global DiskPartition global FailureDomain global StorageRouter global VolatileMutex global VMachineController global VDiskController global ScheduledTaskController _ = VDisk(), VolatileMutex('dummy'), VMachine(), PMachine(), VPool(), BackendType(), FailureDomain(), \ VMachineController, VDiskController, ScheduledTaskController, StorageRouter(), Disk(), DiskPartition() # Cleaning storage VolatileFactory.store.clean() PersistentFactory.store.clean()
def create_from_template(diskguid, machinename, devicename, pmachineguid, machineguid=None, storagedriver_guid=None): """ Create a disk from a template @param parentdiskguid: guid of the disk @param location: location where virtual device should be created (eg: myVM) @param devicename: device file name for the disk (eg: mydisk-flat.vmdk) @param machineguid: guid of the machine to assign disk to @return diskguid: guid of new disk """ pmachine = PMachine(pmachineguid) hypervisor = Factory.get(pmachine) disk_path = hypervisor.get_disk_path(machinename, devicename) description = '{} {}'.format(machinename, devicename) properties_to_clone = [ 'description', 'size', 'type', 'retentionpolicyid', 'snapshotpolicyid', 'vmachine', 'vpool' ] disk = VDisk(diskguid) if disk.vmachine and not disk.vmachine.is_vtemplate: # Disk might not be attached to a vmachine, but still be a template raise RuntimeError('The given disk does not belong to a template') if storagedriver_guid is not None: storagedriver_id = StorageDriver( storagedriver_guid).storagedriver_id else: storagedriver_id = disk.storagedriver_id new_disk = VDisk() new_disk.copy(disk, include=properties_to_clone) new_disk.vpool = disk.vpool new_disk.devicename = hypervisor.clean_backing_disk_filename(disk_path) new_disk.parent_vdisk = disk new_disk.name = '{}-clone'.format(disk.name) new_disk.description = description new_disk.vmachine = VMachine( machineguid) if machineguid else disk.vmachine new_disk.save() logger.info( 'Create disk from template {} to new disk {} to location {}'. format(disk.name, new_disk.name, disk_path)) try: volume_id = disk.storagedriver_client.create_clone_from_template( disk_path, str(disk.volume_id), node_id=str(storagedriver_id)) new_disk.volume_id = volume_id new_disk.save() except Exception as ex: logger.error( 'Clone disk on volumedriver level failed with exception: {0}'. format(str(ex))) new_disk.delete() raise return { 'diskguid': new_disk.guid, 'name': new_disk.name, 'backingdevice': disk_path }
def _prepare(self): # Setup failure_domain = FailureDomain() failure_domain.name = 'Test' failure_domain.save() backend_type = BackendType() backend_type.name = 'BackendType' backend_type.code = 'BT' backend_type.save() vpool = VPool() vpool.name = 'vpool' vpool.backend_type = backend_type vpool.save() pmachine = PMachine() pmachine.name = 'PMachine' pmachine.username = '******' pmachine.ip = '127.0.0.1' pmachine.hvtype = 'KVM' pmachine.save() vmachine_1 = VMachine() vmachine_1.name = 'vmachine_1' vmachine_1.devicename = 'dummy' vmachine_1.pmachine = pmachine vmachine_1.is_vtemplate = True vmachine_1.save() vdisk_1_1 = VDisk() vdisk_1_1.name = 'vdisk_1_1' vdisk_1_1.volume_id = 'vdisk_1_1' vdisk_1_1.vmachine = vmachine_1 vdisk_1_1.vpool = vpool vdisk_1_1.devicename = 'dummy' vdisk_1_1.size = 0 vdisk_1_1.save() vdisk_1_1.reload_client() storage_router = StorageRouter() storage_router.name = 'storage_router' storage_router.ip = '127.0.0.1' storage_router.pmachine = pmachine storage_router.machine_id = System.get_my_machine_id() storage_router.rdma_capable = False storage_router.primary_failure_domain = failure_domain storage_router.save() storagedriver = StorageDriver() storagedriver.vpool = vpool storagedriver.storagerouter = storage_router storagedriver.name = '1' storagedriver.mountpoint = '/' storagedriver.cluster_ip = storage_router.ip storagedriver.storage_ip = '127.0.0.1' storagedriver.storagedriver_id = '1' storagedriver.ports = [1, 2, 3] storagedriver.save() service_type = ServiceType() service_type.name = 'MetadataServer' service_type.save() s_id = '{0}-{1}'.format(storagedriver.storagerouter.name, '1') service = Service() service.name = s_id service.storagerouter = storagedriver.storagerouter service.ports = [1] service.type = service_type service.save() mds_service = MDSService() mds_service.service = service mds_service.number = 0 mds_service.capacity = 10 mds_service.vpool = storagedriver.vpool mds_service.save() def ensure_safety(vdisk): pass class Dtl_Checkup(): @staticmethod def delay(vpool_guid=None, vdisk_guid=None, storagerouters_to_exclude=None): pass MDSServiceController.ensure_safety = staticmethod(ensure_safety) VDiskController.dtl_checkup = Dtl_Checkup return vdisk_1_1, pmachine
def clone(machineguid, timestamp, name): """ Clone a vmachine using the disk snapshot based on a snapshot timestamp @param machineguid: guid of the machine to clone @param timestamp: timestamp of the disk snapshots to use for the clone @param name: name for the new machine """ machine = VMachine(machineguid) disks = {} for snapshot in machine.snapshots: if snapshot['timestamp'] == timestamp: for diskguid, snapshotguid in snapshot['snapshots'].iteritems( ): disks[diskguid] = snapshotguid new_machine = VMachine() new_machine.copy(machine) new_machine.name = name new_machine.pmachine = machine.pmachine new_machine.save() new_disk_guids = [] disks_by_order = sorted(machine.vdisks, key=lambda x: x.order) for currentDisk in disks_by_order: if machine.is_vtemplate and currentDisk.templatesnapshot: snapshotid = currentDisk.templatesnapshot else: snapshotid = disks[currentDisk.guid] prefix = '%s-clone' % currentDisk.name result = VDiskController.clone( diskguid=currentDisk.guid, snapshotid=snapshotid, devicename=prefix, pmachineguid=new_machine.pmachine_guid, machinename=new_machine.name, machineguid=new_machine.guid) new_disk_guids.append(result['diskguid']) hv = Factory.get(machine.pmachine) try: result = hv.clone_vm(machine.hypervisor_id, name, disks, None, True) except: VMachineController.delete(machineguid=new_machine.guid) raise new_machine.hypervisor_id = result new_machine.save() return new_machine.guid
def test_happypath(self): """ Validates the happy path; Hourly snapshots are taken with a few manual consistents every now an then. The delelete policy is exectued every day """ # Setup # There are 2 machines; one with two disks, one with one disk and an additional disk backend_type = BackendType() backend_type.name = 'BackendType' backend_type.code = 'BT' backend_type.save() vpool = VPool() vpool.name = 'vpool' vpool.backend_type = backend_type vpool.save() pmachine = PMachine() pmachine.name = 'PMachine' pmachine.username = '******' pmachine.ip = '127.0.0.1' pmachine.hvtype = 'VMWARE' pmachine.save() vmachine_1 = VMachine() vmachine_1.name = 'vmachine_1' vmachine_1.devicename = 'dummy' vmachine_1.pmachine = pmachine vmachine_1.save() vdisk_1_1 = VDisk() vdisk_1_1.name = 'vdisk_1_1' vdisk_1_1.volume_id = 'vdisk_1_1' vdisk_1_1.vmachine = vmachine_1 vdisk_1_1.vpool = vpool vdisk_1_1.devicename = 'dummy' vdisk_1_1.size = 0 vdisk_1_1.save() vdisk_1_1.reload_client() vdisk_1_2 = VDisk() vdisk_1_2.name = 'vdisk_1_2' vdisk_1_2.volume_id = 'vdisk_1_2' vdisk_1_2.vmachine = vmachine_1 vdisk_1_2.vpool = vpool vdisk_1_2.devicename = 'dummy' vdisk_1_2.size = 0 vdisk_1_2.save() vdisk_1_2.reload_client() vmachine_2 = VMachine() vmachine_2.name = 'vmachine_2' vmachine_2.devicename = 'dummy' vmachine_2.pmachine = pmachine vmachine_2.save() vdisk_2_1 = VDisk() vdisk_2_1.name = 'vdisk_2_1' vdisk_2_1.volume_id = 'vdisk_2_1' vdisk_2_1.vmachine = vmachine_2 vdisk_2_1.vpool = vpool vdisk_2_1.devicename = 'dummy' vdisk_2_1.size = 0 vdisk_2_1.save() vdisk_2_1.reload_client() vdisk_3 = VDisk() vdisk_3.name = 'vdisk_3' vdisk_3.volume_id = 'vdisk_3' vdisk_3.vpool = vpool vdisk_3.devicename = 'dummy' vdisk_3.size = 0 vdisk_3.save() vdisk_3.reload_client() for disk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: [dynamic for dynamic in disk._dynamics if dynamic.name == 'snapshots'][0].timeout = 0 # Run the testing scenario debug = True amount_of_days = 50 base = datetime.now().date() day = timedelta(1) minute = 60 hour = minute * 60 for d in xrange(0, amount_of_days): base_timestamp = DeleteSnapshots._make_timestamp(base, day * d) print '' print 'Day cycle: {}: {}'.format( d, datetime.fromtimestamp(base_timestamp).strftime('%Y-%m-%d') ) # At the start of the day, delete snapshot policy runs at 00:30 print '- Deleting snapshots' ScheduledTaskController.deletescrubsnapshots(timestamp=base_timestamp + (minute * 30)) # Validate snapshots print '- Validating snapshots' for vdisk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: self._validate(vdisk, d, base, amount_of_days, debug) # During the day, snapshots are taken # - Create non consistent snapshot every hour, between 2:00 and 22:00 # - Create consistent snapshot at 6:30, 12:30, 18:30 print '- Creating snapshots' for h in xrange(2, 23): timestamp = base_timestamp + (hour * h) for vm in [vmachine_1, vmachine_2]: VMachineController.snapshot(machineguid=vm.guid, label='ss_i_{0}:00'.format(str(h)), is_consistent=False, timestamp=timestamp) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VMachineController.snapshot(machineguid=vm.guid, label='ss_c_{0}:30'.format(str(h)), is_consistent=True, timestamp=ts) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={'label': 'ss_i_{0}:00'.format(str(h)), 'is_consistent': False, 'timestamp': str(timestamp), 'machineguid': None}) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={'label': 'ss_c_{0}:30'.format(str(h)), 'is_consistent': True, 'timestamp': str(ts), 'machineguid': None})
def test_happypath(self): """ Validates the happy path; Hourly snapshots are taken with a few manual consistents every now an then. The delelete policy is exectued every day """ # Setup # There are 2 machines; one with two disks, one with one disk and an additional disk vpool = VPool() vpool.name = 'vpool' vpool.backend_type = BackendType() vpool.save() vmachine_1 = VMachine() vmachine_1.name = 'vmachine_1' vmachine_1.devicename = 'dummy' vmachine_1.pmachine = PMachine() vmachine_1.save() vdisk_1_1 = VDisk() vdisk_1_1.name = 'vdisk_1_1' vdisk_1_1.volume_id = 'vdisk_1_1' vdisk_1_1.vmachine = vmachine_1 vdisk_1_1.vpool = vpool vdisk_1_1.devicename = 'dummy' vdisk_1_1.size = 0 vdisk_1_1.save() vdisk_1_1.reload_client() vdisk_1_2 = VDisk() vdisk_1_2.name = 'vdisk_1_2' vdisk_1_2.volume_id = 'vdisk_1_2' vdisk_1_2.vmachine = vmachine_1 vdisk_1_2.vpool = vpool vdisk_1_2.devicename = 'dummy' vdisk_1_2.size = 0 vdisk_1_2.save() vdisk_1_2.reload_client() vmachine_2 = VMachine() vmachine_2.name = 'vmachine_2' vmachine_2.devicename = 'dummy' vmachine_2.pmachine = PMachine() vmachine_2.save() vdisk_2_1 = VDisk() vdisk_2_1.name = 'vdisk_2_1' vdisk_2_1.volume_id = 'vdisk_2_1' vdisk_2_1.vmachine = vmachine_2 vdisk_2_1.vpool = vpool vdisk_2_1.devicename = 'dummy' vdisk_2_1.size = 0 vdisk_2_1.save() vdisk_2_1.reload_client() vdisk_3 = VDisk() vdisk_3.name = 'vdisk_3' vdisk_3.volume_id = 'vdisk_3' vdisk_3.vpool = vpool vdisk_3.devicename = 'dummy' vdisk_3.size = 0 vdisk_3.save() vdisk_3.reload_client() for disk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: [dynamic for dynamic in disk._dynamics if dynamic.name == 'snapshots'][0].timeout = 0 # Run the testing scenario debug = True amount_of_days = 50 now = int(mktime(datetime.now().date().timetuple())) # Last night minute = 60 hour = minute * 60 day = hour * 24 for d in xrange(0, amount_of_days): base_timestamp = now + (day * d) print '' print 'Day cycle: {}: {}'.format( d, datetime.fromtimestamp(base_timestamp).strftime('%Y-%m-%d') ) # At the start of the day, delete snapshot policy runs at 00:30 print '- Deleting snapshots' ScheduledTaskController.deletescrubsnapshots(timestamp=base_timestamp + (minute * 30)) # Validate snapshots print '- Validating snapshots' for vdisk in [vdisk_3]: # [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: self._validate(vdisk, d, now, amount_of_days, debug) # During the day, snapshots are taken # - Create non consistent snapshot every hour, between 2:00 and 22:00 # - Create consistent snapshot at 6:30, 12:30, 18:30 print '- Creating snapshots' for h in xrange(2, 23): timestamp = base_timestamp + (hour * h) for vm in [vmachine_1, vmachine_2]: VMachineController.snapshot(machineguid=vm.guid, label='ss_i_{}:00'.format(str(h)), is_consistent=False, timestamp=timestamp) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VMachineController.snapshot(machineguid=vm.guid, label='ss_c_{}:30'.format(str(h)), is_consistent=True, timestamp=ts) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={'label': 'ss_i_{}:00'.format(str(h)), 'is_consistent': False, 'timestamp': timestamp, 'machineguid': None}) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={'label': 'ss_c_{}:30'.format(str(h)), 'is_consistent': True, 'timestamp': ts, 'machineguid': None})
def create_from_template(name, machineguid, pmachineguid, description=None): """ Create a new vmachine using an existing vmachine template :param machineguid: guid of the template vmachine :param name: name of new vmachine :param pmachineguid: guid of hypervisor to create new vmachine on :param description: Description for the machine :return: guid of the newly created vmachine | False on any failure """ template_vm = VMachine(machineguid) if not template_vm.is_vtemplate: return False target_pm = PMachine(pmachineguid) target_hypervisor = Factory.get(target_pm) storagerouters = [sr for sr in StorageRouterList.get_storagerouters() if sr.pmachine_guid == target_pm.guid] if len(storagerouters) == 1: target_storagerouter = storagerouters[0] else: raise ValueError('Pmachine {0} has no StorageRouter assigned to it'.format(pmachineguid)) routing_key = "sr.{0}".format(target_storagerouter.machine_id) vpool = None vpool_guids = set() if template_vm.vpool is not None: vpool = template_vm.vpool vpool_guids.add(vpool.guid) for disk in template_vm.vdisks: vpool = disk.vpool vpool_guids.add(vpool.guid) if len(vpool_guids) != 1: raise RuntimeError('Only 1 vpool supported on template disk(s) - {0} found!'.format(len(vpool_guids))) if not template_vm.pmachine.hvtype == target_pm.hvtype: raise RuntimeError('Source and target hypervisor not identical') # Currently, only one vPool is supported, so we can just use whatever the `vpool` variable above # was set to as 'the' vPool for the code below. This obviously will have to change once vPool mixes # are supported. target_storagedriver = None source_storagedriver = None for vpool_storagedriver in vpool.storagedrivers: if vpool_storagedriver.storagerouter.pmachine_guid == target_pm.guid: target_storagedriver = vpool_storagedriver if vpool_storagedriver.storagerouter.pmachine_guid == template_vm.pmachine_guid: source_storagedriver = vpool_storagedriver if target_storagedriver is None: raise RuntimeError('Volume not served on target hypervisor') source_hv = Factory.get(template_vm.pmachine) target_hv = Factory.get(target_pm) if not source_hv.is_datastore_available(source_storagedriver.storage_ip, source_storagedriver.mountpoint): raise RuntimeError('Datastore unavailable on source hypervisor') if not target_hv.is_datastore_available(target_storagedriver.storage_ip, target_storagedriver.mountpoint): raise RuntimeError('Datastore unavailable on target hypervisor') source_vm = source_hv.get_vm_object(template_vm.hypervisor_id) if not source_vm: raise RuntimeError('VM with key reference {0} not found'.format(template_vm.hypervisor_id)) name_duplicates = VMachineList.get_vmachine_by_name(name) if name_duplicates is not None and len(name_duplicates) > 0: raise RuntimeError('A vMachine with name {0} already exists'.format(name)) vm_path = target_hypervisor.get_vmachine_path(name, target_storagedriver.storagerouter.machine_id) new_vm = VMachine() new_vm.copy(template_vm) new_vm.hypervisor_id = '' new_vm.vpool = template_vm.vpool new_vm.pmachine = target_pm new_vm.name = name new_vm.description = description new_vm.is_vtemplate = False new_vm.devicename = target_hypervisor.clean_vmachine_filename(vm_path) new_vm.status = 'CREATED' new_vm.save() storagedrivers = [storagedriver for storagedriver in vpool.storagedrivers if storagedriver.storagerouter.pmachine_guid == new_vm.pmachine_guid] if len(storagedrivers) == 0: raise RuntimeError('Cannot find Storage Driver serving {0} on {1}'.format(vpool.name, new_vm.pmachine.name)) disks = [] disks_by_order = sorted(template_vm.vdisks, key=lambda x: x.order) for disk in disks_by_order: try: prefix = '{0}-clone'.format(disk.name) result = VDiskController.create_from_template( diskguid=disk.guid, devicename=prefix, pmachineguid=target_pm.guid, machinename=new_vm.name, machineguid=new_vm.guid ) disks.append(result) VMachineController._logger.debug('Disk appended: {0}'.format(result)) except Exception as exception: VMachineController._logger.error('Creation of disk {0} failed: {1}'.format(disk.name, str(exception)), print_msg=True) VMachineController.delete.s(machineguid=new_vm.guid).apply_async(routing_key = routing_key) raise try: result = target_hv.create_vm_from_template( name, source_vm, disks, target_storagedriver.storage_ip, target_storagedriver.mountpoint, wait=True ) except Exception as exception: VMachineController._logger.error('Creation of vm {0} on hypervisor failed: {1}'.format(new_vm.name, str(exception)), print_msg=True) VMachineController.delete.s(machineguid=new_vm.guid).apply_async(routing_key = routing_key) raise new_vm.hypervisor_id = result new_vm.status = 'SYNC' new_vm.save() return new_vm.guid
def create_from_template(name, machineguid, pmachineguid, description=None): """ Create a new vmachine using an existing vmachine template @param machineguid: guid of the template vmachine @param name: name of new vmachine @param pmachineguid: guid of hypervisor to create new vmachine on @return: guid of the newly created vmachine | False on any failure """ template_vm = VMachine(machineguid) if not template_vm.is_vtemplate: return False target_pm = PMachine(pmachineguid) target_hypervisor = Factory.get(target_pm) storagerouters = [ sr for sr in StorageRouterList.get_storagerouters() if sr.pmachine_guid == target_pm.guid ] if len(storagerouters) == 1: target_storagerouter = storagerouters[0] else: raise ValueError( 'Pmachine {} has no StorageRouter assigned to it'.format( pmachineguid)) routing_key = "sr.{0}".format(target_storagerouter.machine_id) vpool = None vpool_guids = set() if template_vm.vpool is not None: vpool = template_vm.vpool vpool_guids.add(vpool.guid) for disk in template_vm.vdisks: vpool = disk.vpool vpool_guids.add(vpool.guid) if len(vpool_guids) != 1: raise RuntimeError( 'Only 1 vpool supported on template disk(s) - {0} found!'. format(len(vpool_guids))) if not template_vm.pmachine.hvtype == target_pm.hvtype: raise RuntimeError('Source and target hypervisor not identical') # Currently, only one vPool is supported, so we can just use whatever the `vpool` variable above # was set to as 'the' vPool for the code below. This obviously will have to change once vPool mixes # are supported. target_storagedriver = None source_storagedriver = None for vpool_storagedriver in vpool.storagedrivers: if vpool_storagedriver.storagerouter.pmachine_guid == target_pm.guid: target_storagedriver = vpool_storagedriver if vpool_storagedriver.storagerouter.pmachine_guid == template_vm.pmachine_guid: source_storagedriver = vpool_storagedriver if target_storagedriver is None: raise RuntimeError('Volume not served on target hypervisor') source_hv = Factory.get(template_vm.pmachine) target_hv = Factory.get(target_pm) if not source_hv.is_datastore_available( source_storagedriver.storage_ip, source_storagedriver.mountpoint): raise RuntimeError('Datastore unavailable on source hypervisor') if not target_hv.is_datastore_available( target_storagedriver.storage_ip, target_storagedriver.mountpoint): raise RuntimeError('Datastore unavailable on target hypervisor') source_vm = source_hv.get_vm_object(template_vm.hypervisor_id) if not source_vm: raise RuntimeError('VM with key reference {0} not found'.format( template_vm.hypervisor_id)) name_duplicates = VMachineList.get_vmachine_by_name(name) if name_duplicates is not None and len(name_duplicates) > 0: raise RuntimeError( 'A vMachine with name {0} already exists'.format(name)) vm_path = target_hypervisor.get_vmachine_path( name, target_storagedriver.storagerouter.machine_id) new_vm = VMachine() new_vm.copy(template_vm) new_vm.hypervisor_id = '' new_vm.vpool = template_vm.vpool new_vm.pmachine = target_pm new_vm.name = name new_vm.description = description new_vm.is_vtemplate = False new_vm.devicename = target_hypervisor.clean_vmachine_filename(vm_path) new_vm.status = 'CREATED' new_vm.save() storagedrivers = [ storagedriver for storagedriver in vpool.storagedrivers if storagedriver.storagerouter.pmachine_guid == new_vm.pmachine_guid ] if len(storagedrivers) == 0: raise RuntimeError( 'Cannot find Storage Driver serving {0} on {1}'.format( vpool.name, new_vm.pmachine.name)) storagedriverguid = storagedrivers[0].guid disks = [] disks_by_order = sorted(template_vm.vdisks, key=lambda x: x.order) try: for disk in disks_by_order: prefix = '{0}-clone'.format(disk.name) result = VDiskController.create_from_template( diskguid=disk.guid, devicename=prefix, pmachineguid=target_pm.guid, machinename=new_vm.name, machineguid=new_vm.guid, storagedriver_guid=storagedriverguid) disks.append(result) logger.debug('Disk appended: {0}'.format(result)) except Exception as exception: logger.error('Creation of disk {0} failed: {1}'.format( disk.name, str(exception)), print_msg=True) VMachineController.delete.s(machineguid=new_vm.guid).apply_async( routing_key=routing_key) raise try: result = target_hv.create_vm_from_template( name, source_vm, disks, target_storagedriver.storage_ip, target_storagedriver.mountpoint, wait=True) except Exception as exception: logger.error('Creation of vm {0} on hypervisor failed: {1}'.format( new_vm.name, str(exception)), print_msg=True) VMachineController.delete.s(machineguid=new_vm.guid).apply_async( routing_key=routing_key) raise new_vm.hypervisor_id = result new_vm.status = 'SYNC' new_vm.save() return new_vm.guid
def clone(diskguid, snapshotid, devicename, pmachineguid, machinename, machineguid=None): """ Clone a disk """ pmachine = PMachine(pmachineguid) hypervisor = Factory.get(pmachine) description = '{} {}'.format(machinename, devicename) properties_to_clone = [ 'description', 'size', 'type', 'retentionpolicyguid', 'snapshotpolicyguid', 'autobackup' ] vdisk = VDisk(diskguid) location = hypervisor.get_backing_disk_path(machinename, devicename) new_vdisk = VDisk() new_vdisk.copy(vdisk, include=properties_to_clone) new_vdisk.parent_vdisk = vdisk new_vdisk.name = '{0}-clone'.format(vdisk.name) new_vdisk.description = description new_vdisk.devicename = hypervisor.clean_backing_disk_filename(location) new_vdisk.parentsnapshot = snapshotid new_vdisk.vmachine = VMachine( machineguid) if machineguid else vdisk.vmachine new_vdisk.vpool = vdisk.vpool new_vdisk.save() try: storagedriver = StorageDriverList.get_by_storagedriver_id( vdisk.storagedriver_id) if storagedriver is None: raise RuntimeError( 'Could not find StorageDriver with id {0}'.format( vdisk.storagedriver_id)) mds_service = MDSServiceController.get_preferred_mds( storagedriver.storagerouter, vdisk.vpool) if mds_service is None: raise RuntimeError('Could not find a MDS service') logger.info('Clone snapshot {} of disk {} to location {}'.format( snapshotid, vdisk.name, location)) volume_id = vdisk.storagedriver_client.create_clone( target_path=location, metadata_backend_config=MDSMetaDataBackendConfig([ MDSNodeConfig(address=str( mds_service.service.storagerouter.ip), port=mds_service.service.ports[0]) ]), parent_volume_id=str(vdisk.volume_id), parent_snapshot_id=str(snapshotid), node_id=str(vdisk.storagedriver_id)) except Exception as ex: logger.error( 'Caught exception during clone, trying to delete the volume. {0}' .format(ex)) new_vdisk.delete() VDiskController.delete_volume(location) raise new_vdisk.volume_id = volume_id new_vdisk.save() try: MDSServiceController.ensure_safety(new_vdisk) except Exception as ex: logger.error( 'Caught exception during "ensure_safety" {0}'.format(ex)) return { 'diskguid': new_vdisk.guid, 'name': new_vdisk.name, 'backingdevice': location }
def clone(machineguid, timestamp, name): """ Clone a vmachine using the disk snapshot based on a snapshot timestamp @param machineguid: guid of the machine to clone @param timestamp: timestamp of the disk snapshots to use for the clone @param name: name for the new machine """ machine = VMachine(machineguid) timestamp = str(timestamp) if timestamp not in (snap['timestamp'] for snap in machine.snapshots): raise RuntimeError('Invalid timestamp provided, not a valid snapshot of this vmachine.') vpool = None storagerouter = None if machine.pmachine is not None and machine.pmachine.hvtype == 'VMWARE': for vdisk in machine.vdisks: if vdisk.vpool is not None: vpool = vdisk.vpool break for vdisk in machine.vdisks: if vdisk.storagerouter_guid: storagerouter = StorageRouter(vdisk.storagerouter_guid) break hv = Factory.get(machine.pmachine) vm_path = hv.get_vmachine_path(name, storagerouter.machine_id if storagerouter is not None else '') # mutex in sync_with_hypervisor uses "None" for KVM hvtype mutex = volatile_mutex('{0}_{1}'.format(hv.clean_vmachine_filename(vm_path), vpool.guid if vpool is not None else 'none')) disks = {} for snapshot in machine.snapshots: if snapshot['timestamp'] == timestamp: for diskguid, snapshotguid in snapshot['snapshots'].iteritems(): disks[diskguid] = snapshotguid try: mutex.acquire(wait=120) new_machine = VMachine() new_machine.copy(machine) new_machine.name = name new_machine.devicename = hv.clean_vmachine_filename(vm_path) new_machine.pmachine = machine.pmachine new_machine.save() finally: mutex.release() new_disk_guids = [] vm_disks = [] mountpoint = None disks_by_order = sorted(machine.vdisks, key=lambda x: x.order) try: for currentDisk in disks_by_order: if machine.is_vtemplate and currentDisk.templatesnapshot: snapshotid = currentDisk.templatesnapshot else: snapshotid = disks[currentDisk.guid] prefix = '%s-clone' % currentDisk.name result = VDiskController.clone(diskguid=currentDisk.guid, snapshotid=snapshotid, devicename=prefix, pmachineguid=new_machine.pmachine_guid, machinename=new_machine.name, machineguid=new_machine.guid) new_disk_guids.append(result['diskguid']) mountpoint = StorageDriverList.get_by_storagedriver_id(currentDisk.storagedriver_id).mountpoint vm_disks.append(result) except Exception as ex: VMachineController._logger.error('Failed to clone disks. {0}'.format(ex)) VMachineController.delete(machineguid=new_machine.guid) raise try: result = hv.clone_vm(machine.hypervisor_id, name, vm_disks, mountpoint) except Exception as ex: VMachineController._logger.error('Failed to clone vm. {0}'.format(ex)) VMachineController.delete(machineguid=new_machine.guid) raise try: mutex.acquire(wait=120) new_machine.hypervisor_id = result new_machine.save() finally: mutex.release() return new_machine.guid
def test_happypath(self): """ Validates the happy path; Hourly snapshots are taken with a few manual consistent every now an then. The delete policy is executed every day """ # Setup # There are 2 machines; one with two disks, one with one disk and a stand-alone additional disk failure_domain = FailureDomain() failure_domain.name = 'Test' failure_domain.save() backend_type = BackendType() backend_type.name = 'BackendType' backend_type.code = 'BT' backend_type.save() vpool = VPool() vpool.name = 'vpool' vpool.status = 'RUNNING' vpool.backend_type = backend_type vpool.save() pmachine = PMachine() pmachine.name = 'PMachine' pmachine.username = '******' pmachine.ip = '127.0.0.1' pmachine.hvtype = 'VMWARE' pmachine.save() storage_router = StorageRouter() storage_router.name = 'storage_router' storage_router.ip = '127.0.0.1' storage_router.pmachine = pmachine storage_router.machine_id = System.get_my_machine_id() storage_router.rdma_capable = False storage_router.primary_failure_domain = failure_domain storage_router.save() disk = Disk() disk.name = 'physical_disk_1' disk.path = '/dev/non-existent' disk.size = 500 * 1024 ** 3 disk.state = 'OK' disk.is_ssd = True disk.storagerouter = storage_router disk.save() disk_partition = DiskPartition() disk_partition.id = 'disk_partition_id' disk_partition.disk = disk disk_partition.path = '/dev/disk/non-existent' disk_partition.size = 400 * 1024 ** 3 disk_partition.state = 'OK' disk_partition.offset = 1024 disk_partition.roles = [DiskPartition.ROLES.SCRUB] disk_partition.mountpoint = '/var/tmp' disk_partition.save() vmachine_1 = VMachine() vmachine_1.name = 'vmachine_1' vmachine_1.devicename = 'dummy' vmachine_1.pmachine = pmachine vmachine_1.save() vdisk_1_1 = VDisk() vdisk_1_1.name = 'vdisk_1_1' vdisk_1_1.volume_id = 'vdisk_1_1' vdisk_1_1.vmachine = vmachine_1 vdisk_1_1.vpool = vpool vdisk_1_1.devicename = 'dummy' vdisk_1_1.size = 0 vdisk_1_1.save() vdisk_1_1.reload_client() vdisk_1_2 = VDisk() vdisk_1_2.name = 'vdisk_1_2' vdisk_1_2.volume_id = 'vdisk_1_2' vdisk_1_2.vmachine = vmachine_1 vdisk_1_2.vpool = vpool vdisk_1_2.devicename = 'dummy' vdisk_1_2.size = 0 vdisk_1_2.save() vdisk_1_2.reload_client() vmachine_2 = VMachine() vmachine_2.name = 'vmachine_2' vmachine_2.devicename = 'dummy' vmachine_2.pmachine = pmachine vmachine_2.save() vdisk_2_1 = VDisk() vdisk_2_1.name = 'vdisk_2_1' vdisk_2_1.volume_id = 'vdisk_2_1' vdisk_2_1.vmachine = vmachine_2 vdisk_2_1.vpool = vpool vdisk_2_1.devicename = 'dummy' vdisk_2_1.size = 0 vdisk_2_1.save() vdisk_2_1.reload_client() vdisk_3 = VDisk() vdisk_3.name = 'vdisk_3' vdisk_3.volume_id = 'vdisk_3' vdisk_3.vpool = vpool vdisk_3.devicename = 'dummy' vdisk_3.size = 0 vdisk_3.save() vdisk_3.reload_client() for disk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: [dynamic for dynamic in disk._dynamics if dynamic.name == 'snapshots'][0].timeout = 0 # Run the testing scenario travis = 'TRAVIS' in os.environ and os.environ['TRAVIS'] == 'true' if travis is True: print 'Running in Travis, reducing output.' debug = not travis amount_of_days = 50 base = datetime.datetime.now().date() day = datetime.timedelta(1) minute = 60 hour = minute * 60 for d in xrange(0, amount_of_days): base_timestamp = self._make_timestamp(base, day * d) print '' print 'Day cycle: {0}: {1}'.format(d, datetime.datetime.fromtimestamp(base_timestamp).strftime('%Y-%m-%d')) # At the start of the day, delete snapshot policy runs at 00:30 print '- Deleting snapshots' ScheduledTaskController.delete_snapshots(timestamp=base_timestamp + (minute * 30)) # Validate snapshots print '- Validating snapshots' for vdisk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: self._validate(vdisk, d, base, amount_of_days, debug) # During the day, snapshots are taken # - Create non consistent snapshot every hour, between 2:00 and 22:00 # - Create consistent snapshot at 6:30, 12:30, 18:30 print '- Creating snapshots' for h in xrange(2, 23): timestamp = base_timestamp + (hour * h) for vm in [vmachine_1, vmachine_2]: VMachineController.snapshot(machineguid=vm.guid, label='ss_i_{0}:00'.format(str(h)), is_consistent=False, timestamp=timestamp) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VMachineController.snapshot(machineguid=vm.guid, label='ss_c_{0}:30'.format(str(h)), is_consistent=True, timestamp=ts) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={'label': 'ss_i_{0}:00'.format(str(h)), 'is_consistent': False, 'timestamp': str(timestamp), 'machineguid': None}) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={'label': 'ss_c_{0}:30'.format(str(h)), 'is_consistent': True, 'timestamp': str(ts), 'machineguid': None})
def test_happypath(self): """ Validates the happy path; Hourly snapshots are taken with a few manual consistent every now an then. The delete policy is executed every day """ # Setup # There are 2 machines; one with two disks, one with one disk and an additional disk failure_domain = FailureDomain() failure_domain.name = "Test" failure_domain.save() backend_type = BackendType() backend_type.name = "BackendType" backend_type.code = "BT" backend_type.save() vpool = VPool() vpool.name = "vpool" vpool.backend_type = backend_type vpool.save() pmachine = PMachine() pmachine.name = "PMachine" pmachine.username = "******" pmachine.ip = "127.0.0.1" pmachine.hvtype = "VMWARE" pmachine.save() storage_router = StorageRouter() storage_router.name = "storage_router" storage_router.ip = "127.0.0.1" storage_router.pmachine = pmachine storage_router.machine_id = System.get_my_machine_id() storage_router.rdma_capable = False storage_router.primary_failure_domain = failure_domain storage_router.save() disk = Disk() disk.name = "physical_disk_1" disk.path = "/dev/non-existent" disk.size = 500 * 1024 ** 3 disk.state = "OK" disk.is_ssd = True disk.storagerouter = storage_router disk.save() disk_partition = DiskPartition() disk_partition.id = "disk_partition_id" disk_partition.disk = disk disk_partition.path = "/dev/disk/non-existent" disk_partition.size = 400 * 1024 ** 3 disk_partition.state = "OK" disk_partition.offset = 1024 disk_partition.roles = [DiskPartition.ROLES.SCRUB] disk_partition.mountpoint = "/var/tmp" disk_partition.save() vmachine_1 = VMachine() vmachine_1.name = "vmachine_1" vmachine_1.devicename = "dummy" vmachine_1.pmachine = pmachine vmachine_1.save() vdisk_1_1 = VDisk() vdisk_1_1.name = "vdisk_1_1" vdisk_1_1.volume_id = "vdisk_1_1" vdisk_1_1.vmachine = vmachine_1 vdisk_1_1.vpool = vpool vdisk_1_1.devicename = "dummy" vdisk_1_1.size = 0 vdisk_1_1.save() vdisk_1_1.reload_client() vdisk_1_2 = VDisk() vdisk_1_2.name = "vdisk_1_2" vdisk_1_2.volume_id = "vdisk_1_2" vdisk_1_2.vmachine = vmachine_1 vdisk_1_2.vpool = vpool vdisk_1_2.devicename = "dummy" vdisk_1_2.size = 0 vdisk_1_2.save() vdisk_1_2.reload_client() vmachine_2 = VMachine() vmachine_2.name = "vmachine_2" vmachine_2.devicename = "dummy" vmachine_2.pmachine = pmachine vmachine_2.save() vdisk_2_1 = VDisk() vdisk_2_1.name = "vdisk_2_1" vdisk_2_1.volume_id = "vdisk_2_1" vdisk_2_1.vmachine = vmachine_2 vdisk_2_1.vpool = vpool vdisk_2_1.devicename = "dummy" vdisk_2_1.size = 0 vdisk_2_1.save() vdisk_2_1.reload_client() vdisk_3 = VDisk() vdisk_3.name = "vdisk_3" vdisk_3.volume_id = "vdisk_3" vdisk_3.vpool = vpool vdisk_3.devicename = "dummy" vdisk_3.size = 0 vdisk_3.save() vdisk_3.reload_client() for disk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: [dynamic for dynamic in disk._dynamics if dynamic.name == "snapshots"][0].timeout = 0 # Run the testing scenario debug = True amount_of_days = 50 base = datetime.now().date() day = timedelta(1) minute = 60 hour = minute * 60 for d in xrange(0, amount_of_days): base_timestamp = DeleteSnapshots._make_timestamp(base, day * d) print "" print "Day cycle: {0}: {1}".format(d, datetime.fromtimestamp(base_timestamp).strftime("%Y-%m-%d")) # At the start of the day, delete snapshot policy runs at 00:30 print "- Deleting snapshots" ScheduledTaskController.delete_snapshots(timestamp=base_timestamp + (minute * 30)) # Validate snapshots print "- Validating snapshots" for vdisk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: self._validate(vdisk, d, base, amount_of_days, debug) # During the day, snapshots are taken # - Create non consistent snapshot every hour, between 2:00 and 22:00 # - Create consistent snapshot at 6:30, 12:30, 18:30 print "- Creating snapshots" for h in xrange(2, 23): timestamp = base_timestamp + (hour * h) for vm in [vmachine_1, vmachine_2]: VMachineController.snapshot( machineguid=vm.guid, label="ss_i_{0}:00".format(str(h)), is_consistent=False, timestamp=timestamp, ) if h in [6, 12, 18]: ts = timestamp + (minute * 30) VMachineController.snapshot( machineguid=vm.guid, label="ss_c_{0}:30".format(str(h)), is_consistent=True, timestamp=ts ) VDiskController.create_snapshot( diskguid=vdisk_3.guid, metadata={ "label": "ss_i_{0}:00".format(str(h)), "is_consistent": False, "timestamp": str(timestamp), "machineguid": None, }, ) if h in [6, 12, 18]: ts = timestamp + (minute * 30) VDiskController.create_snapshot( diskguid=vdisk_3.guid, metadata={ "label": "ss_c_{0}:30".format(str(h)), "is_consistent": True, "timestamp": str(ts), "machineguid": None, }, )
def update_from_voldrv(name, storagedriver_id): """ This method will update/create a vmachine based on a given vmx/xml file """ pmachine = PMachineList.get_by_storagedriver_id(storagedriver_id) if pmachine.hvtype not in ['VMWARE', 'KVM']: return hypervisor = Factory.get(pmachine) name = hypervisor.clean_vmachine_filename(name) storagedriver = StorageDriverList.get_by_storagedriver_id( storagedriver_id) vpool = storagedriver.vpool machine_ids = [ storagedriver.storagerouter.machine_id for storagedriver in vpool.storagedrivers ] if hypervisor.should_process(name, machine_ids=machine_ids): if pmachine.hvtype == 'VMWARE': storagedriver = StorageDriverList.get_by_storagedriver_id( storagedriver_id) vpool = storagedriver.vpool else: vpool = None pmachine = PMachineList.get_by_storagedriver_id(storagedriver_id) mutex = VolatileMutex('{}_{}'.format( name, vpool.guid if vpool is not None else 'none')) try: mutex.acquire(wait=120) limit = 5 exists = hypervisor.file_exists(storagedriver, name) while limit > 0 and exists is False: time.sleep(1) exists = hypervisor.file_exists(storagedriver, name) limit -= 1 if exists is False: logger.info( 'Could not locate vmachine with name {0} on vpool {1}'. format(name, vpool.name)) vmachine = VMachineList.get_by_devicename_and_vpool( name, vpool) if vmachine is not None: VMachineController.delete_from_voldrv( name, storagedriver_id=storagedriver_id) return finally: mutex.release() try: mutex.acquire(wait=5) vmachine = VMachineList.get_by_devicename_and_vpool( name, vpool) if not vmachine: vmachine = VMachine() vmachine.vpool = vpool vmachine.pmachine = pmachine vmachine.status = 'CREATED' vmachine.devicename = name vmachine.save() finally: mutex.release() if pmachine.hvtype == 'KVM': try: VMachineController.sync_with_hypervisor( vmachine.guid, storagedriver_id=storagedriver_id) vmachine.status = 'SYNC' except: vmachine.status = 'SYNC_NOK' vmachine.save() else: logger.info('Ignored invalid file {0}'.format(name))
def update_from_voldrv(name, storagedriver_id): """ This method will update/create a vmachine based on a given vmx/xml file :param name: Name of the vmx :param storagedriver_id: Storage Driver hosting the vmachine """ pmachine = PMachineList.get_by_storagedriver_id(storagedriver_id) if pmachine.hvtype not in ['VMWARE', 'KVM']: return hypervisor = Factory.get(pmachine) name = hypervisor.clean_vmachine_filename(name) storagedriver = StorageDriverList.get_by_storagedriver_id(storagedriver_id) vpool = storagedriver.vpool machine_ids = [storagedriver.storagerouter.machine_id for storagedriver in vpool.storagedrivers] if hypervisor.should_process(name, machine_ids=machine_ids): if pmachine.hvtype == 'VMWARE': storagedriver = StorageDriverList.get_by_storagedriver_id(storagedriver_id) vpool = storagedriver.vpool else: vpool = None pmachine = PMachineList.get_by_storagedriver_id(storagedriver_id) mutex = volatile_mutex('{0}_{1}'.format(name, vpool.guid if vpool is not None else 'none')) try: mutex.acquire(wait=120) limit = 5 exists = hypervisor.file_exists(storagedriver, name) while limit > 0 and exists is False: time.sleep(1) exists = hypervisor.file_exists(storagedriver, name) limit -= 1 if exists is False: VMachineController._logger.info('Could not locate vmachine with name {0} on vpool {1}'.format(name, vpool.name)) vmachine = VMachineList.get_by_devicename_and_vpool(name, vpool) if vmachine is not None: VMachineController.delete_from_voldrv(name, storagedriver_id=storagedriver_id) return finally: mutex.release() try: mutex.acquire(wait=5) vmachine = VMachineList.get_by_devicename_and_vpool(name, vpool) if not vmachine: vmachines = VMachineList.get_vmachine_by_name(name) if vmachines is not None: vmachine = vmachines[0] if not vmachine: vmachine = VMachine() vmachine.vpool = vpool vmachine.pmachine = pmachine vmachine.status = 'CREATED' vmachine.devicename = name vmachine.save() finally: mutex.release() if pmachine.hvtype == 'KVM': try: mutex.acquire(wait=120) VMachineController.sync_with_hypervisor(vmachine.guid, storagedriver_id=storagedriver_id) vmachine.status = 'SYNC' except: vmachine.status = 'SYNC_NOK' finally: mutex.release() vmachine.save() else: VMachineController._logger.info('Ignored invalid file {0}'.format(name))
def test_happypath(self): """ Validates the happy path; Hourly snapshots are taken with a few manual consistent every now an then. The delete policy is executed every day """ # Setup # There are 2 machines; one with two disks, one with one disk and a stand-alone additional disk failure_domain = FailureDomain() failure_domain.name = 'Test' failure_domain.save() backend_type = BackendType() backend_type.name = 'BackendType' backend_type.code = 'BT' backend_type.save() vpool = VPool() vpool.name = 'vpool' vpool.status = 'RUNNING' vpool.backend_type = backend_type vpool.save() pmachine = PMachine() pmachine.name = 'PMachine' pmachine.username = '******' pmachine.ip = '127.0.0.1' pmachine.hvtype = 'VMWARE' pmachine.save() storage_router = StorageRouter() storage_router.name = 'storage_router' storage_router.ip = '127.0.0.1' storage_router.pmachine = pmachine storage_router.machine_id = System.get_my_machine_id() storage_router.rdma_capable = False storage_router.primary_failure_domain = failure_domain storage_router.save() disk = Disk() disk.name = 'physical_disk_1' disk.path = '/dev/non-existent' disk.size = 500 * 1024**3 disk.state = 'OK' disk.is_ssd = True disk.storagerouter = storage_router disk.save() disk_partition = DiskPartition() disk_partition.id = 'disk_partition_id' disk_partition.disk = disk disk_partition.path = '/dev/disk/non-existent' disk_partition.size = 400 * 1024**3 disk_partition.state = 'OK' disk_partition.offset = 1024 disk_partition.roles = [DiskPartition.ROLES.SCRUB] disk_partition.mountpoint = '/var/tmp' disk_partition.save() vmachine_1 = VMachine() vmachine_1.name = 'vmachine_1' vmachine_1.devicename = 'dummy' vmachine_1.pmachine = pmachine vmachine_1.save() vdisk_1_1 = VDisk() vdisk_1_1.name = 'vdisk_1_1' vdisk_1_1.volume_id = 'vdisk_1_1' vdisk_1_1.vmachine = vmachine_1 vdisk_1_1.vpool = vpool vdisk_1_1.devicename = 'dummy' vdisk_1_1.size = 0 vdisk_1_1.save() vdisk_1_1.reload_client() vdisk_1_2 = VDisk() vdisk_1_2.name = 'vdisk_1_2' vdisk_1_2.volume_id = 'vdisk_1_2' vdisk_1_2.vmachine = vmachine_1 vdisk_1_2.vpool = vpool vdisk_1_2.devicename = 'dummy' vdisk_1_2.size = 0 vdisk_1_2.save() vdisk_1_2.reload_client() vmachine_2 = VMachine() vmachine_2.name = 'vmachine_2' vmachine_2.devicename = 'dummy' vmachine_2.pmachine = pmachine vmachine_2.save() vdisk_2_1 = VDisk() vdisk_2_1.name = 'vdisk_2_1' vdisk_2_1.volume_id = 'vdisk_2_1' vdisk_2_1.vmachine = vmachine_2 vdisk_2_1.vpool = vpool vdisk_2_1.devicename = 'dummy' vdisk_2_1.size = 0 vdisk_2_1.save() vdisk_2_1.reload_client() vdisk_3 = VDisk() vdisk_3.name = 'vdisk_3' vdisk_3.volume_id = 'vdisk_3' vdisk_3.vpool = vpool vdisk_3.devicename = 'dummy' vdisk_3.size = 0 vdisk_3.save() vdisk_3.reload_client() for disk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: [ dynamic for dynamic in disk._dynamics if dynamic.name == 'snapshots' ][0].timeout = 0 # Run the testing scenario travis = 'TRAVIS' in os.environ and os.environ['TRAVIS'] == 'true' if travis is True: print 'Running in Travis, reducing output.' debug = not travis amount_of_days = 50 base = datetime.datetime.now().date() day = datetime.timedelta(1) minute = 60 hour = minute * 60 for d in xrange(0, amount_of_days): base_timestamp = self._make_timestamp(base, day * d) print '' print 'Day cycle: {0}: {1}'.format( d, datetime.datetime.fromtimestamp(base_timestamp).strftime( '%Y-%m-%d')) # At the start of the day, delete snapshot policy runs at 00:30 print '- Deleting snapshots' ScheduledTaskController.delete_snapshots(timestamp=base_timestamp + (minute * 30)) # Validate snapshots print '- Validating snapshots' for vdisk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]: self._validate(vdisk, d, base, amount_of_days, debug) # During the day, snapshots are taken # - Create non consistent snapshot every hour, between 2:00 and 22:00 # - Create consistent snapshot at 6:30, 12:30, 18:30 print '- Creating snapshots' for h in xrange(2, 23): timestamp = base_timestamp + (hour * h) for vm in [vmachine_1, vmachine_2]: VMachineController.snapshot(machineguid=vm.guid, label='ss_i_{0}:00'.format( str(h)), is_consistent=False, timestamp=timestamp) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VMachineController.snapshot(machineguid=vm.guid, label='ss_c_{0}:30'.format( str(h)), is_consistent=True, timestamp=ts) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={ 'label': 'ss_i_{0}:00'.format( str(h)), 'is_consistent': False, 'timestamp': str(timestamp), 'machineguid': None }) if h in [6, 12, 18]: ts = (timestamp + (minute * 30)) VDiskController.create_snapshot(diskguid=vdisk_3.guid, metadata={ 'label': 'ss_c_{0}:30'.format( str(h)), 'is_consistent': True, 'timestamp': str(ts), 'machineguid': None })
def create_from_template(diskguid, machinename, devicename, pmachineguid, machineguid=None, storagedriver_guid=None): """ Create a disk from a template @param devicename: device file name for the disk (eg: mydisk-flat.vmdk) @param machineguid: guid of the machine to assign disk to @return diskguid: guid of new disk """ pmachine = PMachine(pmachineguid) hypervisor = Factory.get(pmachine) disk_path = hypervisor.get_disk_path(machinename, devicename) description = '{} {}'.format(machinename, devicename) properties_to_clone = [ 'description', 'size', 'type', 'retentionpolicyid', 'snapshotpolicyid', 'vmachine', 'vpool' ] vdisk = VDisk(diskguid) if vdisk.vmachine and not vdisk.vmachine.is_vtemplate: # Disk might not be attached to a vmachine, but still be a template raise RuntimeError('The given vdisk does not belong to a template') if storagedriver_guid is not None: storagedriver_id = StorageDriver( storagedriver_guid).storagedriver_id else: storagedriver_id = vdisk.storagedriver_id storagedriver = StorageDriverList.get_by_storagedriver_id( storagedriver_id) if storagedriver is None: raise RuntimeError( 'Could not find StorageDriver with id {0}'.format( storagedriver_id)) new_vdisk = VDisk() new_vdisk.copy(vdisk, include=properties_to_clone) new_vdisk.vpool = vdisk.vpool new_vdisk.devicename = hypervisor.clean_backing_disk_filename( disk_path) new_vdisk.parent_vdisk = vdisk new_vdisk.name = '{}-clone'.format(vdisk.name) new_vdisk.description = description new_vdisk.vmachine = VMachine( machineguid) if machineguid else vdisk.vmachine new_vdisk.save() mds_service = MDSServiceController.get_preferred_mds( storagedriver.storagerouter, vdisk.vpool) if mds_service is None: raise RuntimeError('Could not find a MDS service') logger.info( 'Create disk from template {} to new disk {} to location {}'. format(vdisk.name, new_vdisk.name, disk_path)) try: volume_id = vdisk.storagedriver_client.create_clone_from_template( target_path=disk_path, metadata_backend_config=MDSMetaDataBackendConfig([ MDSNodeConfig(address=str( mds_service.service.storagerouter.ip), port=mds_service.service.ports[0]) ]), parent_volume_id=str(vdisk.volume_id), node_id=str(storagedriver_id)) new_vdisk.volume_id = volume_id new_vdisk.save() MDSServiceController.ensure_safety(new_vdisk) except Exception as ex: logger.error( 'Clone disk on volumedriver level failed with exception: {0}'. format(str(ex))) new_vdisk.delete() raise return { 'diskguid': new_vdisk.guid, 'name': new_vdisk.name, 'backingdevice': disk_path }