diff --git a/cinder/opts.py b/cinder/opts.py index dfbd681b133..fad6c4d67d0 100644 --- a/cinder/opts.py +++ b/cinder/opts.py @@ -70,8 +70,6 @@ from cinder import ssh_utils as cinder_sshutils from cinder.transfer import api as cinder_transfer_api from cinder.volume import api as cinder_volume_api from cinder.volume import driver as cinder_volume_driver -from cinder.volume.drivers import block_device as \ - cinder_volume_drivers_blockdevice from cinder.volume.drivers import blockbridge as \ cinder_volume_drivers_blockbridge from cinder.volume.drivers import coho as cinder_volume_drivers_coho @@ -300,7 +298,6 @@ def list_opts(): itertools.chain( cinder_volume_driver.volume_opts, cinder_volume_driver.iser_opts, - cinder_volume_drivers_blockdevice.volume_opts, cinder_volume_drivers_blockbridge.blockbridge_opts, cinder_volume_drivers_coho.coho_opts, cinder_volume_drivers_coprhd_common.volume_opts, diff --git a/cinder/tests/unit/volume/drivers/test_block_device.py b/cinder/tests/unit/volume/drivers/test_block_device.py deleted file mode 100644 index c501c9fbea4..00000000000 --- a/cinder/tests/unit/volume/drivers/test_block_device.py +++ /dev/null @@ -1,421 +0,0 @@ -# Copyright (c) 2013 Mirantis, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from oslo_config import cfg - -from cinder import context -from cinder import db -import cinder.exception -from cinder.objects import fields -from cinder.objects import snapshot as obj_snap -from cinder.objects import volume as obj_volume -import cinder.test -from cinder.tests.unit import fake_constants as fake -from cinder.volume import configuration as conf -from cinder.volume.drivers import block_device -from cinder.volume import utils as volutils - - -class TestBlockDeviceDriver(cinder.test.TestCase): - def setUp(self): - fake_opt = [cfg.StrOpt('fake_opt', default='fake', help='fake option')] - super(TestBlockDeviceDriver, self).setUp() - self.configuration = conf.Configuration(fake_opt, 'fake_group') - self.configuration.available_devices = ['/dev/loop1', '/dev/loop2'] - self.configuration.iscsi_helper = 'tgtadm' - self.host = 'localhost' - self.configuration.iscsi_port = 3260 - self.configuration.volume_dd_blocksize = 1234 - self.drv = block_device.BlockDeviceDriver( - configuration=self.configuration, - host='localhost', db=db) - - def test_initialize_connection(self): - TEST_VOLUME1 = obj_volume.Volume(host='localhost1', - provider_location='1 2 3 /dev/loop1', - provider_auth='a b c', - attached_mode='rw', - id=fake.VOLUME_ID) - TEST_CONNECTOR = {'host': 'localhost1'} - - data = self.drv.initialize_connection(TEST_VOLUME1, TEST_CONNECTOR) - expected_data = {'data': {'device_path': '/dev/loop1'}, - 'driver_volume_type': 'local'} - - self.assertEqual(expected_data, data) - - @mock.patch('cinder.volume.driver.ISCSIDriver.initialize_connection') - def test_initialize_connection_different_hosts(self, _init_conn): - TEST_CONNECTOR = {'host': 'localhost1'} - TEST_VOLUME2 = obj_volume.Volume(host='localhost2', - provider_location='1 2 3 /dev/loop2', - provider_auth='d e f', - attached_mode='rw', - id=fake.VOLUME2_ID) - _init_conn.return_value = 'data' - - data = self.drv.initialize_connection(TEST_VOLUME2, TEST_CONNECTOR) - expected_data = {'data': {'auth_method': 'd', - 'auth_password': 'f', - 'auth_username': 'e', - 'encrypted': False, - 'target_discovered': False, - 'target_iqn': '2', - 'target_lun': 3, - 'target_portal': '1', - 'volume_id': fake.VOLUME2_ID}} - - self.assertEqual(expected_data['data'], data['data']) - - @mock.patch('cinder.volume.drivers.block_device.BlockDeviceDriver.' - 'local_path', return_value=None) - @mock.patch('cinder.volume.utils.clear_volume') - def test_delete_not_volume_provider_location(self, _clear_volume, - _local_path): - TEST_VOLUME2 = obj_volume.Volume(provider_location=None) - self.drv.delete_volume(TEST_VOLUME2) - _local_path.assert_called_once_with(TEST_VOLUME2) - - @mock.patch('os.path.exists', return_value=True) - @mock.patch('cinder.volume.utils.clear_volume') - def test_delete_volume_path_exist(self, _clear_volume, _exists): - TEST_VOLUME = obj_volume.Volume(name_id=fake.VOLUME_NAME_ID, - size=1, - provider_location='/dev/loop1', - display_name='vol1', - status='available') - - with mock.patch.object(self.drv, 'local_path', - return_value='/dev/loop1') as lp_mocked: - with mock.patch.object(self.drv, '_get_devices_sizes', - return_value={'/dev/loop1': 1}) as \ - gds_mocked: - volutils.clear_volume(gds_mocked, lp_mocked) - - self.drv.delete_volume(TEST_VOLUME) - - lp_mocked.assert_called_once_with(TEST_VOLUME) - gds_mocked.assert_called_once_with(['/dev/loop1']) - - self.assertTrue(_exists.called) - self.assertTrue(_clear_volume.called) - - def test_delete_path_is_not_in_list_of_available_devices(self): - TEST_VOLUME2 = obj_volume.Volume(provider_location='/dev/loop0') - with mock.patch.object(self.drv, 'local_path', - return_value='/dev/loop0') as lp_mocked: - self.drv.delete_volume(TEST_VOLUME2) - lp_mocked.assert_called_once_with(TEST_VOLUME2) - - def test__update_provider_location(self): - TEST_VOLUME = obj_volume.Volume(name_id=fake.VOLUME_NAME_ID, - size=1, - display_name='vol1') - with mock.patch.object(obj_volume.Volume, 'update') as update_mocked, \ - mock.patch.object(obj_volume.Volume, 'save') as save_mocked: - self.drv._update_provider_location(TEST_VOLUME, 'dev_path') - self.assertEqual(1, update_mocked.call_count) - save_mocked.assert_called_once_with() - - def test_create_volume(self): - TEST_VOLUME = obj_volume.Volume(name_id=fake.VOLUME_NAME_ID, - size=1, - display_name='vol1') - - with mock.patch.object(self.drv, 'find_appropriate_size_device', - return_value='dev_path') as fasd_mocked: - with mock.patch.object(self.drv, '_update_provider_location') as \ - upl_mocked: - self.drv.create_volume(TEST_VOLUME) - fasd_mocked.assert_called_once_with(TEST_VOLUME.size) - upl_mocked.assert_called_once_with(TEST_VOLUME, 'dev_path') - - def test_update_volume_stats(self): - - with mock.patch.object(self.drv, '_devices_sizes', - return_value={'/dev/loop1': 1024, - '/dev/loop2': 1024}) as \ - ds_mocked: - with mock.patch.object(self.drv, '_get_used_devices') as \ - gud_mocked: - self.drv._update_volume_stats() - - reserved_percentage = self.configuration.reserved_percentage - self.assertEqual({ - 'vendor_name': "Open Source", - 'driver_version': self.drv.VERSION, - 'volume_backend_name': 'BlockDev', - 'storage_protocol': 'unknown', - 'pools': [{ - 'QoS_support': False, - 'total_capacity_gb': 2, - 'free_capacity_gb': 2, - 'reserved_percentage': reserved_percentage, - 'pool_name': 'BlockDev'}]}, self.drv._stats) - gud_mocked.assert_called_once_with() - ds_mocked.assert_called_once_with() - - @mock.patch('cinder.volume.utils.copy_volume') - def test_create_cloned_volume(self, _copy_volume): - TEST_SRC = obj_volume.Volume(id=fake.VOLUME_ID, - name_id=fake.VOLUME_NAME_ID, - size=1, - provider_location='/dev/loop1') - TEST_VOLUME = obj_volume.Volume(name_id=fake.VOLUME2_NAME_ID, - size=1, - display_name='vol1') - - with mock.patch.object(self.drv, 'find_appropriate_size_device', - return_value='/dev/loop2') as fasd_mocked: - with mock.patch.object(self.drv, '_get_devices_sizes', - return_value={'/dev/loop2': 2}) as \ - gds_mocked: - with mock.patch.object(self.drv, 'local_path', - return_value='/dev/loop1') as \ - lp_mocked: - with mock.patch.object(self.drv, - '_update_provider_location') as \ - upl_mocked: - volutils.copy_volume('/dev/loop1', fasd_mocked, 2, - mock.sentinel, - execute=self.drv._execute) - self.drv.create_cloned_volume(TEST_VOLUME, TEST_SRC) - fasd_mocked.assert_called_once_with(TEST_SRC.size) - lp_mocked.assert_called_once_with(TEST_SRC) - gds_mocked.assert_called_once_with(['/dev/loop2']) - upl_mocked.assert_called_once_with( - TEST_VOLUME, '/dev/loop2') - - @mock.patch.object(cinder.image.image_utils, 'fetch_to_raw') - def test_copy_image_to_volume(self, _fetch_to_raw): - TEST_VOLUME = obj_volume.Volume(name_id=fake.VOLUME_NAME_ID, - size=1, - provider_location='/dev/loop1') - TEST_IMAGE_SERVICE = "image_service" - TEST_IMAGE_ID = "image_id" - - with mock.patch.object(self.drv, 'local_path', - return_value='/dev/loop1') as lp_mocked: - self.drv.copy_image_to_volume(context, TEST_VOLUME, - TEST_IMAGE_SERVICE, TEST_IMAGE_ID) - lp_mocked.assert_called_once_with(TEST_VOLUME) - - _fetch_to_raw.assert_called_once_with(context, TEST_IMAGE_SERVICE, - TEST_IMAGE_ID, '/dev/loop1', - 1234, size=1) - - def test_copy_volume_to_image(self): - TEST_VOLUME = {'provider_location': '/dev/loop1'} - TEST_IMAGE_SERVICE = "image_service" - TEST_IMAGE_META = "image_meta" - - with mock.patch.object(cinder.image.image_utils, 'upload_volume') as \ - _upload_volume: - with mock.patch.object(self.drv, 'local_path') as _local_path: - _local_path.return_value = '/dev/loop1' - self.drv.copy_volume_to_image(context, TEST_VOLUME, - TEST_IMAGE_SERVICE, - TEST_IMAGE_META) - - self.assertTrue(_local_path.called) - _upload_volume.assert_called_once_with(context, - TEST_IMAGE_SERVICE, - TEST_IMAGE_META, - '/dev/loop1') - - def test_get_used_devices(self): - TEST_VOLUME1 = {'host': 'localhost', - 'provider_location': '/dev/loop1'} - TEST_VOLUME2 = {'host': 'localhost', - 'provider_location': '/dev/loop2'} - - def fake_local_path(vol): - return vol['provider_location'].split()[-1] - - with mock.patch.object(obj_volume.VolumeList, 'get_all_by_host', - return_value=[TEST_VOLUME1, TEST_VOLUME2]),\ - mock.patch.object(obj_snap.SnapshotList, 'get_by_host', - return_value=[]): - with mock.patch.object(context, 'get_admin_context'): - with mock.patch.object(self.drv, 'local_path', - return_value=fake_local_path): - path1 = self.drv.local_path(TEST_VOLUME1) - path2 = self.drv.local_path(TEST_VOLUME2) - self.assertEqual(set([path1, path2]), - self.drv._get_used_devices()) - - def test_get_devices_sizes(self): - dev_paths = ['/dev/loop1', '/dev/loop2', '/dev/loop3'] - out = '4294967296\n2147483648\n3221225472\nn' - with mock.patch.object(self.drv, - '_execute', - return_value=(out, None)) as _execute: - actual = self.drv._get_devices_sizes(dev_paths) - self.assertEqual(3, len(actual)) - self.assertEqual({'/dev/loop1': 4096, '/dev/loop2': 2048, - '/dev/loop3': 3072}, actual) - _execute.assert_called_once_with('blockdev', '--getsize64', - *dev_paths, run_as_root=True) - - def test_devices_sizes(self): - with mock.patch.object(self.drv, '_get_devices_sizes') as \ - _get_dvc_size: - _get_dvc_size.return_value = {'/dev/loop1': 1, '/dev/loop2': 1} - self.assertEqual(2, len(self.drv._devices_sizes())) - self.assertEqual({'/dev/loop1': 1, '/dev/loop2': 1}, - self.drv._devices_sizes()) - - def test_find_appropriate_size_device_no_free_disks(self): - size = 1 - with mock.patch.object(self.drv, '_devices_sizes') as _dvc_sizes: - with mock.patch.object(self.drv, '_get_used_devices') as \ - _get_used_dvc: - _dvc_sizes.return_value = {'/dev/loop1': 1, - '/dev/loop2': 1} - _get_used_dvc.return_value = set(['/dev/loop1', '/dev/loop2']) - self.assertRaises(cinder.exception.CinderException, - self.drv.find_appropriate_size_device, size) - - def test_find_appropriate_size_device_not_big_enough_disk(self): - size = 2948 - with mock.patch.object(self.drv, '_devices_sizes') as _dvc_sizes: - with mock.patch.object(self.drv, '_get_used_devices') as \ - _get_used_dvc: - _dvc_sizes.return_value = {'/dev/loop1': 1024, - '/dev/loop2': 1924} - _get_used_dvc.return_value = set(['/dev/loop1']) - self.assertRaises(cinder.exception.CinderException, - self.drv.find_appropriate_size_device, size) - - def test_find_appropriate_size_device(self): - size = 1 - with mock.patch.object(self.drv, '_devices_sizes') as _dvc_sizes: - with mock.patch.object(self.drv, '_get_used_devices') as \ - _get_used_dvc: - _dvc_sizes.return_value = {'/dev/loop1': 2048, - '/dev/loop2': 1024} - _get_used_dvc.return_value = set() - self.assertEqual('/dev/loop2', - self.drv.find_appropriate_size_device(size)) - - def test_extend_volume_exists(self): - TEST_VOLUME = {'name': 'vol1', 'id': 123} - with mock.patch.object(self.drv, '_get_devices_sizes', - return_value={'/dev/loop1': 1024}) as \ - mock_get_size: - with mock.patch.object(self.drv, 'local_path', - return_value='/dev/loop1') as lp_mocked: - self.assertRaises(cinder.exception.CinderException, - self.drv.extend_volume, TEST_VOLUME, 2) - lp_mocked.assert_called_once_with(TEST_VOLUME) - mock_get_size.assert_called_once_with(['/dev/loop1']) - - @mock.patch('cinder.volume.utils.copy_volume') - def test_create_snapshot(self, _copy_volume): - TEST_VOLUME = obj_volume.Volume(id=fake.VOLUME_ID, - name_id=fake.VOLUME_NAME_ID, - size=1, - display_name='vol1', - status='available', - provider_location='/dev/loop1') - TEST_SNAP = obj_snap.Snapshot(id=fake.SNAPSHOT_ID, - volume_id=fake.VOLUME_ID, - volume_size=1024, - provider_location='/dev/loop2', - volume=TEST_VOLUME) - - with mock.patch.object(self.drv, 'find_appropriate_size_device', - return_value='/dev/loop2') as fasd_mocked: - with mock.patch.object(self.drv, '_get_devices_sizes', - return_value={'/dev/loop2': 1024}) as \ - gds_mocked: - with mock.patch.object(self.drv, - '_update_provider_location') as \ - upl_mocked: - volutils.copy_volume('/dev/loop1', fasd_mocked, 1024, - mock.sentinel, - execute=self.drv._execute) - self.drv.create_snapshot(TEST_SNAP) - fasd_mocked.assert_called_once_with(TEST_SNAP.volume_size) - gds_mocked.assert_called_once_with(['/dev/loop2']) - upl_mocked.assert_called_once_with( - TEST_SNAP, '/dev/loop2') - - def test_create_snapshot_with_not_available_volume(self): - TEST_VOLUME = obj_volume.Volume(id=fake.VOLUME_ID, - name_id=fake.VOLUME_NAME_ID, - size=1, - display_name='vol1', - status='in use', - provider_location='/dev/loop1') - TEST_SNAP = obj_snap.Snapshot(id=fake.SNAPSHOT_ID, - volume_id=fake.VOLUME_ID, - volume_size=1024, - provider_location='/dev/loop2', - volume=TEST_VOLUME) - - self.assertRaises(cinder.exception.CinderException, - self.drv.create_snapshot, TEST_SNAP) - - @mock.patch('cinder.volume.utils.copy_volume') - def test_create_volume_from_snapshot(self, _copy_volume): - TEST_SNAP = obj_snap.Snapshot(volume_id=fake.VOLUME_ID, - volume_size=1024, - provider_location='/dev/loop1') - TEST_VOLUME = obj_volume.Volume(id=fake.VOLUME_ID, - name_id=fake.VOLUME_NAME_ID, - size=1, - display_name='vol1', - provider_location='/dev/loop2') - - with mock.patch.object(self.drv, 'find_appropriate_size_device', - return_value='/dev/loop2') as fasd_mocked: - with mock.patch.object(self.drv, '_get_devices_sizes', - return_value={'/dev/loop2': 1024}) as \ - gds_mocked: - with mock.patch.object(self.drv, - '_update_provider_location') as \ - upl_mocked: - volutils.copy_volume('/dev/loop1', fasd_mocked, 1024, - mock.sentinel, - execute=self.drv._execute) - self.drv.create_volume_from_snapshot( - TEST_VOLUME, TEST_SNAP) - fasd_mocked.assert_called_once_with( - TEST_SNAP.volume_size) - gds_mocked.assert_called_once_with(['/dev/loop2']) - upl_mocked.assert_called_once_with( - TEST_VOLUME, '/dev/loop2') - - @mock.patch('os.path.exists', return_value=True) - @mock.patch('cinder.volume.utils.clear_volume') - def test_delete_snapshot(self, _clear_volume, _exists): - TEST_SNAP = obj_snap.Snapshot(volume_id=fake.VOLUME_ID, - provider_location='/dev/loop1', - status=fields.SnapshotStatus.AVAILABLE) - - with mock.patch.object(self.drv, 'local_path', - return_value='/dev/loop1') as lp_mocked: - with mock.patch.object(self.drv, '_get_devices_sizes', - return_value={'/dev/loop1': 1}) as \ - gds_mocked: - volutils.clear_volume(gds_mocked, lp_mocked) - self.drv.delete_snapshot(TEST_SNAP) - lp_mocked.assert_called_once_with(TEST_SNAP) - gds_mocked.assert_called_once_with(['/dev/loop1']) - - self.assertTrue(_exists.called) - self.assertTrue(_clear_volume.called) diff --git a/cinder/volume/drivers/block_device.py b/cinder/volume/drivers/block_device.py deleted file mode 100644 index 043023562f8..00000000000 --- a/cinder/volume/drivers/block_device.py +++ /dev/null @@ -1,326 +0,0 @@ -# Copyright (c) 2013 Mirantis, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -from oslo_config import cfg -from oslo_log import log as logging -from oslo_log import versionutils -from oslo_utils import importutils -from oslo_utils import units - -from cinder import context -from cinder import exception -from cinder.i18n import _ -from cinder.image import image_utils -from cinder import interface -from cinder import objects -from cinder import utils -from cinder.volume import configuration -from cinder.volume import driver -from cinder.volume import utils as volutils - - -LOG = logging.getLogger(__name__) - -volume_opts = [ - cfg.ListOpt('available_devices', - default=[], - help='List of all available devices'), -] - -CONF = cfg.CONF -CONF.register_opts(volume_opts, group=configuration.SHARED_CONF_GROUP) - - -@interface.volumedriver -class BlockDeviceDriver(driver.BaseVD, - driver.CloneableImageVD): - VERSION = '2.3.0' - - # ThirdPartySystems wiki page - CI_WIKI_NAME = "Cinder_Jenkins" - SUPPORTED = False - - def __init__(self, *args, **kwargs): - super(BlockDeviceDriver, self).__init__(*args, **kwargs) - # This driver has been marked as deprecated in the Ocata release, as - # per the standard OpenStack deprecation policy it can be removed in - # the Queens release. - msg = _("The block_device driver is deprecated and will be " - "removed in a future release.") - versionutils.report_deprecated_feature(LOG, msg) - - self.configuration.append_config_values(volume_opts) - self.backend_name = \ - self.configuration.safe_get('volume_backend_name') or "BlockDev" - target_driver =\ - self.target_mapping[self.configuration.safe_get('iscsi_helper')] - self.target_driver = importutils.import_object( - target_driver, - configuration=self.configuration, - db=self.db, - executor=self._execute) - - def check_for_setup_error(self): - pass - - def _update_provider_location(self, obj, device): - # We update provider_location and host to mark device as used to - # avoid race with other threads. - # TODO(ynesenenko): need to remove DB access from driver - host = '{host}#{pool}'.format(host=self.host, pool=self.get_pool(obj)) - obj.update({'provider_location': device, 'host': host}) - obj.save() - - @utils.synchronized('block_device', external=True) - def create_volume(self, volume): - device = self.find_appropriate_size_device(volume.size) - LOG.info("Creating %(volume)s on %(device)s", - {"volume": volume.name, "device": device}) - self._update_provider_location(volume, device) - - def delete_volume(self, volume): - """Deletes a logical volume.""" - self._clear_block_device(volume) - - def _clear_block_device(self, device): - """Deletes a block device.""" - dev_path = self.local_path(device) - if not dev_path or dev_path not in \ - self.configuration.available_devices: - return - if os.path.exists(dev_path) and \ - self.configuration.volume_clear != 'none': - dev_size = self._get_devices_sizes([dev_path]) - volutils.clear_volume( - dev_size[dev_path], dev_path, - volume_clear=self.configuration.volume_clear, - volume_clear_size=self.configuration.volume_clear_size) - else: - LOG.warning("The device %s won't be cleared.", device) - - if device.status == "error_deleting": - msg = _("Failed to delete device.") - LOG.error(msg, resource=device) - raise exception.VolumeDriverException(msg) - - def local_path(self, device): - if device.provider_location: - path = device.provider_location.rsplit(" ", 1) - return path[-1] - else: - return None - - def copy_image_to_volume(self, context, volume, image_service, image_id): - """Fetch the image from image_service and write it to the volume.""" - image_utils.fetch_to_raw(context, - image_service, - image_id, - self.local_path(volume), - self.configuration.volume_dd_blocksize, - size=volume.size) - - def copy_volume_to_image(self, context, volume, image_service, image_meta): - """Copy the volume to the specified image.""" - image_utils.upload_volume(context, - image_service, - image_meta, - self.local_path(volume)) - - @utils.synchronized('block_device', external=True) - def create_cloned_volume(self, volume, src_vref): - LOG.info('Creating clone of volume: %s.', src_vref.id) - device = self.find_appropriate_size_device(src_vref.size) - dev_size = self._get_devices_sizes([device]) - volutils.copy_volume( - self.local_path(src_vref), device, - dev_size[device], - self.configuration.volume_dd_blocksize, - execute=self._execute) - self._update_provider_location(volume, device) - - def get_volume_stats(self, refresh=False): - if refresh: - self._update_volume_stats() - return self._stats - - def _update_volume_stats(self): - """Retrieve stats info from volume group.""" - dict_of_devices_sizes = self._devices_sizes() - used_devices = self._get_used_devices() - total_size = 0 - free_size = 0 - for device, size in dict_of_devices_sizes.items(): - if device not in used_devices: - free_size += size - total_size += size - - LOG.debug("Updating volume stats.") - data = { - 'volume_backend_name': self.backend_name, - 'vendor_name': "Open Source", - 'driver_version': self.VERSION, - 'storage_protocol': 'unknown', - 'pools': []} - - single_pool = { - 'pool_name': data['volume_backend_name'], - 'total_capacity_gb': total_size / units.Ki, - 'free_capacity_gb': free_size / units.Ki, - 'reserved_percentage': self.configuration.reserved_percentage, - 'QoS_support': False} - - data['pools'].append(single_pool) - self._stats = data - - def get_pool(self, volume): - return self.backend_name - - def _get_used_paths(self, lst): - used_dev = set() - for item in lst: - local_path = self.local_path(item) - if local_path: - used_dev.add(local_path) - return used_dev - - def _get_used_devices(self): - lst = objects.VolumeList.get_all_by_host(context.get_admin_context(), - self.host) - used_devices = self._get_used_paths(lst) - snp_lst = objects.SnapshotList.get_by_host(context.get_admin_context(), - self.host) - return used_devices.union(self._get_used_paths(snp_lst)) - - def _get_devices_sizes(self, dev_paths): - """Return devices' sizes in Mb""" - out, _err = self._execute('blockdev', '--getsize64', *dev_paths, - run_as_root=True) - dev_sizes = {} - out = out.split('\n') - # blockdev returns devices' sizes in order that - # they have been passed to it. - for n, size in enumerate(out[:-1]): - dev_sizes[dev_paths[n]] = int(size) / units.Mi - - return dev_sizes - - def _devices_sizes(self): - available_devices = self.configuration.available_devices - return self._get_devices_sizes(available_devices) - - def find_appropriate_size_device(self, size): - dict_of_devices_sizes = self._devices_sizes() - free_devices = (set(self.configuration.available_devices) - - self._get_used_devices()) - if not free_devices: - raise exception.CinderException(_("No free disk")) - possible_device = None - possible_device_size = None - for device in free_devices: - dev_size = dict_of_devices_sizes[device] - if (size * units.Ki <= dev_size and - (possible_device is None or - dev_size < possible_device_size)): - possible_device = device - possible_device_size = dev_size - - if possible_device: - return possible_device - else: - raise exception.CinderException(_("No big enough free disk")) - - def extend_volume(self, volume, new_size): - dev_path = self.local_path(volume) - total_size = self._get_devices_sizes([dev_path]) - # Convert from Megabytes to Gigabytes - size = total_size[dev_path] / units.Ki - if size < new_size: - msg = _("Insufficient free space available to extend volume.") - LOG.error(msg, resource=volume) - raise exception.CinderException(msg) - - @utils.synchronized('block_device', external=True) - def create_snapshot(self, snapshot): - volume = snapshot.volume - if volume.status != 'available': - msg = _("Volume is not available.") - LOG.error(msg, resource=volume) - raise exception.CinderException(msg) - - LOG.info('Creating volume snapshot: %s.', snapshot.id) - device = self.find_appropriate_size_device(snapshot.volume_size) - dev_size = self._get_devices_sizes([device]) - volutils.copy_volume( - self.local_path(volume), device, - dev_size[device], - self.configuration.volume_dd_blocksize, - execute=self._execute) - self._update_provider_location(snapshot, device) - - def delete_snapshot(self, snapshot): - self._clear_block_device(snapshot) - - @utils.synchronized('block_device', external=True) - def create_volume_from_snapshot(self, volume, snapshot): - LOG.info('Creating volume %s from snapshot.', volume.id) - device = self.find_appropriate_size_device(snapshot.volume_size) - dev_size = self._get_devices_sizes([device]) - volutils.copy_volume( - self.local_path(snapshot), device, - dev_size[device], - self.configuration.volume_dd_blocksize, - execute=self._execute) - self._update_provider_location(volume, device) - - # ####### Interface methods for DataPath (Target Driver) ######## - - def ensure_export(self, context, volume): - volume_path = self.local_path(volume) - model_update = \ - self.target_driver.ensure_export( - context, - volume, - volume_path) - return model_update - - def create_export(self, context, volume, connector): - volume_path = self.local_path(volume) - export_info = self.target_driver.create_export(context, - volume, - volume_path) - return { - 'provider_location': export_info['location'] + ' ' + volume_path, - 'provider_auth': export_info['auth'], - } - - def remove_export(self, context, volume): - self.target_driver.remove_export(context, volume) - - def initialize_connection(self, volume, connector): - if connector['host'] != volutils.extract_host(volume.host, 'host'): - return self.target_driver.initialize_connection(volume, connector) - else: - return { - 'driver_volume_type': 'local', - 'data': {'device_path': self.local_path(volume)}, - } - - def validate_connector(self, connector): - return self.target_driver.validate_connector(connector) - - def terminate_connection(self, volume, connector, **kwargs): - pass diff --git a/releasenotes/notes/remove-block-device-driver-14f76dca2ee9bd38.yaml b/releasenotes/notes/remove-block-device-driver-14f76dca2ee9bd38.yaml new file mode 100644 index 00000000000..f3a22d9c19e --- /dev/null +++ b/releasenotes/notes/remove-block-device-driver-14f76dca2ee9bd38.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + BlockDeviceDriver was deprecated in Ocata release and marked as + 'unsupported'. There is no CI for it too. If you used this driver before + you have to migrate your volumes to LVM with LIO target yourself before + upgrading to Queens release to get your volumes working.