def update_migrated_volume(self, volume, new_volume): try: self._modify_lun_name(new_volume['name'], volume['name']) except Exception: reason = _('Failed to _modify_lun_name [%s].') % new_volume['name'] raise exception.VolumeMigrationFailed(reason=reason) return {'_name_id': None}
def _migrate_volume_generic(self, ctxt, volume, host): rpcapi = volume_rpcapi.VolumeAPI() # Create new volume on remote host new_vol_values = {} for k, v in volume.iteritems(): new_vol_values[k] = v del new_vol_values['id'] new_vol_values['host'] = host['host'] new_vol_values['status'] = 'migration_target_creating' new_volume = self.db.volume_create(ctxt, new_vol_values) rpcapi.create_volume(ctxt, new_volume, host['host'], None, None) # Wait for new_volume to become ready starttime = time.time() deadline = starttime + CONF.migration_create_volume_timeout_secs new_volume = self.db.volume_get(ctxt, new_volume['id']) tries = 0 while new_volume['status'] != 'migration_target': tries = tries + 1 now = time.time() if new_volume['status'] == 'error': msg = _("failed to create new_volume on destination host") raise exception.VolumeMigrationFailed(reason=msg) elif now > deadline: msg = _("timeout creating new_volume on destination host") raise exception.VolumeMigrationFailed(reason=msg) else: time.sleep(tries**2) new_volume = self.db.volume_get(ctxt, new_volume['id']) # Copy the source volume to the destination volume try: self.driver.copy_volume_data(ctxt, volume, new_volume, remote='dest') except Exception: with excutils.save_and_reraise_exception(): msg = _("Failed to copy volume %(vol1)s to %(vol2)s") LOG.error(msg % { 'vol1': volume['id'], 'vol2': new_volume['id'] }) rpcapi.delete_volume(ctxt, volume) # Delete the source volume (if it fails, don't fail the migration) try: self.delete_volume(ctxt, volume['id']) except Exception as ex: msg = _("Failed to delete migration source vol %(vol)s: %(err)s") LOG.error(msg % {'vol': volume['id'], 'err': ex}) # Rename the destination volume to the name of the source volume. # We rename rather than create the destination with the same as the # source because: (a) some backends require unique names between pools # in addition to within pools, and (b) we want to enable migration # within one pool (for example, changing a volume's type by creating a # new volume and copying the data over) try: rpcapi.rename_volume(ctxt, new_volume, volume['id']) except Exception: msg = _("Failed to rename migration destination volume " "%(vol)s to %(name)s") LOG.error(msg % {'vol': new_volume['id'], 'name': volume['name']}) self.db.finish_volume_migration(ctxt, volume['id'], new_volume['id'])
def _migrate_volume_generic(self, ctxt, volume, host): rpcapi = volume_rpcapi.VolumeAPI() # Create new volume on remote host new_vol_values = {} for k, v in volume.iteritems(): new_vol_values[k] = v del new_vol_values['id'] del new_vol_values['_name_id'] # We don't copy volume_type because the db sets that according to # volume_type_id, which we do copy del new_vol_values['volume_type'] new_vol_values['host'] = host['host'] new_vol_values['status'] = 'creating' new_vol_values['migration_status'] = 'target:%s' % volume['id'] new_vol_values['attach_status'] = 'detached' new_volume = self.db.volume_create(ctxt, new_vol_values) rpcapi.create_volume(ctxt, new_volume, host['host'], None, None) # Wait for new_volume to become ready starttime = time.time() deadline = starttime + CONF.migration_create_volume_timeout_secs new_volume = self.db.volume_get(ctxt, new_volume['id']) tries = 0 while new_volume['status'] != 'available': tries = tries + 1 now = time.time() if new_volume['status'] == 'error': msg = _("failed to create new_volume on destination host") raise exception.VolumeMigrationFailed(reason=msg) elif now > deadline: msg = _("timeout creating new_volume on destination host") raise exception.VolumeMigrationFailed(reason=msg) else: time.sleep(tries ** 2) new_volume = self.db.volume_get(ctxt, new_volume['id']) # Copy the source volume to the destination volume try: if volume['status'] == 'available': self.driver.copy_volume_data(ctxt, volume, new_volume, remote='dest') # The above call is synchronous so we complete the migration self.migrate_volume_completion(ctxt, volume['id'], new_volume['id'], error=False) else: nova_api = compute.API() # This is an async call to Nova, which will call the completion # when it's done nova_api.update_server_volume(ctxt, volume['instance_uuid'], volume['id'], new_volume['id']) except Exception: with excutils.save_and_reraise_exception(): msg = _("Failed to copy volume %(vol1)s to %(vol2)s") LOG.error(msg % {'vol1': volume['id'], 'vol2': new_volume['id']}) volume = self.db.volume_get(ctxt, volume['id']) # If we're in the completing phase don't delete the target # because we may have already deleted the source! if volume['migration_status'] == 'migrating': rpcapi.delete_volume(ctxt, new_volume) new_volume['migration_status'] = None