def test_clone_from_template_happypath(self): """ Test clone from template - happy path """ StorageDriverModule.use_good_client() vdisk_1_1, pmachine = self._prepare() VDiskController.create_from_template(vdisk_1_1.guid, 'vmachine_2', 'vdisk_1_1-clone', pmachine.guid) vdisks = VDiskList.get_vdisk_by_name('vdisk_1_1') self.assertEqual(len(vdisks), 1, 'Vdisk not modeled') clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone') self.assertEqual(len(clones), 1, 'Clone not modeled')
def test_clone_from_template_happypath(self): """ Test clone from template - happy path """ StorageDriverModule.use_good_client() vdisk_1_1, pmachine = self._prepare() VDiskController.create_from_template(vdisk_1_1.guid, 'vmachine_2', 'vdisk_1_1-clone', pmachine.guid) vdisks = VDiskList.get_vdisk_by_name('vdisk_1_1') self.assertEqual(len(vdisks), 1, 'Vdisk not modeled') clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone') self.assertEqual(len(clones), 1, 'Clone not modeled')
def get_vdisk_by_name(name): """ Retrieve the DAL vDisk object based on its name :param name: Name of the virtual disk :return: vDisk DAL object """ return VDiskList.get_vdisk_by_name(vdiskname=name)
def test_clone_from_template_error_handling(self): """ Test clone from template - error during create """ StorageDriverModule.use_bad_client() vdisk_1_1, pmachine = self._prepare() self.assertRaises(RuntimeError, VDiskController.create_from_template, vdisk_1_1.guid, 'vmachine_2', 'vdisk_1_1-clone', pmachine.guid) clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone') self.assertIsNone(clones, 'Clone not deleted after exception')
def test_clone_from_template_error_handling(self): """ Test clone from template - error during create """ StorageDriverModule.use_bad_client() vdisk_1_1, pmachine = self._prepare() self.assertRaises(RuntimeError, VDiskController.create_from_template, vdisk_1_1.guid, 'vmachine_2', 'vdisk_1_1-clone', pmachine.guid) clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone') self.assertIsNone(clones, 'Clone not deleted after exception')
def test_clone_from_template_error_handling2(self): """ Test clone from template - error during create, then error during delete """ StorageDriverModule.use_bad_client() global VDisk def delete(self, *args, **kwargs): raise RuntimeError('DAL Error') _delete = VDisk.delete VDisk.delete = delete vdisk_1_1, pmachine = self._prepare() self.assertRaises(RuntimeError, VDiskController.create_from_template, vdisk_1_1.guid, 'vmachine_2', 'vdisk_1_1-clone', pmachine.guid) clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone') self.assertEqual(len(clones), 1, 'Clone deleted') VDisk.delete = _delete
def test_clone_from_template_error_handling2(self): """ Test clone from template - error during create, then error during delete """ StorageDriverModule.use_bad_client() global VDisk def delete(self, *args, **kwargs): raise RuntimeError('DAL Error') _delete = VDisk.delete VDisk.delete = delete vdisk_1_1, pmachine = self._prepare() self.assertRaises(RuntimeError, VDiskController.create_from_template, vdisk_1_1.guid, 'vmachine_2', 'vdisk_1_1-clone', pmachine.guid) clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone') self.assertEqual(len(clones), 1, 'Clone deleted') VDisk.delete = _delete
def clone(diskguid, snapshotid, devicename, pmachineguid, machinename=None, machineguid=None, detached=False): """ Clone a disk :param diskguid: Guid of the disk to clone :param snapshotid: ID of the snapshot to clone from :param devicename: Name of the device to use in clone's description :param pmachineguid: Guid of the physical machine :param machinename: Name of the machine the disk is attached to :param machineguid: Guid of the machine :param detached: Boolean indicating the disk is attached to a machine or not """ # 1. Validations name_regex = "^[0-9a-zA-Z][-_a-zA-Z0-9]{1,48}[a-zA-Z0-9]$" if not re.match(name_regex, devicename): raise RuntimeError("Invalid name for virtual disk clone") if VDiskList.get_vdisk_by_name(vdiskname=devicename) is not None: raise RuntimeError("A virtual disk with this name already exists") vdisk = VDisk(diskguid) 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)) if machineguid is not None and detached is True: raise ValueError('A vMachine GUID was specified while detached is True') # 2. Create new snapshot if required if snapshotid is None: timestamp = str(int(time.time())) metadata = {'label': '', 'is_consistent': False, 'timestamp': timestamp, 'machineguid': machineguid, 'is_automatic': True} sd_snapshot_id = VDiskController.create_snapshot(diskguid, metadata) tries = 25 # 5 minutes while snapshotid is None and tries > 0: time.sleep(25 - tries) tries -= 1 vdisk.invalidate_dynamics(['snapshots']) for snapshot in vdisk.snapshots: if snapshot['guid'] != sd_snapshot_id: continue if snapshot['in_backend'] is True: snapshotid = snapshot['guid'] if snapshotid is None: try: VDiskController.delete_snapshot(diskguid=diskguid, snapshotid=sd_snapshot_id) except: pass raise RuntimeError('Could not find created snapshot in time') # 3. Model new cloned virtual disk hypervisor = Factory.get(PMachine(pmachineguid)) location = hypervisor.get_disk_path(machinename, devicename) new_vdisk = VDisk() new_vdisk.copy(vdisk, include=['description', 'size', 'type', 'retentionpolicyguid', 'snapshotpolicyguid', 'autobackup']) new_vdisk.parent_vdisk = vdisk new_vdisk.name = devicename new_vdisk.description = devicename if machinename is None else '{0} {1}'.format(machinename, devicename) new_vdisk.devicename = hypervisor.clean_backing_disk_filename(location) new_vdisk.parentsnapshot = snapshotid if detached is False: new_vdisk.vmachine = VMachine(machineguid) if machineguid else vdisk.vmachine new_vdisk.vpool = vdisk.vpool new_vdisk.save() # 4. Configure Storage Driver try: 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 {0} of disk {1} to location {2}'.format(snapshotid, vdisk.name, location)) backend_config = MDSMetaDataBackendConfig([MDSNodeConfig(address=str(mds_service.service.storagerouter.ip), port=mds_service.service.ports[0])]) volume_id = vdisk.storagedriver_client.create_clone(target_path=location, metadata_backend_config=backend_config, 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)) try: VDiskController.clean_bad_disk(new_vdisk.guid) except Exception as ex2: logger.exception('Exception during exception handling of "create_clone_from_template" : {0}'.format(str(ex2))) raise new_vdisk.volume_id = volume_id new_vdisk.save() # 5. Check MDS & DTL for new clone try: MDSServiceController.ensure_safety(new_vdisk) except Exception as ex: logger.error('Caught exception during "ensure_safety" {0}'.format(ex)) VDiskController.dtl_checkup.delay(vdisk_guid=new_vdisk.guid) return {'diskguid': new_vdisk.guid, 'name': new_vdisk.name, 'backingdevice': location}