diff --git a/cinder/exception.py b/cinder/exception.py index 7959ddcb537..defa800c21d 100644 --- a/cinder/exception.py +++ b/cinder/exception.py @@ -1302,11 +1302,6 @@ class HNASConnError(VolumeDriverException): message = "%(message)s" -# Tegile Storage drivers -class TegileAPIException(VolumeBackendAPIException): - message = _("Unexpected response from Tegile IntelliFlash API") - - # NexentaStor driver exception class NexentaException(VolumeDriverException): message = "%(message)s" diff --git a/cinder/opts.py b/cinder/opts.py index 7f1561f60ee..d5a55532c99 100644 --- a/cinder/opts.py +++ b/cinder/opts.py @@ -167,7 +167,6 @@ from cinder.volume.drivers import sheepdog as cinder_volume_drivers_sheepdog from cinder.volume.drivers import solidfire as cinder_volume_drivers_solidfire from cinder.volume.drivers.synology import synology_common as \ cinder_volume_drivers_synology_synologycommon -from cinder.volume.drivers import tegile as cinder_volume_drivers_tegile from cinder.volume.drivers import tintri as cinder_volume_drivers_tintri from cinder.volume.drivers.vmware import vmdk as \ cinder_volume_drivers_vmware_vmdk @@ -362,7 +361,6 @@ def list_opts(): cinder_volume_drivers_sheepdog.sheepdog_opts, cinder_volume_drivers_solidfire.sf_opts, cinder_volume_drivers_synology_synologycommon.cinder_opts, - cinder_volume_drivers_tegile.tegile_opts, cinder_volume_drivers_tintri.tintri_opts, cinder_volume_drivers_vmware_vmdk.vmdk_opts, cinder_volume_drivers_vzstorage.vzstorage_opts, diff --git a/cinder/tests/unit/volume/drivers/test_tegile.py b/cinder/tests/unit/volume/drivers/test_tegile.py deleted file mode 100644 index 6a92fba3cbc..00000000000 --- a/cinder/tests/unit/volume/drivers/test_tegile.py +++ /dev/null @@ -1,408 +0,0 @@ -# Copyright (c) 2015 by Tegile Systems, 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. -""" -Volume driver Test for Tegile storage. -""" - -import mock - -from cinder import context -from cinder.exception import TegileAPIException -from cinder import test -from cinder.volume.drivers import tegile - -BASE_DRIVER = tegile.TegileIntelliFlashVolumeDriver -ISCSI_DRIVER = tegile.TegileISCSIDriver -FC_DRIVER = tegile.TegileFCDriver - -test_config = mock.Mock() -test_config.san_ip = 'some-ip' -test_config.san_login = 'some-user' -test_config.san_password = 'some-password' -test_config.san_is_local = True -test_config.tegile_default_pool = 'random-pool' -test_config.tegile_default_project = 'random-project' -test_config.volume_backend_name = "unittest" - -test_volume = {'host': 'node#testPool', - 'name': 'testvol', - 'id': 'a24c2ee8-525a-4406-8ccd-8d38688f8e9e', - '_name_id': 'testvol', - 'metadata': {'project': 'testProj'}, - 'provider_location': None, - 'size': 10} - -test_snapshot = {'name': 'testSnap', - 'id': '07ae9978-5445-405e-8881-28f2adfee732', - 'volume': {'host': 'node#testPool', - 'size': 1, - '_name_id': 'testvol' - } - } - -array_stats = {'total_capacity_gb': 4569.199686084874, - 'free_capacity_gb': 4565.381390112452, - 'pools': [{'total_capacity_gb': 913.5, - 'QoS_support': False, - 'free_capacity_gb': 911.812650680542, - 'reserved_percentage': 0, - 'pool_name': 'pyramid' - }, - {'total_capacity_gb': 2742.1996604874, - 'QoS_support': False, - 'free_capacity_gb': 2740.148867149747, - 'reserved_percentage': 0, - 'pool_name': 'cobalt' - }, - {'total_capacity_gb': 913.5, - 'QoS_support': False, - 'free_capacity_gb': 913.4198722839355, - 'reserved_percentage': 0, - 'pool_name': 'test' - }] - } - - -class FakeTegileService(object): - @staticmethod - def send_api_request(method, params=None, - request_type='post', - api_service='v2', - fine_logging=False): - if method is 'createVolume': - return '' - elif method is 'deleteVolume': - return '' - elif method is 'createVolumeSnapshot': - return '' - elif method is 'deleteVolumeSnapshot': - return '' - elif method is 'cloneVolumeSnapshot': - return '' - elif method is 'listPools': - return '' - elif method is 'resizeVolume': - return '' - elif method is 'getVolumeSizeinGB': - return 25 - elif method is 'getISCSIMappingForVolume': - return {'target_lun': 27, - 'target_iqn': 'iqn.2012-02.com.tegile:openstack-cobalt', - 'target_portal': '10.68.103.106:3260' - } - elif method is 'getFCPortsForVolume': - return {'target_lun': 12, - 'initiator_target_map': - '{"21000024ff59bb6e":["21000024ff578701",],' - '"21000024ff59bb6f":["21000024ff578700",],}', - 'target_wwn': '["21000024ff578700","21000024ff578701",]'} - elif method is 'getArrayStats': - return array_stats - - -fake_tegile_backend = FakeTegileService() - - -class FakeTegileServiceFail(object): - @staticmethod - def send_api_request(method, params=None, - request_type='post', - api_service='v2', - fine_logging=False): - raise TegileAPIException - - -fake_tegile_backend_fail = FakeTegileServiceFail() - - -class TegileIntelliFlashVolumeDriverTestCase(test.TestCase): - def setUp(self): - self.ctxt = context.get_admin_context() - self.configuration = test_config - super(TegileIntelliFlashVolumeDriverTestCase, self).setUp() - - def test_create_volume(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual({ - 'metadata': {'pool': 'testPool', - 'project': test_config.tegile_default_project - } - }, tegile_driver.create_volume(test_volume)) - - def test_create_volume_fail(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.create_volume, - test_volume) - - def test_delete_volume(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - tegile_driver.delete_volume(test_volume) - - def test_delete_volume_fail(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.delete_volume, - test_volume) - - def test_create_snapshot(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - tegile_driver.create_snapshot(test_snapshot) - - def test_create_snapshot_fail(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.create_snapshot, - test_snapshot) - - def test_delete_snapshot(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - tegile_driver.delete_snapshot(test_snapshot) - - def test_delete_snapshot_fail(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.delete_snapshot, - test_snapshot) - - def test_create_volume_from_snapshot(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual({ - 'metadata': {'pool': 'testPool', - 'project': test_config.tegile_default_project - } - }, tegile_driver.create_volume_from_snapshot(test_volume, - test_snapshot)) - - def test_create_volume_from_snapshot_fail(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.create_volume_from_snapshot, - test_volume, test_snapshot) - - def test_create_cloned_volume(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual({'metadata': {'project': 'testProj', - 'pool': 'testPool'}}, - tegile_driver.create_cloned_volume(test_volume, - test_volume)) - - def test_create_cloned_volume_fail(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.create_cloned_volume, - test_volume, test_volume) - - def test_get_volume_stats(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual({'driver_version': '1.0.0', - 'free_capacity_gb': 4565.381390112452, - 'pools': [{'QoS_support': False, - 'allocated_capacity_gb': 0.0, - 'free_capacity_gb': 911.812650680542, - 'pool_name': 'pyramid', - 'reserved_percentage': 0, - 'total_capacity_gb': 913.5}, - {'QoS_support': False, - 'allocated_capacity_gb': 0.0, - 'free_capacity_gb': 2740.148867149747, - 'pool_name': 'cobalt', - 'reserved_percentage': 0, - 'total_capacity_gb': 2742.1996604874}, - {'QoS_support': False, - 'allocated_capacity_gb': 0.0, - 'free_capacity_gb': 913.4198722839355, - 'pool_name': 'test', - 'reserved_percentage': 0, - 'total_capacity_gb': 913.5}], - 'storage_protocol': 'iSCSI', - 'total_capacity_gb': 4569.199686084874, - 'vendor_name': 'Tegile Systems Inc.', - 'volume_backend_name': 'unittest'}, - tegile_driver.get_volume_stats(True)) - - def test_get_pool(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual('testPool', tegile_driver.get_pool(test_volume)) - - def test_extend_volume(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - tegile_driver.extend_volume(test_volume, 12) - - def test_extend_volume_fail(self): - tegile_driver = self.get_object(self.configuration) - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.extend_volume, - test_volume, 30) - - def test_manage_existing(self): - tegile_driver = self.get_object(self.configuration) - existing_ref = {'name': 'existingvol'} - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual({'metadata': {'pool': 'testPool', - 'project': 'testProj' - }, - '_name_id': ('existingvol',) - }, tegile_driver.manage_existing(test_volume, - existing_ref)) - - def test_manage_existing_get_size(self): - tegile_driver = self.get_object(self.configuration) - existing_ref = {'name': 'existingvol'} - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual(25, - tegile_driver.manage_existing_get_size( - test_volume, - existing_ref)) - - def test_manage_existing_get_size_fail(self): - tegile_driver = self.get_object(self.configuration) - existing_ref = {'name': 'existingvol'} - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend_fail): - self.assertRaises(TegileAPIException, - tegile_driver.manage_existing_get_size, - test_volume, existing_ref) - - def get_object(self, configuration): - class TegileBaseDriver(BASE_DRIVER): - def initialize_connection(self, volume, connector, **kwargs): - pass - - def terminate_connection(self, volume, connector, - force=False, **kwargs): - pass - - return TegileBaseDriver(configuration=self.configuration) - - -class TegileISCSIDriverTestCase(test.TestCase): - def setUp(self): - super(TegileISCSIDriverTestCase, self).setUp() - self.ctxt = context.get_admin_context() - self.configuration = test_config - self.configuration.chap_username = 'fake' - self.configuration.chap_password = "test" - - def test_initialize_connection(self): - tegile_driver = self.get_object(self.configuration) - connector = {'initiator': 'iqn.1993-08.org.debian:01:d0bb9a834f8'} - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual( - {'data': {'auth_method': 'CHAP', - 'discard': False, - 'target_discovered': (False,), - 'auth_password': 'test', - 'auth_username': 'fake', - 'target_iqn': 'iqn.2012-02.' - 'com.tegile:openstack-cobalt', - 'target_lun': 27, - 'target_portal': '10.68.103.106:3260', - 'volume_id': ( - 'a24c2ee8-525a-4406-8ccd-8d38688f8e9e',)}, - 'driver_volume_type': 'iscsi'}, - tegile_driver.initialize_connection(test_volume, - connector)) - - def get_object(self, configuration): - return ISCSI_DRIVER(configuration=configuration) - - -class TegileFCDriverTestCase(test.TestCase): - def setUp(self): - super(TegileFCDriverTestCase, self).setUp() - self.ctxt = context.get_admin_context() - self.configuration = test_config - - def test_initialize_connection(self): - tegile_driver = self.get_object(self.configuration) - connector = {'wwpns': ['500110a0001a3990']} - with mock.patch.object(tegile_driver, - '_api_executor', - fake_tegile_backend): - self.assertEqual({'data': {'encrypted': False, - 'initiator_target_map': { - '21000024ff59bb6e': - ['21000024ff578701'], - '21000024ff59bb6f': - ['21000024ff578700'] - }, - 'target_discovered': False, - 'target_lun': 12, - 'target_wwn': - ['21000024ff578700', - '21000024ff578701']}, - 'driver_volume_type': 'fibre_channel'}, - tegile_driver.initialize_connection( - test_volume, - connector)) - - def get_object(self, configuration): - return FC_DRIVER(configuration=configuration) diff --git a/cinder/volume/drivers/tegile.py b/cinder/volume/drivers/tegile.py deleted file mode 100644 index 76a8cb18a7e..00000000000 --- a/cinder/volume/drivers/tegile.py +++ /dev/null @@ -1,665 +0,0 @@ -# Copyright (c) 2015 by Tegile Systems, 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. -""" -Volume driver for Tegile storage. -""" - -import ast -import json -import requests - -from oslo_config import cfg -from oslo_log import log as logging -from oslo_utils import units -import six - -from cinder import exception -from cinder.i18n import _ -from cinder import interface -from cinder import utils -from cinder.volume import configuration -from cinder.volume import driver -from cinder.volume.drivers.san import san -from cinder.volume import utils as volume_utils -from cinder.zonemanager import utils as fczm_utils - -LOG = logging.getLogger(__name__) -default_api_service = 'openstack' -TEGILE_API_PATH = 'zebi/api' -TEGILE_DEFAULT_BLOCK_SIZE = '32KB' -TEGILE_LOCAL_CONTAINER_NAME = 'Local' -DEBUG_LOGGING = False - -tegile_opts = [ - cfg.StrOpt('tegile_default_pool', - help='Create volumes in this pool'), - cfg.StrOpt('tegile_default_project', - help='Create volumes in this project')] - -CONF = cfg.CONF -CONF.register_opts(tegile_opts, group=configuration.SHARED_CONF_GROUP) - - -def debugger(func): - """Returns a wrapper that wraps func. - - The wrapper will log the entry and exit points of the function - """ - - def wrapper(*args, **kwds): - if DEBUG_LOGGING: - LOG.debug('Entering %(classname)s.%(funcname)s', - {'classname': args[0].__class__.__name__, - 'funcname': func.__name__}) - LOG.debug('Arguments: %(args)s, %(kwds)s', - {'args': args[1:], - 'kwds': kwds}) - f_result = func(*args, **kwds) - if DEBUG_LOGGING: - LOG.debug('Exiting %(classname)s.%(funcname)s', - {'classname': args[0].__class__.__name__, - 'funcname': func.__name__}) - LOG.debug('Results: %(result)s', - {'result': f_result}) - return f_result - - return wrapper - - -class TegileAPIExecutor(object): - def __init__(self, classname, hostname, username, password): - self._classname = classname - self._hostname = hostname - self._username = username - self._password = password - - @debugger - @utils.retry(exceptions=(requests.ConnectionError, requests.Timeout)) - def send_api_request(self, method, params=None, - request_type='post', - api_service=default_api_service, - fine_logging=DEBUG_LOGGING): - if params is not None: - params = json.dumps(params) - - url = 'https://%s/%s/%s/%s' % (self._hostname, - TEGILE_API_PATH, - api_service, - method) - if fine_logging: - LOG.debug('TegileAPIExecutor(%(classname)s) method: %(method)s, ' - 'url: %(url)s', {'classname': self._classname, - 'method': method, - 'url': url}) - if request_type == 'post': - if fine_logging: - LOG.debug('TegileAPIExecutor(%(classname)s) ' - 'method: %(method)s, payload: %(payload)s', - {'classname': self._classname, - 'method': method, - 'payload': params}) - req = requests.post(url, - data=params, - auth=(self._username, self._password), - verify=False) - else: - req = requests.get(url, - auth=(self._username, self._password), - verify=False) - - if fine_logging: - LOG.debug('TegileAPIExecutor(%(classname)s) method: %(method)s, ' - 'return code: %(retcode)s', - {'classname': self._classname, - 'method': method, - 'retcode': req}) - try: - response = req.json() - if fine_logging: - LOG.debug('TegileAPIExecutor(%(classname)s) ' - 'method: %(method)s, response: %(response)s', - {'classname': self._classname, - 'method': method, - 'response': response}) - except ValueError: - response = '' - req.close() - - if req.status_code != 200: - msg = _('API response: %(response)s') % {'response': response} - raise exception.TegileAPIException(msg) - - return response - - -class TegileIntelliFlashVolumeDriver(san.SanDriver): - """Tegile IntelliFlash Volume Driver.""" - - VENDOR = 'Tegile Systems Inc.' - VERSION = '1.0.0' - REQUIRED_OPTIONS = ['san_ip', 'san_login', - 'san_password', 'tegile_default_pool'] - SNAPSHOT_PREFIX = 'Manual-V-' - - # ThirdPartySystems wiki page - CI_WIKI_NAME = "Tegile_Storage_CI" - - # TODO(smcginnis) Remove driver in Queens if CI issues not fixed - SUPPORTED = False - - _api_executor = None - - def __init__(self, *args, **kwargs): - self._context = None - super(TegileIntelliFlashVolumeDriver, self).__init__(*args, **kwargs) - self.configuration.append_config_values(tegile_opts) - self._protocol = 'iSCSI' # defaults to iscsi - hostname = getattr(self.configuration, 'san_ip') - username = getattr(self.configuration, 'san_login') - password = getattr(self.configuration, 'san_password') - self._default_pool = getattr(self.configuration, 'tegile_default_pool') - self._default_project = ( - getattr(self.configuration, 'tegile_default_project') or - 'openstack') - self._api_executor = TegileAPIExecutor(self.__class__.__name__, - hostname, - username, - password) - - @debugger - def do_setup(self, context): - super(TegileIntelliFlashVolumeDriver, self).do_setup(context) - self._context = context - self._check_ops(self.REQUIRED_OPTIONS, self.configuration) - - @debugger - def create_volume(self, volume): - pool = volume_utils.extract_host(volume['host'], level='pool', - default_pool_name=self._default_pool) - tegile_volume = {'blockSize': TEGILE_DEFAULT_BLOCK_SIZE, - 'datasetPath': '%s/%s/%s' % - (pool, - TEGILE_LOCAL_CONTAINER_NAME, - self._default_project), - 'local': 'true', - 'name': volume['name'], - 'poolName': '%s' % pool, - 'projectName': '%s' % self._default_project, - 'protocol': self._protocol, - 'thinProvision': 'true', - 'volSize': volume['size'] * units.Gi} - params = list() - params.append(tegile_volume) - params.append(True) - - self._api_executor.send_api_request(method='createVolume', - params=params) - - LOG.info("Created volume %(volname)s, volume id %(volid)s.", - {'volname': volume['name'], 'volid': volume['id']}) - - return self.get_additional_info(volume, pool, self._default_project) - - @debugger - def delete_volume(self, volume): - """Deletes a snapshot.""" - params = list() - pool, project, volume_name = self._get_pool_project_volume_name(volume) - params.append('%s/%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name)) - params.append(True) - params.append(False) - - self._api_executor.send_api_request('deleteVolume', params) - - @debugger - def create_snapshot(self, snapshot): - """Creates a snapshot.""" - snap_name = snapshot['name'] - display_list = [getattr(snapshot, 'display_name', ''), - getattr(snapshot, 'display_description', '')] - snap_description = ':'.join(filter(None, display_list)) - # Limit to 254 characters - snap_description = snap_description[:254] - - pool, project, volume_name = self._get_pool_project_volume_name( - snapshot['volume']) - - volume = {'blockSize': TEGILE_DEFAULT_BLOCK_SIZE, - 'datasetPath': '%s/%s/%s' % - (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project), - 'local': 'true', - 'name': volume_name, - 'poolName': '%s' % pool, - 'projectName': '%s' % project, - 'protocol': self._protocol, - 'thinProvision': 'true', - 'volSize': snapshot['volume']['size'] * units.Gi} - params = list() - params.append(volume) - params.append(snap_name) - params.append(False) - - LOG.info('Creating snapshot for volume_name=%(vol)s' - ' snap_name=%(name)s snap_description=%(desc)s', - {'vol': volume_name, - 'name': snap_name, - 'desc': snap_description}) - - self._api_executor.send_api_request('createVolumeSnapshot', params) - - @debugger - def delete_snapshot(self, snapshot): - """Deletes a snapshot.""" - params = list() - pool, project, volume_name = self._get_pool_project_volume_name( - snapshot['volume']) - params.append('%s/%s/%s/%s@%s%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name, - self.SNAPSHOT_PREFIX, - snapshot['name'])) - params.append(False) - - self._api_executor.send_api_request('deleteVolumeSnapshot', params) - - @debugger - def create_volume_from_snapshot(self, volume, snapshot): - """Creates a volume from snapshot.""" - params = list() - pool, project, volume_name = self._get_pool_project_volume_name( - snapshot['volume']) - - params.append('%s/%s/%s/%s@%s%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name, - self.SNAPSHOT_PREFIX, - snapshot['name'])) - params.append(volume['name']) - params.append(True) - params.append(True) - - self._api_executor.send_api_request('cloneVolumeSnapshot', params) - return self.get_additional_info(volume, pool, project) - - @debugger - def create_cloned_volume(self, volume, src_vref): - """Creates a clone of the specified volume.""" - pool, project, volume_name = self._get_pool_project_volume_name( - src_vref) - data_set_path = '%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project) - source_volume = {'blockSize': TEGILE_DEFAULT_BLOCK_SIZE, - 'datasetPath': data_set_path, - 'local': 'true', - 'name': volume_name, - 'poolName': '%s' % pool, - 'projectName': '%s' % project, - 'protocol': self._protocol, - 'thinProvision': 'true', - 'volSize': src_vref['size'] * units.Gi} - - dest_volume = {'blockSize': TEGILE_DEFAULT_BLOCK_SIZE, - 'datasetPath': data_set_path, - # clone can reside only in the source project - 'local': 'true', - 'name': volume['name'], - 'poolName': '%s' % pool, - 'projectName': '%s' % project, - 'protocol': self._protocol, - 'thinProvision': 'true', - 'volSize': volume['size'] * units.Gi} - - params = list() - params.append(source_volume) - params.append(dest_volume) - - self._api_executor.send_api_request(method='createClonedVolume', - params=params) - return self.get_additional_info(volume, pool, project) - - @debugger - def get_volume_stats(self, refresh=False): - """Get volume status. - - If 'refresh' is True, run update first. - The name is a bit misleading as - the majority of the data here is cluster - data - """ - if refresh: - try: - self._update_volume_stats() - except Exception: - pass - - return self._stats - - @debugger - def _update_volume_stats(self): - """Retrieves stats info from volume group.""" - - try: - data = self._api_executor.send_api_request(method='getArrayStats', - request_type='get', - fine_logging=False) - # fixing values coming back here as String to float - data['total_capacity_gb'] = float(data.get('total_capacity_gb', 0)) - data['free_capacity_gb'] = float(data.get('free_capacity_gb', 0)) - for pool in data.get('pools', []): - pool['total_capacity_gb'] = float( - pool.get('total_capacity_gb', 0)) - pool['free_capacity_gb'] = float( - pool.get('free_capacity_gb', 0)) - pool['allocated_capacity_gb'] = float( - pool.get('allocated_capacity_gb', 0)) - - data['volume_backend_name'] = getattr(self.configuration, - 'volume_backend_name') - data['vendor_name'] = self.VENDOR - data['driver_version'] = self.VERSION - data['storage_protocol'] = self._protocol - - self._stats = data - except Exception as e: - LOG.warning('TegileIntelliFlashVolumeDriver(%(clsname)s) ' - '_update_volume_stats failed: %(error)s', - {'clsname': self.__class__.__name__, - 'error': e}) - - @debugger - def get_pool(self, volume): - """Returns pool name where volume resides. - - :param volume: The volume hosted by the driver. - :return: Name of the pool where given volume is hosted. - """ - pool = volume_utils.extract_host(volume['host'], level='pool', - default_pool_name=self._default_pool) - return pool - - @debugger - def extend_volume(self, volume, new_size): - params = list() - pool, project, volume_name = self._get_pool_project_volume_name(volume) - params.append('%s/%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name)) - vol_size = six.text_type(new_size) - params.append(vol_size) - params.append('GB') - self._api_executor.send_api_request(method='resizeVolume', - params=params) - - @debugger - def manage_existing(self, volume, existing_ref): - volume['name_id'] = existing_ref['name'] - pool, project, volume_name = self._get_pool_project_volume_name(volume) - additional_info = self.get_additional_info(volume, pool, project) - additional_info['_name_id'] = existing_ref['name'], - return additional_info - - @debugger - def manage_existing_get_size(self, volume, existing_ref): - params = list() - pool, project, volume_name = self._get_pool_project_volume_name(volume) - params.append('%s/%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - existing_ref['name'])) - volume_size = self._api_executor.send_api_request( - method='getVolumeSizeinGB', - params=params) - - return volume_size - - @debugger - def _get_pool_project_volume_name(self, volume): - pool = volume_utils.extract_host(volume['host'], level='pool', - default_pool_name=self._default_pool) - try: - project = volume['metadata']['project'] - except (AttributeError, TypeError, KeyError): - project = self._default_project - - if volume['_name_id'] is not None: - volume_name = volume['_name_id'] - else: - volume_name = volume['name'] - - return pool, project, volume_name - - @debugger - def get_additional_info(self, volume, pool, project): - try: - metadata = self._get_volume_metadata(volume) - except Exception: - metadata = dict() - metadata['pool'] = pool - metadata['project'] = project - return {'metadata': metadata} - - @debugger - def _get_volume_metadata(self, volume): - volume_metadata = {} - if 'volume_metadata' in volume: - for metadata in volume['volume_metadata']: - volume_metadata[metadata['key']] = metadata['value'] - if 'metadata' in volume: - metadata = volume['metadata'] - for key in metadata: - volume_metadata[key] = metadata[key] - return volume_metadata - - @debugger - def _check_ops(self, required_ops, configuration): - """Ensures that the options we care about are set.""" - for attr in required_ops: - if not getattr(configuration, attr, None): - raise exception.InvalidInput(reason=_('%(attr)s is not ' - 'set.') % {'attr': attr}) - - -@interface.volumedriver -class TegileISCSIDriver(TegileIntelliFlashVolumeDriver, san.SanISCSIDriver): - """Tegile ISCSI Driver.""" - - def __init__(self, *args, **kwargs): - super(TegileISCSIDriver, self).__init__(*args, **kwargs) - self._protocol = 'iSCSI' - - @debugger - def do_setup(self, context): - super(TegileISCSIDriver, self).do_setup(context) - - @debugger - def initialize_connection(self, volume, connector): - """Driver entry point to attach a volume to an instance.""" - - if getattr(self.configuration, 'use_chap_auth', False): - chap_username = getattr(self.configuration, 'chap_username', '') - chap_password = getattr(self.configuration, 'chap_password', '') - else: - chap_username = '' - chap_password = '' - - if volume['provider_location'] is None: - params = list() - pool, project, volume_name = ( - self._get_pool_project_volume_name(volume)) - params.append('%s/%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name)) - initiator_info = { - 'initiatorName': connector['initiator'], - 'chapUserName': chap_username, - 'chapSecret': chap_password - } - params.append(initiator_info) - mapping_info = self._api_executor.send_api_request( - method='getISCSIMappingForVolume', - params=params) - target_portal = mapping_info['target_portal'] - target_iqn = mapping_info['target_iqn'] - target_lun = mapping_info['target_lun'] - else: - (target_portal, target_iqn, target_lun) = ( - volume['provider_location'].split()) - - connection_data = dict() - connection_data['target_portal'] = target_portal - connection_data['target_iqn'] = target_iqn - connection_data['target_lun'] = int(target_lun) - connection_data['target_discovered'] = False, - connection_data['volume_id'] = volume['id'], - connection_data['discard'] = False - if getattr(self.configuration, 'use_chap_auth', False): - connection_data['auth_method'] = 'CHAP' - connection_data['auth_username'] = chap_username - connection_data['auth_password'] = chap_password - return { - 'driver_volume_type': 'iscsi', - 'data': connection_data - } - - @debugger - def terminate_connection(self, volume, connector, **kwargs): - pass - - @debugger - def create_export(self, context, volume, connector): - """Driver entry point to get the export info for a new volume.""" - params = list() - pool, project, volume_name = self._get_pool_project_volume_name(volume) - params.append('%s/%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name)) - if getattr(self.configuration, 'use_chap_auth', False): - chap_username = getattr(self.configuration, 'chap_username', '') - chap_password = getattr(self.configuration, 'chap_password', '') - else: - chap_username = '' - chap_password = '' - - initiator_info = { - 'initiatorName': connector['initiator'], - 'chapUserName': chap_username, - 'chapSecret': chap_password - } - params.append(initiator_info) - mapping_info = self._api_executor.send_api_request( - method='getISCSIMappingForVolume', - params=params) - target_portal = mapping_info['target_portal'] - target_iqn = mapping_info['target_iqn'] - target_lun = int(mapping_info['target_lun']) - - provider_location = '%s %s %s' % (target_portal, - target_iqn, - target_lun) - if getattr(self.configuration, 'use_chap_auth', False): - provider_auth = ('CHAP %s %s' % (chap_username, - chap_password)) - else: - provider_auth = None - return ( - {'provider_location': provider_location, - 'provider_auth': provider_auth}) - - -@interface.volumedriver -class TegileFCDriver(TegileIntelliFlashVolumeDriver, - driver.FibreChannelDriver): - """Tegile FC driver.""" - - def __init__(self, *args, **kwargs): - super(TegileFCDriver, self).__init__(*args, **kwargs) - self._protocol = 'FC' - - @debugger - def do_setup(self, context): - super(TegileFCDriver, self).do_setup(context) - - @fczm_utils.add_fc_zone - @debugger - def initialize_connection(self, volume, connector): - """Initializes the connection and returns connection info.""" - - params = list() - pool, project, volume_name = self._get_pool_project_volume_name(volume) - params.append('%s/%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name)) - wwpns = connector['wwpns'] - - connectors = ','.join(wwpns) - - params.append(connectors) - target_info = self._api_executor.send_api_request( - method='getFCPortsForVolume', - params=params) - initiator_target_map = target_info['initiator_target_map'] - connection_data = { - 'driver_volume_type': 'fibre_channel', - 'data': { - 'encrypted': False, - 'target_discovered': False, - 'target_lun': int(target_info['target_lun']), - 'target_wwn': ast.literal_eval(target_info['target_wwn']), - 'initiator_target_map': ast.literal_eval(initiator_target_map) - } - } - - return connection_data - - @fczm_utils.remove_fc_zone - @debugger - def terminate_connection(self, volume, connector, force=False, **kwargs): - - params = list() - pool, project, volume_name = self._get_pool_project_volume_name(volume) - params.append('%s/%s/%s/%s' % (pool, - TEGILE_LOCAL_CONTAINER_NAME, - project, - volume_name)) - wwpns = connector['wwpns'] - - connectors = ','.join(wwpns) - - params.append(connectors) - target_info = self._api_executor.send_api_request( - method='getFCPortsForVolume', - params=params) - initiator_target_map = target_info['initiator_target_map'] - - connection_data = { - 'data': { - 'target_wwn': ast.literal_eval(target_info['target_wwn']), - 'initiator_target_map': ast.literal_eval(initiator_target_map) - } - } - - return connection_data diff --git a/doc/source/configuration/block-storage/config-options.rst b/doc/source/configuration/block-storage/config-options.rst index 55c6060ab20..1d50fcb3674 100644 --- a/doc/source/configuration/block-storage/config-options.rst +++ b/doc/source/configuration/block-storage/config-options.rst @@ -31,5 +31,4 @@ These options can also be set in the ``cinder.conf`` file. .. include:: ../tables/cinder-scheduler.inc .. include:: ../tables/cinder-scst.inc .. include:: ../tables/cinder-storage.inc -.. include:: ../tables/cinder-tegile.inc .. include:: ../tables/cinder-zones.inc diff --git a/doc/source/configuration/tables/cinder-tegile.inc b/doc/source/configuration/tables/cinder-tegile.inc deleted file mode 100644 index a98feb90c57..00000000000 --- a/doc/source/configuration/tables/cinder-tegile.inc +++ /dev/null @@ -1,24 +0,0 @@ -.. - Warning: Do not edit this file. It is automatically generated from the - software project's code and your changes will be overwritten. - - The tool to generate this file lives in openstack-doc-tools repository. - - Please make any changes needed in the code, then run the - autogenerate-config-doc tool from the openstack-doc-tools repository, or - ask for help on the documentation mailing list, IRC channel or meeting. - -.. _cinder-tegile: - -.. list-table:: Description of Tegile volume driver configuration options - :header-rows: 1 - :class: config-ref-table - - * - Configuration option = Default value - - Description - * - **[DEFAULT]** - - - * - ``tegile_default_pool`` = ``None`` - - (String) Create volumes in this pool - * - ``tegile_default_project`` = ``None`` - - (String) Create volumes in this project diff --git a/releasenotes/notes/queens-driver-removal-72a1a36689b6d890.yaml b/releasenotes/notes/queens-driver-removal-72a1a36689b6d890.yaml index 2d0a45c9117..142353ca0be 100644 --- a/releasenotes/notes/queens-driver-removal-72a1a36689b6d890.yaml +++ b/releasenotes/notes/queens-driver-removal-72a1a36689b6d890.yaml @@ -11,6 +11,7 @@ upgrade: * Infortrend * QNAP * Reduxio + * Tegile * Violin * X-IO * ZTE