def _find_ovs_model_disk_by_location(self, location, hostname, retry=3, timeout=3): """Find OVS disk object based on location and hostname :return VDisk: OVS DAL model object """ hostname = self._get_real_hostname(hostname) LOG.debug('[_FIND OVS DISK] Location %s, hostname %s', location, hostname) attempt = 0 while attempt <= retry: for vd in vdisklist.VDiskList.get_vdisks(): if vd.vpool: for vsr in vd.vpool.storagedrivers: if vsr.storagerouter.name == hostname: _location = "{0}/{1}".format(vsr.mountpoint, vd.devicename) if _location == location: LOG.debug('Location %s Disk found %s', (location, vd.guid)) disk = vdiskhybrid.VDisk(vd.guid) return disk msg = 'NO RESULT Attempt %s timeout %s max attempts %s' LOG.debug(msg, attempt, timeout, retry) if timeout: time.sleep(timeout) attempt += 1 msg = (_('No disk found for location %s') % location) LOG.exception(msg) raise exception.VolumeBackendAPIException(data=msg)
def create_volume_from_snapshot(self, volume, snapshot): """Creates a volume from a snapshot. Called on "cinder create --snapshot-id ..." :param snapshot: snapshot reference (sqlalchemy Model) :param volume: volume reference (sqlalchemy Model) Volume here is just a ModelObject, it doesn't exist physically, it will be created by OVS. Diskguid to be passed to the clone method is the ovs diskguid of the parent of the snapshot with snapshot.id OVS: Clone from arbitrary volume, requires volumedriver 3.6 release > 15.08.2014 """ _debug_vol_info('CLONE_VOL', volume) _debug_vol_info('CLONE_SNAP', snapshot) mountpoint = self._get_hostname_mountpoint(str(volume.host)) ovs_snap_disk = self._find_ovs_model_disk_by_snapshot_id(snapshot.id) OVSVolumeDriver._wait_for_snapshot(ovs_snap_disk, snapshot.id) devicename = volume.display_name if not devicename: devicename = volume.name pmachineguid = self._find_ovs_model_pmachine_guid_by_hostname( str(volume.host)) LOG.info('[CLONE FROM SNAP] %s %s %s %s' % (ovs_snap_disk.guid, snapshot.id, devicename, pmachineguid)) try: kwargs = dict(diskguid=ovs_snap_disk.guid, snapshotid=snapshot.id, devicename=devicename, pmachineguid=pmachineguid, machinename="", machineguid=None) LOG.debug('[CLONE FROM SNAP] Executing clone - async') # Execute "clone" task async, using celery workers # wait for the result for 30 minutes then raise TimeoutError disk_meta = vdisklib.VDiskController.clone.apply_async( kwargs=kwargs).get(timeout=1800) LOG.debug('[CLONE FROM SNAP] Executing clone - async - DONE') volume['provider_location'] = '{}{}'.format( mountpoint, disk_meta['backingdevice']) LOG.debug('[CLONE FROM SNAP] Meta: %s' % str(disk_meta)) LOG.debug('[CLONE FROM SNAP] New volume %s' % volume['provider_location']) vdisk = vdiskhybrid.VDisk(disk_meta['diskguid']) vdisk.cinder_id = volume.id vdisk.name = devicename vdisk.save() except Exception as ex: LOG.error('CLONE FROM SNAP: Internal error %s ' % str(ex)) self.delete_volume(volume) raise return { 'provider_location': volume['provider_location'], 'display_name': volume['display_name'] }
def create_volume_from_snapshot(self, volume, snapshot): """Creates a volume from a snapshot. Called on "cinder create --snapshot-id ..." :param snapshot: snapshot reference (sqlalchemy Model) :param volume: volume reference (sqlalchemy Model) Volume here is just a ModelObject, it doesn't exist physically, it will be created by OVS. Diskguid to be passed to the clone method is the ovs diskguid of the parent of the snapshot with snapshot.id OVS: Clone from arbitrary volume, requires volumedriver 3.6 release > 15.08.2014 """ mountpoint = self._get_hostname_mountpoint(str(volume.host)) ovs_snap_disk = self._find_ovs_model_disk_by_snapshot_id(snapshot.id) devicename = volume.display_name if not devicename: devicename = volume.name pmachineguid = self._find_ovs_model_pmachine_guid_by_hostname( six.text_type(volume.host)) LOG.debug( '[CLONE FROM SNAP] %(disk)s %(snapshot)s %(device)s ' '%(machine)s', { 'disk': ovs_snap_disk.guid, 'snapshot': snapshot.id, 'device': devicename, 'machine': pmachineguid }) disk_meta = vdisklib.VDiskController.clone(diskguid=ovs_snap_disk.guid, snapshotid=snapshot.id, devicename=devicename, pmachineguid=pmachineguid, machinename="", machineguid=None) volume['provider_location'] = '{}{}'.format(mountpoint, disk_meta['backingdevice']) LOG.debug('[CLONE FROM SNAP] Meta: %s', six.text_type(disk_meta)) LOG.debug('[CLONE FROM SNAP] New volume %s', volume['provider_location']) vdisk = vdiskhybrid.VDisk(disk_meta['diskguid']) vdisk.cinder_id = volume.id vdisk.name = devicename vdisk.save() return { 'provider_location': volume['provider_location'], 'display_name': volume['display_name'] }
def create_cloned_volume(self, volume, src_vref): """Create a cloned volume from another volume. Called on "cinder create --source-volid ... " :param volume: volume reference - target volume (sqlalchemy Model) :param src_vref: volume reference - source volume (sqlalchemy Model) OVS: Create clone from template if the source is a template Create volume from snapshot if the source is a volume - create snapshot of source volume if it doesn't have snapshots """ mountpoint = self._get_hostname_mountpoint(str(volume.host)) name = volume.display_name if not name: name = volume.name volume.display_name = volume.name pmachineguid = self._find_ovs_model_pmachine_guid_by_hostname( six.text_type(volume.host)) # Source source_ovs_disk = self._find_ovs_model_disk_by_location( str(src_vref.provider_location), src_vref.host) if source_ovs_disk.info['object_type'] == 'TEMPLATE': LOG.debug('[CREATE_FROM_TEMPLATE] VDisk %s is a template', source_ovs_disk.devicename) # Cloning from a template LOG.debug('[CREATE FROM TEMPLATE] ovs_disk %s ', source_ovs_disk.devicename) disk_meta = vdisklib.VDiskController.create_from_template( diskguid = source_ovs_disk.guid, machinename = "", devicename = str(name), pmachineguid = pmachineguid, machineguid = None, storagedriver_guid = None) volume['provider_location'] = '{}{}'.format( mountpoint, disk_meta['backingdevice']) LOG.debug('[CREATE FROM TEMPLATE] New volume %s', volume['provider_location']) vdisk = vdiskhybrid.VDisk(disk_meta['diskguid']) vdisk.cinder_id = volume.id vdisk.name = name LOG.debug('[CREATE FROM TEMPLATE] Updating meta %s %s', volume.id, name) vdisk.save() else: LOG.debug('[THIN CLONE] VDisk %s is not a template', source_ovs_disk.devicename) # We do not support yet full volume clone # - requires "emancipate" functionality # So for now we'll take a snapshot # (or the latest snapshot existing) and clone from that snapshot if not len(source_ovs_disk.snapshots): metadata = {'label': "Cinder clone snapshot {0}".format(name), 'is_consistent': False, 'timestamp': time.time(), 'machineguid': source_ovs_disk.vmachine_guid, 'is_automatic': False} LOG.debug('CREATE_SNAP %s %s', name, str(metadata)) snapshotid = vdisklib.VDiskController.create_snapshot( diskguid = source_ovs_disk.guid, metadata = metadata, snapshotid = None) LOG.debug('CREATE_SNAP OK') else: snapshotid = source_ovs_disk.snapshots[-1]['guid'] LOG.debug('[CREATE CLONE FROM SNAP] %s ', snapshotid) disk_meta = vdisklib.VDiskController.clone( diskguid = source_ovs_disk.guid, snapshotid = snapshotid, devicename = str(name), pmachineguid = pmachineguid, machinename = "", machineguid=None) volume['provider_location'] = '{}{}'.format( mountpoint, disk_meta['backingdevice']) LOG.debug('[CLONE FROM SNAP] Meta: %s', str(disk_meta)) LOG.debug('[CLONE FROM SNAP] New volume %s', volume['provider_location']) vdisk = vdiskhybrid.VDisk(disk_meta['diskguid']) vdisk.cinder_id = volume.id vdisk.name = name vdisk.save() return {'provider_location': volume['provider_location'], 'display_name': volume['display_name']}