def migrate_volume(self, ctxt, volume, host, thin=False, mirror_count=0): """Optimize the migration if the destination is on the same server. If the specified host is another back-end on the same server, and the volume is not attached, we can do the migration locally without going through iSCSI. """ false_ret = (False, None) if volume['status'] != 'available': return false_ret if 'location_info' not in host['capabilities']: return false_ret info = host['capabilities']['location_info'] try: (dest_type, dest_hostname, dest_vg, lvm_type, lvm_mirrors) =\ info.split(':') lvm_mirrors = int(lvm_mirrors) except ValueError: return false_ret if (dest_type != 'LVMVolumeDriver' or dest_hostname != self.hostname): return false_ret if dest_vg == self.vg.vg_name: message = (_("Refusing to migrate volume ID: %(id)s. Please " "check your configuration because source and " "destination are the same Volume Group: %(name)s.") % { 'id': volume['id'], 'name': self.vg.vg_name }) LOG.error(message) raise exception.VolumeBackendAPIException(data=message) vg_list = volume_utils.get_all_volume_groups() try: next(vg for vg in vg_list if vg['name'] == dest_vg) except StopIteration: LOG.error("Destination Volume Group %s does not exist", dest_vg) return false_ret helper = utils.get_root_helper() lvm_conf_file = self.configuration.lvm_conf_file if lvm_conf_file.lower() == 'none': lvm_conf_file = None dest_vg_ref = lvm.LVM(dest_vg, helper, lvm_type=lvm_type, executor=self._execute, lvm_conf=lvm_conf_file) self._create_volume(volume['name'], self._sizestr(volume['size']), lvm_type, lvm_mirrors, dest_vg_ref) # copy_volume expects sizes in MiB, we store integer GiB # be sure to convert before passing in size_in_mb = int(volume['size']) * units.Ki try: volume_utils.copy_volume(self.local_path(volume), self.local_path(volume, vg=dest_vg), size_in_mb, self.configuration.volume_dd_blocksize, execute=self._execute, sparse=self._sparse_copy_volume) except Exception as e: with excutils.save_and_reraise_exception(): LOG.error( "Volume migration failed due to " "exception: %(reason)s.", {'reason': six.text_type(e)}, resource=volume) dest_vg_ref.delete(volume) self._delete_volume(volume) return (True, None)
def check_for_setup_error(self): """Verify that requirements are in place to use LVM driver.""" if self.vg is None: root_helper = utils.get_root_helper() lvm_conf_file = self.configuration.lvm_conf_file if lvm_conf_file.lower() == 'none': lvm_conf_file = None try: lvm_type = self.configuration.lvm_type if lvm_type == 'auto': if volume_utils.supports_thin_provisioning(): lvm_type = 'thin' else: lvm_type = 'default' self.vg = lvm.LVM( self.configuration.volume_group, root_helper, lvm_type=lvm_type, executor=self._execute, lvm_conf=lvm_conf_file, suppress_fd_warn=( self.configuration.lvm_suppress_fd_warnings)) except exception.VolumeGroupNotFound: message = (_("Volume Group %s does not exist") % self.configuration.volume_group) raise exception.VolumeBackendAPIException(data=message) vg_list = volume_utils.get_all_volume_groups( self.configuration.volume_group) vg_dict = next(vg for vg in vg_list if vg['name'] == self.vg.vg_name) if vg_dict is None: message = (_("Volume Group %s does not exist") % self.configuration.volume_group) raise exception.VolumeBackendAPIException(data=message) pool_name = "%s-pool" % self.configuration.volume_group if self.configuration.lvm_type == 'auto': # Default to thin provisioning if it is supported and # the volume group is empty, or contains a thin pool # for us to use. self.vg.update_volume_group_info() self.configuration.lvm_type = 'default' if volume_utils.supports_thin_provisioning(): if self.vg.get_volume(pool_name) is not None: LOG.info('Enabling LVM thin provisioning by default ' 'because a thin pool exists.') self.configuration.lvm_type = 'thin' elif len(self.vg.get_volumes()) == 0: LOG.info('Enabling LVM thin provisioning by default ' 'because no LVs exist.') self.configuration.lvm_type = 'thin' if self.configuration.lvm_type == 'thin': # Specific checks for using Thin provisioned LV's if not volume_utils.supports_thin_provisioning(): message = _("Thin provisioning not supported " "on this version of LVM.") raise exception.VolumeBackendAPIException(data=message) if self.vg.get_volume(pool_name) is None: try: self.vg.create_thin_pool(pool_name) except processutils.ProcessExecutionError as exc: exception_message = (_("Failed to create thin pool, " "error message was: %s") % six.text_type(exc.stderr)) raise exception.VolumeBackendAPIException( data=exception_message) # Enable sparse copy since lvm_type is 'thin' self._sparse_copy_volume = True