diff --git a/cinder/opts.py b/cinder/opts.py index e0343d5cd07..a857b73db5b 100644 --- a/cinder/opts.py +++ b/cinder/opts.py @@ -95,10 +95,10 @@ from cinder.volume.drivers.fusionstorage import dsware as \ cinder_volume_drivers_fusionstorage_dsware from cinder.volume.drivers.hitachi import hbsd_common as \ cinder_volume_drivers_hitachi_hbsdcommon -from cinder.volume.drivers.hitachi import hbsd_fc as \ - cinder_volume_drivers_hitachi_hbsdfc from cinder.volume.drivers.hitachi import hbsd_rest as \ cinder_volume_drivers_hitachi_hbsdrest +from cinder.volume.drivers.hitachi import hbsd_rest_fc as \ + cinder_volume_drivers_hitachi_hbsdrestfc from cinder.volume.drivers.hpe import hpe_3par_common as \ cinder_volume_drivers_hpe_hpe3parcommon from cinder.volume.drivers.huawei import common as \ @@ -328,8 +328,8 @@ def list_opts(): cinder_volume_drivers_fujitsu_eternus_dx_eternusdxcommon. FJ_ETERNUS_DX_OPT_opts, cinder_volume_drivers_hitachi_hbsdcommon.COMMON_VOLUME_OPTS, - cinder_volume_drivers_hitachi_hbsdfc.FC_VOLUME_OPTS, cinder_volume_drivers_hitachi_hbsdrest.REST_VOLUME_OPTS, + cinder_volume_drivers_hitachi_hbsdrestfc.FC_VOLUME_OPTS, cinder_volume_drivers_hpe_hpe3parcommon.hpe3par_opts, cinder_volume_drivers_huawei_common.huawei_opts, cinder_volume_drivers_ibm_flashsystemcommon.flashsystem_opts, diff --git a/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_fc.py b/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_fc.py index e1c97633113..ff92de96e4c 100644 --- a/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_fc.py +++ b/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_fc.py @@ -23,6 +23,7 @@ from requests import models from cinder import context as cinder_context from cinder.db.sqlalchemy import api as sqlalchemy_api +from cinder import exception from cinder.objects import group_snapshot as obj_group_snap from cinder.objects import snapshot as obj_snap from cinder.tests.unit import fake_group @@ -36,7 +37,6 @@ from cinder.volume.drivers.hitachi import hbsd_common from cinder.volume.drivers.hitachi import hbsd_fc from cinder.volume.drivers.hitachi import hbsd_rest from cinder.volume.drivers.hitachi import hbsd_rest_api -from cinder.volume.drivers.hitachi import hbsd_utils from cinder.volume import volume_types from cinder.volume import volume_utils from cinder.zonemanager import utils as fczm_utils @@ -617,7 +617,7 @@ class HBSDRESTFCDriverTest(test.TestCase): request.return_value = FakeResponse( 500, ERROR_RESULT, headers={'Content-Type': 'json'}) - self.assertRaises(hbsd_utils.HBSDError, + self.assertRaises(exception.VolumeDriverException, self.driver.create_volume, fake_volume.fake_volume_obj(self.ctxt)) self.assertGreater(request.call_count, 1) @@ -651,7 +651,7 @@ class HBSDRESTFCDriverTest(test.TestCase): FakeResponse(200, GET_LDEV_RESULT_PAIR), FakeResponse(200, GET_LDEV_RESULT_PAIR), FakeResponse(200, GET_LDEV_RESULT_PAIR)] - self.assertRaises(hbsd_utils.HBSDError, + self.assertRaises(exception.VolumeDriverException, self.driver.delete_volume, TEST_VOLUME[0]) self.assertGreater(request.call_count, 2) @@ -741,7 +741,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(fczm_utils, "add_fc_zone") @mock.patch.object(requests.Session, "request") def test_initialize_connection(self, request, add_fc_zone): - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [FakeResponse(200, GET_HOST_WWNS_RESULT), FakeResponse(202, COMPLETED_SUCCEEDED_RESULT)] @@ -757,7 +757,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(requests.Session, "request") def test_initialize_connection_already_mapped(self, request, add_fc_zone): """Normal case: ldev have already mapped.""" - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [ FakeResponse(200, GET_HOST_WWNS_RESULT), @@ -776,7 +776,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(requests.Session, "request") def test_initialize_connection_shared_target(self, request, add_fc_zone): """Normal case: A target shared with other systems.""" - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [FakeResponse(200, NOTFOUND_RESULT), FakeResponse(200, NOTFOUND_RESULT), @@ -794,7 +794,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(fczm_utils, "remove_fc_zone") @mock.patch.object(requests.Session, "request") def test_terminate_connection(self, request, remove_fc_zone): - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [FakeResponse(200, GET_HOST_WWNS_RESULT), FakeResponse(200, GET_LDEV_RESULT_MAPPED), @@ -809,7 +809,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(requests.Session, "request") def test_terminate_connection_not_connector(self, request, remove_fc_zone): """Normal case: Connector is None.""" - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [FakeResponse(200, GET_LDEV_RESULT_MAPPED), FakeResponse(200, GET_HOST_GROUP_RESULT), @@ -827,7 +827,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(requests.Session, "request") def test_terminate_connection_not_lun(self, request, remove_fc_zone): """Normal case: Lun already not exist.""" - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [FakeResponse(200, GET_HOST_WWNS_RESULT), FakeResponse(200, GET_LDEV_RESULT)] @@ -838,7 +838,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(fczm_utils, "add_fc_zone") @mock.patch.object(requests.Session, "request") def test_initialize_connection_snapshot(self, request, add_fc_zone): - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [FakeResponse(200, GET_HOST_WWNS_RESULT), FakeResponse(202, COMPLETED_SUCCEEDED_RESULT)] @@ -853,7 +853,7 @@ class HBSDRESTFCDriverTest(test.TestCase): @mock.patch.object(fczm_utils, "remove_fc_zone") @mock.patch.object(requests.Session, "request") def test_terminate_connection_snapshot(self, request, remove_fc_zone): - self.configuration.hitachi_zoning_request = True + self.driver.common.conf.hitachi_zoning_request = True self.driver.common._lookup_service = FakeLookupService() request.side_effect = [FakeResponse(200, GET_HOST_WWNS_RESULT), FakeResponse(200, GET_LDEV_RESULT_MAPPED), @@ -1020,7 +1020,7 @@ class HBSDRESTFCDriverTest(test.TestCase): def test_create_group_from_src_volume_error(self): self.assertRaises( - hbsd_utils.HBSDError, self.driver.create_group_from_src, + exception.VolumeDriverException, self.driver.create_group_from_src, self.ctxt, TEST_GROUP[1], [TEST_VOLUME[1]], source_group=TEST_GROUP[0], source_vols=[TEST_VOLUME[3]] ) @@ -1036,7 +1036,7 @@ class HBSDRESTFCDriverTest(test.TestCase): def test_update_group_error(self, is_group_a_cg_snapshot_type): is_group_a_cg_snapshot_type.return_value = True self.assertRaises( - hbsd_utils.HBSDError, self.driver.update_group, + exception.VolumeDriverException, self.driver.update_group, self.ctxt, TEST_GROUP[0], add_volumes=[TEST_VOLUME[3]], remove_volumes=[TEST_VOLUME[0]] ) diff --git a/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_iscsi.py b/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_iscsi.py index 5b5623f7f05..beb38e71985 100644 --- a/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_iscsi.py +++ b/cinder/tests/unit/volume/drivers/hitachi/test_hitachi_hbsd_rest_iscsi.py @@ -21,6 +21,7 @@ import requests from cinder import context as cinder_context from cinder.db.sqlalchemy import api as sqlalchemy_api +from cinder import exception from cinder.objects import group_snapshot as obj_group_snap from cinder.objects import snapshot as obj_snap from cinder.tests.unit import fake_group @@ -34,7 +35,6 @@ from cinder.volume.drivers.hitachi import hbsd_common from cinder.volume.drivers.hitachi import hbsd_iscsi from cinder.volume.drivers.hitachi import hbsd_rest from cinder.volume.drivers.hitachi import hbsd_rest_api -from cinder.volume.drivers.hitachi import hbsd_utils from cinder.volume import volume_types from cinder.volume import volume_utils @@ -497,14 +497,14 @@ class HBSDRESTISCSIDriverTest(test.TestCase): @mock.patch.object(driver.ISCSIDriver, "get_goodness_function") @mock.patch.object(driver.ISCSIDriver, "get_filter_function") @mock.patch.object(requests.Session, "request") - def test_get_volume_stats( + def test__update_volume_stats( self, request, get_filter_function, get_goodness_function): request.return_value = FakeResponse(200, GET_POOL_RESULT) get_filter_function.return_value = None get_goodness_function.return_value = None - stats = self.driver.get_volume_stats(True) - self.assertEqual('Hitachi', stats['vendor_name']) - self.assertTrue(stats["pools"][0]['multiattach']) + self.driver._update_volume_stats() + self.assertEqual('Hitachi', self.driver._stats['vendor_name']) + self.assertTrue(self.driver._stats["pools"][0]['multiattach']) self.assertEqual(1, request.call_count) self.assertEqual(1, get_filter_function.call_count) self.assertEqual(1, get_goodness_function.call_count) @@ -826,7 +826,7 @@ class HBSDRESTISCSIDriverTest(test.TestCase): def test_create_group_from_src_volume_error(self): self.assertRaises( - hbsd_utils.HBSDError, self.driver.create_group_from_src, + exception.VolumeDriverException, self.driver.create_group_from_src, self.ctxt, TEST_GROUP[1], [TEST_VOLUME[1]], source_group=TEST_GROUP[0], source_vols=[TEST_VOLUME[3]] ) @@ -842,7 +842,7 @@ class HBSDRESTISCSIDriverTest(test.TestCase): def test_update_group_error(self, is_group_a_cg_snapshot_type): is_group_a_cg_snapshot_type.return_value = True self.assertRaises( - hbsd_utils.HBSDError, self.driver.update_group, + exception.VolumeDriverException, self.driver.update_group, self.ctxt, TEST_GROUP[0], add_volumes=[TEST_VOLUME[3]], remove_volumes=[TEST_VOLUME[0]] ) diff --git a/cinder/volume/drivers/hitachi/hbsd_common.py b/cinder/volume/drivers/hitachi/hbsd_common.py index 765029bf58a..8169660a98a 100644 --- a/cinder/volume/drivers/hitachi/hbsd_common.py +++ b/cinder/volume/drivers/hitachi/hbsd_common.py @@ -22,12 +22,11 @@ from oslo_utils import excutils from cinder import coordination from cinder import exception +from cinder.i18n import _ from cinder.volume import configuration from cinder.volume.drivers.hitachi import hbsd_utils as utils from cinder.volume import volume_utils -VERSION = '2.2.0' - _STR_VOLUME = 'volume' _STR_SNAPSHOT = 'snapshot' @@ -106,11 +105,6 @@ COMMON_VOLUME_OPTS = [ 'a copy pair deletion or data restoration.'), ] -_REQUIRED_COMMON_OPTS = [ - 'hitachi_storage_id', - 'hitachi_pool', -] - CONF = cfg.CONF CONF.register_opts(COMMON_VOLUME_OPTS, group=configuration.SHARED_CONF_GROUP) @@ -155,6 +149,10 @@ class HBSDCommon(): 'wwns': {}, 'portals': {}, } + self._required_common_opts = [ + self.driver_info['param_prefix'] + '_storage_id', + self.driver_info['param_prefix'] + '_pool', + ] def create_ldev(self, size): """Create an LDEV and return its LDEV number.""" @@ -189,7 +187,7 @@ class HBSDCommon(): ldev_info = self.get_ldev_info(['status', 'attributes'], pvol) if ldev_info['status'] != 'NML': msg = utils.output_log(MSG.INVALID_LDEV_STATUS_FOR_COPY, ldev=pvol) - raise utils.HBSDError(msg) + self.raise_error(msg) svol = self.create_ldev(size) try: self.create_pair_on_storage(pvol, svol, is_snapshot) @@ -197,7 +195,7 @@ class HBSDCommon(): with excutils.save_and_reraise_exception(): try: self.delete_ldev(svol) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log(MSG.DELETE_LDEV_FAILED, ldev=svol) return svol @@ -209,7 +207,7 @@ class HBSDCommon(): if ldev is None: msg = utils.output_log( MSG.INVALID_LDEV_FOR_VOLUME_COPY, type=src_type, id=src['id']) - raise utils.HBSDError(msg) + self.raise_error(msg) size = volume['size'] new_ldev = self._copy_on_storage(ldev, size) @@ -243,7 +241,7 @@ class HBSDCommon(): if pair_info['pvol'] == ldev: utils.output_log( MSG.UNABLE_TO_DELETE_PAIR, pvol=pair_info['pvol']) - raise utils.HBSDBusy() + self.raise_busy() else: self.delete_pair_based_on_svol( pair_info['pvol'], pair_info['svol_info'][0]) @@ -284,8 +282,11 @@ class HBSDCommon(): return try: self.delete_ldev(ldev) - except utils.HBSDBusy: - raise exception.VolumeIsBusy(volume_name=volume['name']) + except exception.VolumeDriverException as ex: + if ex.msg == utils.BUSY_MESSAGE: + raise exception.VolumeIsBusy(volume_name=volume['name']) + else: + raise ex def create_snapshot(self, snapshot): """Create a snapshot from a volume and return its properties.""" @@ -295,7 +296,7 @@ class HBSDCommon(): msg = utils.output_log( MSG.INVALID_LDEV_FOR_VOLUME_COPY, type='volume', id=src_vref['id']) - raise utils.HBSDError(msg) + self.raise_error(msg) size = snapshot['volume_size'] new_ldev = self._copy_on_storage(ldev, size, True) return { @@ -312,8 +313,11 @@ class HBSDCommon(): return try: self.delete_ldev(ldev) - except utils.HBSDBusy: - raise exception.SnapshotIsBusy(snapshot_name=snapshot['name']) + except exception.VolumeDriverException as ex: + if ex.msg == utils.BUSY_MESSAGE: + raise exception.SnapshotIsBusy(snapshot_name=snapshot['name']) + else: + raise ex def get_pool_info(self): """Return the total and free capacity of the storage pool.""" @@ -326,8 +330,8 @@ class HBSDCommon(): self.driver_info['volume_backend_name']) data = { 'volume_backend_name': backend_name, - 'vendor_name': 'Hitachi', - 'driver_version': VERSION, + 'vendor_name': self.driver_info['vendor_name'], + 'driver_version': self.driver_info['version'], 'storage_protocol': self.storage_info['protocol'], 'pools': [], } @@ -344,7 +348,7 @@ class HBSDCommon(): try: (total_capacity, free_capacity, provisioned_capacity) = self.get_pool_info() - except utils.HBSDError: + except exception.VolumeDriverException: single_pool.update(dict( provisioned_capacity_gb=0, backend_state='down')) @@ -387,11 +391,11 @@ class HBSDCommon(): if ldev is None: msg = utils.output_log(MSG.INVALID_LDEV_FOR_EXTENSION, volume_id=volume['id']) - raise utils.HBSDError(msg) + self.raise_error(msg) if self.check_pair_svol(ldev): msg = utils.output_log(MSG.INVALID_VOLUME_TYPE_FOR_EXTEND, volume_id=volume['id']) - raise utils.HBSDError(msg) + self.raise_error(msg) self.delete_pair(ldev) self.extend_ldev(ldev, volume['size'], new_size) @@ -448,8 +452,11 @@ class HBSDCommon(): raise exception.VolumeIsBusy(volume_name=volume['name']) try: self.delete_pair(ldev) - except utils.HBSDBusy: - raise exception.VolumeIsBusy(volume_name=volume['name']) + except exception.VolumeDriverException as ex: + if ex.msg == utils.BUSY_MESSAGE: + raise exception.VolumeIsBusy(volume_name=volume['name']) + else: + raise ex def _range2list(self, param): """Analyze a 'xxx-xxx' string and return a list of two integers.""" @@ -457,7 +464,7 @@ class HBSDCommon(): self.conf.safe_get(param).split('-')] if len(values) != 2 or None in values or values[0] > values[1]: msg = utils.output_log(MSG.INVALID_PARAMETER, param=param) - raise utils.HBSDError(msg) + self.raise_error(msg) return values def check_param_iscsi(self): @@ -466,38 +473,37 @@ class HBSDCommon(): if not self.conf.chap_username: msg = utils.output_log(MSG.INVALID_PARAMETER, param='chap_username') - raise utils.HBSDError(msg) + self.raise_error(msg) if not self.conf.chap_password: msg = utils.output_log(MSG.INVALID_PARAMETER, param='chap_password') - raise utils.HBSDError(msg) + self.raise_error(msg) def check_param(self): """Check parameter values and consistency among them.""" utils.check_opt_value(self.conf, _INHERITED_VOLUME_OPTS) - utils.check_opts(self.conf, COMMON_VOLUME_OPTS) - utils.check_opts(self.conf, self.driver_info['volume_opts']) + self.check_opts(self.conf, COMMON_VOLUME_OPTS) if self.conf.hitachi_ldev_range: self.storage_info['ldev_range'] = self._range2list( - 'hitachi_ldev_range') + self.driver_info['param_prefix'] + '_ldev_range') if (not self.conf.hitachi_target_ports and not self.conf.hitachi_compute_target_ports): msg = utils.output_log( MSG.INVALID_PARAMETER, param='hitachi_target_ports or ' 'hitachi_compute_target_ports') - raise utils.HBSDError(msg) + self.raise_error(msg) if (self.conf.hitachi_group_delete and not self.conf.hitachi_group_create): msg = utils.output_log( MSG.INVALID_PARAMETER, param='hitachi_group_delete or ' 'hitachi_group_create') - raise utils.HBSDError(msg) - for opt in _REQUIRED_COMMON_OPTS: + self.raise_error(msg) + for opt in self._required_common_opts: if not self.conf.safe_get(opt): msg = utils.output_log(MSG.INVALID_PARAMETER, param=opt) - raise utils.HBSDError(msg) + self.raise_error(msg) if self.storage_info['protocol'] == 'iSCSI': self.check_param_iscsi() @@ -535,7 +541,7 @@ class HBSDCommon(): return connector[self.driver_info['hba_id']] msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource=self.driver_info['hba_id_type']) - raise utils.HBSDError(msg) + self.raise_error(msg) def create_target_to_storage(self, port, connector, hba_ids): """Create a host group or an iSCSI target on the specified port.""" @@ -579,7 +585,7 @@ class HBSDCommon(): try: self._create_target(targets, port, connector, hba_ids) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log( self.driver_info['msg_id']['target'], port=port) @@ -604,7 +610,7 @@ class HBSDCommon(): self.conf.hitachi_group_create): self.create_mapping_targets(targets, connector) - utils.require_target_existed(targets) + self.require_target_existed(targets) def do_setup(self, context): """Prepare for the startup of the driver.""" @@ -627,12 +633,12 @@ class HBSDCommon(): not self.storage_info['controller_ports']): msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource="Target ports") - raise utils.HBSDError(msg) + self.raise_error(msg) if (self.conf.hitachi_compute_target_ports and not self.storage_info['compute_ports']): msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource="Compute target ports") - raise utils.HBSDError(msg) + self.raise_error(msg) utils.output_log(MSG.SET_CONFIG_VALUE, object='target port list', value=self.storage_info['controller_ports']) utils.output_log(MSG.SET_CONFIG_VALUE, @@ -694,8 +700,9 @@ class HBSDCommon(): # A synchronization to prevent conflicts between host group creation # and deletion. - @coordination.synchronized('hbsd-host-{self.conf.hitachi_storage_id}-' - '{connector[host]}') + @coordination.synchronized( + '{self.driver_info[driver_file_prefix]}-host-' + '{self.conf.hitachi_storage_id}-{connector[host]}') def initialize_connection(self, volume, connector): """Initialize connection between the server and the volume.""" targets = { @@ -709,7 +716,7 @@ class HBSDCommon(): if ldev is None: msg = utils.output_log(MSG.INVALID_LDEV_FOR_CONNECTION, volume_id=volume['id']) - raise utils.HBSDError(msg) + self.raise_error(msg) target_lun = self.attach_ldev(volume, ldev, connector, targets) @@ -758,7 +765,8 @@ class HBSDCommon(): # A synchronization to prevent conflicts between host group creation # and deletion. @coordination.synchronized( - 'hbsd-host-%(storage_id)s-%(host)s' % { + '%(prefix)s-host-%(storage_id)s-%(host)s' % { + 'prefix': self.driver_info['driver_file_prefix'], 'storage_id': self.conf.hitachi_storage_id, 'host': connector.get('host'), } @@ -819,3 +827,34 @@ class HBSDCommon(): def delete_group_snapshot(self, group_snapshot, snapshots): raise NotImplementedError() + + def check_opts(self, conf, opts): + """Check if the specified configuration is valid.""" + names = [] + for opt in opts: + if opt.required and not conf.safe_get(opt.name): + msg = utils.output_log(MSG.INVALID_PARAMETER, param=opt.name) + self.raise_error(msg) + names.append(opt.name) + utils.check_opt_value(conf, names) + + def require_target_existed(self, targets): + """Check if the target list includes one or more members.""" + if not targets['list']: + msg = utils.output_log(MSG.NO_CONNECTED_TARGET) + self.raise_error(msg) + + def raise_error(self, msg): + """Raise a VolumeDriverException by driver error message.""" + message = _( + '%(prefix)s error occurred. %(msg)s' % { + 'prefix': self.driver_info['driver_prefix'], + 'msg': msg, + } + ) + raise exception.VolumeDriverException(message) + + def raise_busy(self): + """Raise a VolumeDriverException by driver busy message.""" + message = _(utils.BUSY_MESSAGE) + raise exception.VolumeDriverException(message) diff --git a/cinder/volume/drivers/hitachi/hbsd_fc.py b/cinder/volume/drivers/hitachi/hbsd_fc.py index a5ca0a7874f..9e492e5e65f 100644 --- a/cinder/volume/drivers/hitachi/hbsd_fc.py +++ b/cinder/volume/drivers/hitachi/hbsd_fc.py @@ -14,28 +14,21 @@ # """Fibre channel module for Hitachi HBSD Driver.""" -from oslo_config import cfg +import os + from oslo_utils import excutils from cinder import interface -from cinder.volume import configuration from cinder.volume import driver from cinder.volume.drivers.hitachi import hbsd_common as common +from cinder.volume.drivers.hitachi import hbsd_rest_fc as rest_fc from cinder.volume.drivers.hitachi import hbsd_utils as utils from cinder.volume import volume_utils -FC_VOLUME_OPTS = [ - cfg.BoolOpt( - 'hitachi_zoning_request', - default=False, - help='If True, the driver will configure FC zoning between the server ' - 'and the storage system provided that FC zoning manager is ' - 'enabled.'), -] - MSG = utils.HBSDMsg _DRIVER_INFO = { + 'version': utils.VERSION, 'proto': 'FC', 'hba_id': 'wwpns', 'hba_id_type': 'World Wide Name', @@ -45,13 +38,19 @@ _DRIVER_INFO = { 'volume_backend_name': '%(prefix)sFC' % { 'prefix': utils.DRIVER_PREFIX, }, - 'volume_opts': FC_VOLUME_OPTS, 'volume_type': 'fibre_channel', + 'param_prefix': utils.PARAM_PREFIX, + 'vendor_name': utils.VENDOR_NAME, + 'driver_prefix': utils.DRIVER_PREFIX, + 'driver_file_prefix': utils.DRIVER_FILE_PREFIX, + 'target_prefix': utils.TARGET_PREFIX, + 'hdp_vol_attr': utils.HDP_VOL_ATTR, + 'hdt_vol_attr': utils.HDT_VOL_ATTR, + 'nvol_ldev_type': utils.NVOL_LDEV_TYPE, + 'target_iqn_suffix': utils.TARGET_IQN_SUFFIX, + 'pair_attr': utils.PAIR_ATTR, } -CONF = cfg.CONF -CONF.register_opts(FC_VOLUME_OPTS, group=configuration.SHARED_CONF_GROUP) - @interface.volumedriver class HBSDFCDriver(driver.FibreChannelDriver): @@ -67,13 +66,14 @@ class HBSDFCDriver(driver.FibreChannelDriver): API for communication with the storage backend. 2.1.0 - Add Cinder generic volume groups. 2.2.0 - Add maintenance parameters. + 2.2.1 - Make the parameters name variable for supporting OEM storages. """ - VERSION = common.VERSION + VERSION = utils.VERSION # ThirdPartySystems wiki page - CI_WIKI_NAME = "Hitachi_VSP_CI" + CI_WIKI_NAME = utils.CI_WIKI_NAME def __init__(self, *args, **kwargs): """Initialize instance variables.""" @@ -83,9 +83,12 @@ class HBSDFCDriver(driver.FibreChannelDriver): super(HBSDFCDriver, self).__init__(*args, **kwargs) self.configuration.append_config_values(common.COMMON_VOLUME_OPTS) - self.configuration.append_config_values(FC_VOLUME_OPTS) - self.common = utils.import_object( - self.configuration, _DRIVER_INFO, kwargs.get('db')) + self.configuration.append_config_values(rest_fc.FC_VOLUME_OPTS) + os.environ['LANG'] = 'C' + self.common = self._init_common(self.configuration, kwargs.get('db')) + + def _init_common(self, conf, db): + return rest_fc.HBSDRESTFC(conf, _DRIVER_INFO, db) def check_for_setup_error(self): pass diff --git a/cinder/volume/drivers/hitachi/hbsd_iscsi.py b/cinder/volume/drivers/hitachi/hbsd_iscsi.py index 36a67991c62..610b61666ef 100644 --- a/cinder/volume/drivers/hitachi/hbsd_iscsi.py +++ b/cinder/volume/drivers/hitachi/hbsd_iscsi.py @@ -14,17 +14,21 @@ # """iSCSI module for Hitachi HBSD Driver.""" +import os + from oslo_utils import excutils from cinder import interface from cinder.volume import driver from cinder.volume.drivers.hitachi import hbsd_common as common +from cinder.volume.drivers.hitachi import hbsd_rest_iscsi as rest_iscsi from cinder.volume.drivers.hitachi import hbsd_utils as utils from cinder.volume import volume_utils MSG = utils.HBSDMsg _DRIVER_INFO = { + 'version': utils.VERSION, 'proto': 'iSCSI', 'hba_id': 'initiator', 'hba_id_type': 'iSCSI initiator IQN', @@ -34,8 +38,17 @@ _DRIVER_INFO = { 'volume_backend_name': '%(prefix)siSCSI' % { 'prefix': utils.DRIVER_PREFIX, }, - 'volume_opts': [], 'volume_type': 'iscsi', + 'param_prefix': utils.PARAM_PREFIX, + 'vendor_name': utils.VENDOR_NAME, + 'driver_prefix': utils.DRIVER_PREFIX, + 'driver_file_prefix': utils.DRIVER_FILE_PREFIX, + 'target_prefix': utils.TARGET_PREFIX, + 'hdp_vol_attr': utils.HDP_VOL_ATTR, + 'hdt_vol_attr': utils.HDT_VOL_ATTR, + 'nvol_ldev_type': utils.NVOL_LDEV_TYPE, + 'target_iqn_suffix': utils.TARGET_IQN_SUFFIX, + 'pair_attr': utils.PAIR_ATTR, } @@ -53,13 +66,14 @@ class HBSDISCSIDriver(driver.ISCSIDriver): API for communication with the storage backend. 2.1.0 - Add Cinder generic volume groups. 2.2.0 - Add maintenance parameters. + 2.2.1 - Make the parameters name variable for supporting OEM storages. """ - VERSION = common.VERSION + VERSION = utils.VERSION # ThirdPartySystems wiki page - CI_WIKI_NAME = "Hitachi_VSP_CI" + CI_WIKI_NAME = utils.CI_WIKI_NAME def __init__(self, *args, **kwargs): """Initialize instance variables.""" @@ -69,8 +83,11 @@ class HBSDISCSIDriver(driver.ISCSIDriver): super(HBSDISCSIDriver, self).__init__(*args, **kwargs) self.configuration.append_config_values(common.COMMON_VOLUME_OPTS) - self.common = utils.import_object( - self.configuration, _DRIVER_INFO, kwargs.get('db')) + os.environ['LANG'] = 'C' + self.common = self._init_common(self.configuration, kwargs.get('db')) + + def _init_common(self, conf, db): + return rest_iscsi.HBSDRESTISCSI(conf, _DRIVER_INFO, db) def check_for_setup_error(self): pass diff --git a/cinder/volume/drivers/hitachi/hbsd_rest.py b/cinder/volume/drivers/hitachi/hbsd_rest.py index 9681b8d0cce..21430f5898f 100644 --- a/cinder/volume/drivers/hitachi/hbsd_rest.py +++ b/cinder/volume/drivers/hitachi/hbsd_rest.py @@ -38,12 +38,6 @@ _LUN_TIMEOUT = 50 _LUN_RETRY_INTERVAL = 1 _RESTORE_TIMEOUT = 24 * 60 * 60 _STATE_TRANSITION_TIMEOUT = 15 * 60 -PAIR_ATTR = 'HTI' -_SNAP_MODE = 'A' -_CLONE_MODE = 'C' -_NORMAL_MODE = '-' - -_PERMITTED_TYPES = set(['CVS', 'HDP', 'HDT']) _CHECK_LDEV_MANAGEABILITY_KEYS = ( 'emulationType', 'numOfPorts', 'attributes', 'status') @@ -75,9 +69,6 @@ _STATUS_TABLE = { 'SMPP': SMPP, } -SNAP_NAME = 'HBSD-snap' -CLONE_NAME = 'HBSD-clone' - _SNAP_HASH_SIZE = 8 EX_ENOOBJ = 'EX_ENOOBJ' @@ -202,13 +193,13 @@ LOG = logging.getLogger(__name__) MSG = utils.HBSDMsg -def _is_valid_target(target, target_name, target_ports): +def _is_valid_target(self, target, target_name, target_ports): """Check if the specified target is valid.""" return (target[:utils.PORT_ID_LENGTH] in target_ports and - target_name.startswith(utils.TARGET_PREFIX)) + target_name.startswith(self.driver_info['target_prefix'])) -def _check_ldev_manageability(ldev_info, ldev, existing_ref): +def _check_ldev_manageability(self, ldev_info, ldev, existing_ref): """Check if the LDEV meets the criteria for being managed.""" if ldev_info['status'] != NORMAL_STS: msg = utils.output_log(MSG.INVALID_LDEV_FOR_MANAGE) @@ -216,9 +207,12 @@ def _check_ldev_manageability(ldev_info, ldev, existing_ref): existing_ref=existing_ref, reason=msg) attributes = set(ldev_info['attributes']) if (not ldev_info['emulationType'].startswith('OPEN-V') or - len(attributes) < 2 or not attributes.issubset(_PERMITTED_TYPES)): + len(attributes) < 2 or + not attributes.issubset( + set(['CVS', self.driver_info['hdp_vol_attr'], + self.driver_info['hdt_vol_attr']]))): msg = utils.output_log(MSG.INVALID_LDEV_ATTR_FOR_MANAGE, ldev=ldev, - ldevtype=utils.NVOL_LDEV_TYPE) + ldevtype=self.driver_info['nvol_ldev_type']) raise exception.ManageExistingInvalidReference( existing_ref=existing_ref, reason=msg) if ldev_info['numOfPorts']: @@ -262,6 +256,7 @@ class HBSDREST(common.HBSDCommon): self.conf.hitachi_storage_id, self.conf.san_login, self.conf.san_password, + self.driver_info['driver_prefix'], tcp_keepalive=self.conf.hitachi_rest_tcp_keepalive, verify=verify) self.client.login() @@ -343,12 +338,12 @@ class HBSDREST(common.HBSDCommon): if not loop.start(interval=interval).wait(): msg = utils.output_log( MSG.PAIR_STATUS_WAIT_TIMEOUT, svol=ldev) - raise utils.HBSDError(msg) + self.raise_error(msg) def _create_snap_pair(self, pvol, svol): """Create a snapshot copy pair on the storage.""" snapshot_name = '%(prefix)s%(svol)s' % { - 'prefix': SNAP_NAME, + 'prefix': self.driver_info['driver_prefix'] + '-snap', 'svol': svol % _SNAP_HASH_SIZE, } try: @@ -360,13 +355,14 @@ class HBSDREST(common.HBSDCommon): "canCascade": True, "isDataReductionForceCopy": True} self.client.add_snapshot(body) - except utils.HBSDError as ex: + except exception.VolumeDriverException as ex: if (utils.safe_get_err_code(ex.kwargs.get('errobj')) == rest_api.INVALID_SNAPSHOT_POOL and not self.conf.hitachi_snap_pool): msg = utils.output_log( - MSG.INVALID_PARAMETER, param='hitachi_snap_pool') - raise utils.HBSDError(msg) + MSG.INVALID_PARAMETER, + param=self.driver_info['param_prefix'] + '_snap_pool') + self.raise_error(msg) else: raise try: @@ -375,14 +371,14 @@ class HBSDREST(common.HBSDCommon): with excutils.save_and_reraise_exception(): try: self._delete_pair_from_storage(pvol, svol) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log( MSG.DELETE_PAIR_FAILED, pvol=pvol, svol=svol) def _create_clone_pair(self, pvol, svol): """Create a clone copy pair on the storage.""" snapshot_name = '%(prefix)s%(svol)s' % { - 'prefix': CLONE_NAME, + 'prefix': self.driver_info['driver_prefix'] + '-clone', 'svol': svol % _SNAP_HASH_SIZE, } try: @@ -401,13 +397,14 @@ class HBSDREST(common.HBSDCommon): "copySpeed": pace, "isDataReductionForceCopy": True} self.client.add_snapshot(body) - except utils.HBSDError as ex: + except exception.VolumeDriverException as ex: if (utils.safe_get_err_code(ex.kwargs.get('errobj')) == rest_api.INVALID_SNAPSHOT_POOL and not self.conf.hitachi_snap_pool): msg = utils.output_log( - MSG.INVALID_PARAMETER, param='hitachi_snap_pool') - raise utils.HBSDError(msg) + MSG.INVALID_PARAMETER, + param=self.driver_info['param_prefix'] + '_snap_pool') + self.raise_error(msg) else: raise try: @@ -416,7 +413,7 @@ class HBSDREST(common.HBSDCommon): with excutils.save_and_reraise_exception(): try: self._delete_pair_from_storage(pvol, svol) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log( MSG.DELETE_PAIR_FAILED, pvol=pvol, svol=svol) @@ -444,7 +441,8 @@ class HBSDREST(common.HBSDCommon): """Raise True if the LDEV is no longer in a copy pair.""" ldev_info = self.get_ldev_info(['status', 'attributes'], ldev) if (ldev_info['status'] != NORMAL_STS or - PAIR_ATTR not in ldev_info['attributes']): + self.driver_info['pair_attr'] not in + ldev_info['attributes']): raise loopingcall.LoopingCallDone() if utils.timed_out( start_time, _STATE_TRANSITION_TIMEOUT): @@ -455,7 +453,7 @@ class HBSDREST(common.HBSDCommon): if not loop.start(interval=interval).wait(): msg = utils.output_log( MSG.PAIR_STATUS_WAIT_TIMEOUT, svol=ldev) - raise utils.HBSDError(msg) + self.raise_error(msg) def _delete_pair_from_storage(self, pvol, svol): """Disconnect the volume pair that consists of the specified LDEVs.""" @@ -479,23 +477,23 @@ class HBSDREST(common.HBSDCommon): # If the pair status does not satisfy the execution condition, if not (svol_info['is_psus'] or _STATUS_TABLE.get(svol_info['status']) == SMPP): - msg = utils.output_log( + utils.output_log( MSG.UNABLE_TO_DELETE_PAIR, pvol=pvol, svol=svol_info['ldev']) - raise utils.HBSDBusy(msg) + self.raise_busy() self._delete_pair_from_storage(pvol, svol_info['ldev']) def check_param(self): """Check parameter values and consistency among them.""" super(HBSDREST, self).check_param() - utils.check_opts(self.conf, REST_VOLUME_OPTS) - utils.check_opts(self.conf, san.san_opts) + self.check_opts(self.conf, REST_VOLUME_OPTS) + self.check_opts(self.conf, san.san_opts) LOG.debug( 'Setting ldev_range: %s', self.storage_info['ldev_range']) for opt in _REQUIRED_REST_OPTS: if not self.conf.safe_get(opt): msg = utils.output_log(MSG.INVALID_PARAMETER, param=opt) - raise utils.HBSDError(msg) + self.raise_error(msg) if not self.conf.safe_get('san_api_port'): self.conf.san_api_port = _REST_DEFAULT_PORT @@ -552,7 +550,7 @@ class HBSDREST(common.HBSDCommon): lun2 = self._run_add_lun(ldev, port, gid, lun=lun) if lun2 is not None: targets['lun'][port] = True - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log(MSG.MAP_LDEV_FAILED, ldev=ldev, port=port, id=gid, lun=lun) return lun @@ -565,7 +563,7 @@ class HBSDREST(common.HBSDCommon): self.conf.hitachi_group_create): self.create_mapping_targets(targets, connector) - utils.require_target_existed(targets) + self.require_target_existed(targets) targets['list'].sort() for port in target_ports: @@ -578,7 +576,7 @@ class HBSDREST(common.HBSDCommon): if not ldev_info['ports']: return for port_info in ldev_info['ports']: - if _is_valid_target(port_info['portId'], + if _is_valid_target(self, port_info['portId'], port_info['hostGroupName'], target_ports): targets['list'].append(port_info) @@ -631,7 +629,7 @@ class HBSDREST(common.HBSDCommon): try: self.client.delete_host_grp(port, gid) result = 0 - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log(MSG.DELETE_TARGET_FAILED, port=port, id=gid) else: LOG.debug( @@ -701,7 +699,7 @@ class HBSDREST(common.HBSDCommon): if 'errorSource' in result: msg = utils.output_log(MSG.POOL_NOT_FOUND, pool=self.storage_info['pool_id']) - raise utils.HBSDError(msg) + self.raise_error(msg) tp_cap = result['totalPoolCapacity'] / units.Ki ta_cap = result['availableVolumeCapacity'] / units.Ki @@ -715,7 +713,7 @@ class HBSDREST(common.HBSDCommon): ldev = utils.get_ldev(volume) try: self.client.discard_zero_page(ldev) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log(MSG.DISCARD_ZERO_PAGE_FAILED, ldev=ldev) def _get_copy_pair_info(self, ldev): @@ -747,7 +745,7 @@ class HBSDREST(common.HBSDCommon): pair_info = {} ldev_info = self.get_ldev_info(['status', 'attributes'], ldev) if (ldev_info['status'] != NORMAL_STS or - PAIR_ATTR not in ldev_info['attributes']): + self.driver_info['pair_attr'] not in ldev_info['attributes']): return None pvol, svol_info = self._get_copy_pair_info(ldev) @@ -791,7 +789,7 @@ class HBSDREST(common.HBSDCommon): """Check if the LDEV meets the criteria for being managed.""" ldev_info = self.get_ldev_info( _CHECK_LDEV_MANAGEABILITY_KEYS, ldev) - _check_ldev_manageability(ldev_info, ldev, existing_ref) + _check_ldev_manageability(self, ldev_info, ldev, existing_ref) def get_ldev_size_in_gigabyte(self, ldev, existing_ref): """Return the size[GB] of the specified LDEV.""" @@ -819,7 +817,7 @@ class HBSDREST(common.HBSDCommon): if self.storage_info['pool_id'] is None: msg = utils.output_log( MSG.POOL_NOT_FOUND, pool=self.conf.hitachi_pool) - raise utils.HBSDError(msg) + self.raise_error(msg) snap_pool = self.conf.hitachi_snap_pool if snap_pool is not None: @@ -831,7 +829,7 @@ class HBSDREST(common.HBSDCommon): if self.storage_info['snap_pool_id'] is None: msg = utils.output_log(MSG.POOL_NOT_FOUND, pool=self.conf.hitachi_snap_pool) - raise utils.HBSDError(msg) + self.raise_error(msg) else: self.storage_info['snap_pool_id'] = self.storage_info['pool_id'] @@ -883,7 +881,7 @@ class HBSDREST(common.HBSDCommon): """Check if the volume have the pair of the snapshot.""" ldev_info = self.get_ldev_info(['status', 'attributes'], svol) if (ldev_info['status'] != NORMAL_STS or - PAIR_ATTR not in ldev_info['attributes']): + self.driver_info['pair_attr'] not in ldev_info['attributes']): return False params_s = {"svolLdevId": svol} result = self.client.get_snapshots(params_s) @@ -908,7 +906,7 @@ class HBSDREST(common.HBSDCommon): else: self.delete_volume(obj) obj_update['status'] = 'deleted' - except (utils.HBSDError, exception.VolumeIsBusy, + except (exception.VolumeDriverException, exception.VolumeIsBusy, exception.SnapshotIsBusy) as exc: obj_update['status'] = 'available' if isinstance( exc, (exception.VolumeIsBusy, @@ -954,7 +952,7 @@ class HBSDREST(common.HBSDCommon): MSG.INVALID_LDEV_FOR_VOLUME_COPY, type='snapshot' if from_snapshot else 'volume', id=src.id) - raise utils.HBSDError(msg) + self.raise_error(msg) volume_model_update.update( self.create_volume_from_snapshot(volume, src) if from_snapshot else self.create_cloned_volume(volume, @@ -984,13 +982,13 @@ class HBSDREST(common.HBSDCommon): if ldev is not None: new_ldevs.append(ldev) if not is_success: - raise utils.HBSDError(msg) + self.raise_error(msg) except Exception: with excutils.save_and_reraise_exception(): for new_ldev in new_ldevs: try: self.delete_ldev(new_ldev) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log(MSG.DELETE_LDEV_FAILED, ldev=new_ldev) return None, volumes_model_update @@ -1003,7 +1001,7 @@ class HBSDREST(common.HBSDCommon): volume_id=volume.id, group='consistency group', group_id=group.id) - raise utils.HBSDError(msg) + self.raise_error(msg) return None, None, None def _create_non_cgsnapshot(self, group_snapshot, snapshots): @@ -1044,7 +1042,7 @@ class HBSDREST(common.HBSDCommon): now = timeutils.utcnow() strnow = now.strftime("%y%m%d%H%M%S%f") ctg_name = '%(prefix)sC%(ldev)s%(time)s' % { - 'prefix': utils.DRIVER_PREFIX, + 'prefix': self.driver_info['driver_prefix'], 'ldev': "{0:06X}".format(ldev), 'time': strnow[:len(strnow) - 3], } @@ -1054,7 +1052,7 @@ class HBSDREST(common.HBSDCommon): for pair in pairs: try: self._delete_pair_from_storage(pair['pvol'], pair['svol']) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log(MSG.DELETE_PAIR_FAILED, pvol=pair['pvol'], svol=pair['svol']) @@ -1073,19 +1071,21 @@ class HBSDREST(common.HBSDCommon): "canCascade": True, "isDataReductionForceCopy": True} self.client.add_snapshot(body) - except utils.HBSDError as ex: + except exception.VolumeDriverException as ex: if ((utils.safe_get_err_code(ex.kwargs.get('errobj')) == _MAX_CTG_COUNT_EXCEEDED_ADD_SNAPSHOT) or (utils.safe_get_err_code(ex.kwargs.get('errobj')) == _MAX_PAIR_COUNT_IN_CTG_EXCEEDED_ADD_SNAPSHOT)): msg = utils.output_log(MSG.FAILED_CREATE_CTG_SNAPSHOT) - raise utils.HBSDError(msg) + self.raise_error(msg) elif (utils.safe_get_err_code(ex.kwargs.get('errobj')) == rest_api.INVALID_SNAPSHOT_POOL and not self.conf.hitachi_snap_pool): msg = utils.output_log( - MSG.INVALID_PARAMETER, param='hitachi_snap_pool') - raise utils.HBSDError(msg) + MSG.INVALID_PARAMETER, + param=self.driver_info['param_prefix'] + + '_snap_pool') + self.raise_error(msg) raise self._wait_copy_pair_status(pair['svol'], PAIR) self.client.split_snapshotgroup(snapshotgroup_name) @@ -1108,7 +1108,7 @@ class HBSDREST(common.HBSDCommon): msg = utils.output_log( MSG.INVALID_LDEV_FOR_VOLUME_COPY, type='volume', id=snapshot.volume_id) - raise utils.HBSDError(msg) + self.raise_error(msg) size = snapshot.volume_size pair['svol'] = self.create_ldev(size) except Exception as exc: @@ -1122,7 +1122,7 @@ class HBSDREST(common.HBSDCommon): msg = utils.output_log( MSG.INVALID_LDEV_FOR_VOLUME_COPY, type='volume', id=snapshot.volume_id) - raise utils.HBSDError(msg) + self.raise_error(msg) for snapshot in snapshots: loop = loopingcall.FixedIntervalLoopingCall( _create_cgsnapshot_volume, snapshot) @@ -1136,14 +1136,14 @@ class HBSDREST(common.HBSDCommon): msg = pair['msg'] pairs.append(pair) if not is_success: - raise utils.HBSDError(msg) + self.raise_error(msg) self._create_ctg_snap_pair(pairs) except Exception: for pair in pairs: if 'svol' in pair and pair['svol'] is not None: try: self.delete_ldev(pair['svol']) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log( MSG.DELETE_LDEV_FAILED, ldev=pair['svol']) model_update = {'status': fields.GroupSnapshotStatus.ERROR} @@ -1169,26 +1169,41 @@ class HBSDREST(common.HBSDCommon): def init_timer_values(self): global _LUN_TIMEOUT, _LUN_RETRY_INTERVAL global _RESTORE_TIMEOUT, _STATE_TRANSITION_TIMEOUT - _LUN_TIMEOUT = self.conf.hitachi_lun_timeout - _LUN_RETRY_INTERVAL = self.conf.hitachi_lun_retry_interval - _RESTORE_TIMEOUT = self.conf.hitachi_restore_timeout - _STATE_TRANSITION_TIMEOUT = self.conf.hitachi_state_transition_timeout - rest_api._LOCK_TIMEOUT = self.conf.hitachi_lock_timeout - rest_api._REST_TIMEOUT = self.conf.hitachi_rest_timeout - rest_api._EXTEND_TIMEOUT = self.conf.hitachi_extend_timeout - rest_api._EXEC_RETRY_INTERVAL = self.conf.hitachi_exec_retry_interval - rest_api._DEFAULT_CONNECT_TIMEOUT = ( - self.conf.hitachi_rest_connect_timeout) - rest_api._JOB_API_RESPONSE_TIMEOUT = ( - self.conf.hitachi_rest_job_api_response_timeout) - rest_api._GET_API_RESPONSE_TIMEOUT = ( - self.conf.hitachi_rest_get_api_response_timeout) - rest_api._REST_SERVER_BUSY_TIMEOUT = ( - self.conf.hitachi_rest_server_busy_timeout) - rest_api._KEEP_SESSION_LOOP_INTERVAL = ( - self.conf.hitachi_rest_keep_session_loop_interval) - rest_api._ANOTHER_LDEV_MAPPED_RETRY_TIMEOUT = ( - self.conf.hitachi_rest_another_ldev_mapped_retry_timeout) - rest_api._TCP_KEEPIDLE = self.conf.hitachi_rest_tcp_keepidle - rest_api._TCP_KEEPINTVL = self.conf.hitachi_rest_tcp_keepintvl - rest_api._TCP_KEEPCNT = self.conf.hitachi_rest_tcp_keepcnt + _LUN_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_lun_timeout') + _LUN_RETRY_INTERVAL = self.conf.safe_get( + self.driver_info['param_prefix'] + '_lun_retry_interval') + _RESTORE_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_restore_timeout') + _STATE_TRANSITION_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_state_transition_timeout') + rest_api._LOCK_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_lock_timeout') + rest_api._REST_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_rest_timeout') + rest_api._EXTEND_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_extend_timeout') + rest_api._EXEC_RETRY_INTERVAL = self.conf.safe_get( + self.driver_info['param_prefix'] + '_exec_retry_interval') + rest_api._DEFAULT_CONNECT_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_rest_connect_timeout') + rest_api._JOB_API_RESPONSE_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + + '_rest_job_api_response_timeout') + rest_api._GET_API_RESPONSE_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + + '_rest_get_api_response_timeout') + rest_api._REST_SERVER_BUSY_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_rest_server_busy_timeout') + rest_api._KEEP_SESSION_LOOP_INTERVAL = self.conf.safe_get( + self.driver_info['param_prefix'] + + '_rest_keep_session_loop_interval') + rest_api._ANOTHER_LDEV_MAPPED_RETRY_TIMEOUT = self.conf.safe_get( + self.driver_info['param_prefix'] + + '_rest_another_ldev_mapped_retry_timeout') + rest_api._TCP_KEEPIDLE = self.conf.safe_get( + self.driver_info['param_prefix'] + '_rest_tcp_keepidle') + rest_api._TCP_KEEPINTVL = self.conf.safe_get( + self.driver_info['param_prefix'] + '_rest_tcp_keepintvl') + rest_api._TCP_KEEPCNT = self.conf.safe_get( + self.driver_info['param_prefix'] + '_rest_tcp_keepcnt') diff --git a/cinder/volume/drivers/hitachi/hbsd_rest_api.py b/cinder/volume/drivers/hitachi/hbsd_rest_api.py index ab160998cf8..0665c476089 100644 --- a/cinder/volume/drivers/hitachi/hbsd_rest_api.py +++ b/cinder/volume/drivers/hitachi/hbsd_rest_api.py @@ -29,6 +29,8 @@ from requests.adapters import HTTPAdapter from requests.packages.urllib3.connection import HTTPConnection from requests.packages.urllib3.poolmanager import PoolManager +from cinder import exception +from cinder.i18n import _ from cinder.volume.drivers.hitachi import hbsd_utils as utils from cinder.volume import volume_utils @@ -217,7 +219,7 @@ class ResponseData(dict): class RestApiClient(): def __init__(self, ip_addr, ip_port, storage_device_id, - user_id, user_pass, tcp_keepalive=False, + user_id, user_pass, driver_prefix, tcp_keepalive=False, verify=False, connect_timeout=_DEFAULT_CONNECT_TIMEOUT): """Initialize instance variables.""" self.ip_addr = ip_addr @@ -244,6 +246,7 @@ class RestApiClient(): } self.headers = {"content-type": "application/json", "accept": "application/json"} + self.driver_prefix = driver_prefix class Session(requests.auth.AuthBase): @@ -312,7 +315,13 @@ class RestApiClient(): MSG.REST_SERVER_CONNECT_FAILED, exception=type(e), message=e, method=method, url=url, params=params, body=body) - raise utils.HBSDError(msg) + message = _( + '%(prefix)s error occurred. %(msg)s' % { + 'prefix': self.driver_prefix, + 'msg': msg, + } + ) + raise exception.VolumeDriverException(message) response = ResponseData(rsp) if (response['status_code'] == httpclient.INTERNAL_SERVER_ERROR and @@ -348,7 +357,14 @@ class RestApiClient(): params=params, body=body, **response.get_errobj()) if kwargs['do_raise']: - raise utils.HBSDError(msg, errobj=errobj) + message = _( + '%(prefix)s error occurred. %(msg)s' % { + 'prefix': self.driver_prefix, + 'msg': msg, + } + ) + raise exception.VolumeDriverException( + message, errobj=errobj) return False, rsp_body, errobj else: LOG.debug("The resource group to which the operation object ", @@ -402,7 +418,14 @@ class RestApiClient(): method=method, url=url, params=params, body=body) if kwargs['do_raise']: - raise utils.HBSDError(msg, errobj=errobj) + message = _( + '%(prefix)s error occurred. %(msg)s' % { + 'prefix': self.driver_prefix, + 'msg': msg, + } + ) + raise exception.VolumeDriverException( + message, errobj=errobj) return False, rsp_body, errobj if errobj: @@ -425,7 +448,14 @@ class RestApiClient(): method=method, url=url, params=params, body=body) if kwargs['do_raise']: - raise utils.HBSDError(msg, errobj=errobj) + message = _( + '%(prefix)s error occurred. %(msg)s' % { + 'prefix': self.driver_prefix, + 'msg': msg, + } + ) + raise exception.VolumeDriverException( + message, errobj=errobj) return retry, rsp_body, errobj def set_my_session(self, session): @@ -469,7 +499,7 @@ class RestApiClient(): if session is not None: self.get_session(session.id, no_retry=True, no_log=True) has_session = True - except utils.HBSDError as ex: + except exception.VolumeDriverException as ex: LOG.debug('Failed to get session info: %s', ex) return has_session diff --git a/cinder/volume/drivers/hitachi/hbsd_rest_fc.py b/cinder/volume/drivers/hitachi/hbsd_rest_fc.py index 2685dba2a6b..36fd262330e 100644 --- a/cinder/volume/drivers/hitachi/hbsd_rest_fc.py +++ b/cinder/volume/drivers/hitachi/hbsd_rest_fc.py @@ -14,17 +14,32 @@ # """REST interface fibre channel module for Hitachi HBSD Driver.""" +from oslo_config import cfg from oslo_log import log as logging +from cinder import exception +from cinder.volume import configuration from cinder.volume.drivers.hitachi import hbsd_rest as rest from cinder.volume.drivers.hitachi import hbsd_utils as utils from cinder.zonemanager import utils as fczm_utils +FC_VOLUME_OPTS = [ + cfg.BoolOpt( + 'hitachi_zoning_request', + default=False, + help='If True, the driver will configure FC zoning between the server ' + 'and the storage system provided that FC zoning manager is ' + 'enabled.'), +] + _FC_HMO_DISABLE_IO = 91 LOG = logging.getLogger(__name__) MSG = utils.HBSDMsg +CONF = cfg.CONF +CONF.register_opts(FC_VOLUME_OPTS, group=configuration.SHARED_CONF_GROUP) + class HBSDRESTFC(rest.HBSDREST): """REST interface fibre channel class for Hitachi HBSD Driver.""" @@ -89,11 +104,16 @@ class HBSDRESTFC(rest.HBSDREST): utils.output_log(MSG.SET_CONFIG_VALUE, object='port-wwn list', value=self.storage_info['wwns']) + def check_param(self): + """Check parameter values and consistency among them.""" + super(HBSDRESTFC, self).check_param() + self.check_opts(self.conf, FC_VOLUME_OPTS) + def create_target_to_storage(self, port, connector, hba_ids): """Create a host group on the specified port.""" wwpns = self.get_hba_ids_from_connector(connector) target_name = '%(prefix)s-%(wwpns)s' % { - 'prefix': utils.DRIVER_PREFIX, + 'prefix': self.driver_info['driver_prefix'], 'wwpns': min(wwpns), } try: @@ -116,13 +136,13 @@ class HBSDRESTFC(rest.HBSDREST): try: self.client.add_hba_wwn(port, gid, wwn, no_log=True) registered_wwns.append(wwn) - except utils.HBSDError: + except exception.VolumeDriverException: utils.output_log(MSG.ADD_HBA_WWN_FAILED, port=port, gid=gid, wwn=wwn) if not registered_wwns: msg = utils.output_log(MSG.NO_HBA_WWN_ADDED_TO_HOST_GRP, port=port, gid=gid) - raise utils.HBSDError(msg) + self.raise_error(msg) def set_target_mode(self, port, gid): """Configure the host group to meet the environment.""" @@ -193,14 +213,14 @@ class HBSDRESTFC(rest.HBSDREST): wwpns = self.get_hba_ids_from_connector(connector) target_names = [ '%(prefix)s-%(wwpns)s' % { - 'prefix': utils.DRIVER_PREFIX, + 'prefix': self.driver_info['driver_prefix'], 'wwpns': min(wwpns), } ] if 'ip' in connector: target_names.append( '%(prefix)s-%(ip)s' % { - 'prefix': utils.DRIVER_PREFIX, + 'prefix': self.driver_info['driver_prefix'], 'ip': connector['ip'], } ) diff --git a/cinder/volume/drivers/hitachi/hbsd_rest_iscsi.py b/cinder/volume/drivers/hitachi/hbsd_rest_iscsi.py index c048c7d304f..3236fe938c7 100644 --- a/cinder/volume/drivers/hitachi/hbsd_rest_iscsi.py +++ b/cinder/volume/drivers/hitachi/hbsd_rest_iscsi.py @@ -91,14 +91,14 @@ class HBSDRESTISCSI(rest.HBSDREST): def create_target_to_storage(self, port, connector, hba_ids): """Create an iSCSI target on the specified port.""" target_name = '%(prefix)s-%(ip)s' % { - 'prefix': utils.DRIVER_PREFIX, + 'prefix': self.driver_info['driver_prefix'], 'ip': connector['ip'], } body = {'portId': port, 'hostGroupName': target_name} if hba_ids: body['iscsiName'] = '%(id)s%(suffix)s' % { 'id': hba_ids, - 'suffix': utils.TARGET_IQN_SUFFIX, + 'suffix': self.driver_info['target_iqn_suffix'], } try: gid = self.client.add_host_grp(body, no_log=True) @@ -184,7 +184,7 @@ class HBSDRESTISCSI(rest.HBSDREST): targets['info'][port] = False if 'ip' in connector: target_name = '%(prefix)s-%(ip)s' % { - 'prefix': utils.DRIVER_PREFIX, + 'prefix': self.driver_info['driver_prefix'], 'ip': connector['ip'], } if self._set_target_info_by_name( @@ -215,7 +215,7 @@ class HBSDRESTISCSI(rest.HBSDREST): if not iqn: msg = utils.output_log(MSG.RESOURCE_NOT_FOUND, resource='Target IQN') - raise utils.HBSDError(msg) + self.raise_error(msg) targets['iqns'][target] = iqn LOG.debug( 'Found target iqn of host group. (port: %(port)s, ' diff --git a/cinder/volume/drivers/hitachi/hbsd_utils.py b/cinder/volume/drivers/hitachi/hbsd_utils.py index 212996e3a12..76009c6efd9 100644 --- a/cinder/volume/drivers/hitachi/hbsd_utils.py +++ b/cinder/volume/drivers/hitachi/hbsd_utils.py @@ -16,34 +16,31 @@ import enum import logging as base_logging -import os from oslo_config import cfg from oslo_log import log as logging from oslo_utils import excutils -from oslo_utils import importutils from oslo_utils import timeutils from oslo_utils import units from cinder import exception -from cinder.i18n import _ - -_DRIVER_DIR = 'cinder.volume.drivers.hitachi' - -_DRIVERS = { - 'REST': { - 'FC': 'hbsd_rest_fc.HBSDRESTFC', - 'iSCSI': 'hbsd_rest_iscsi.HBSDRESTISCSI', - }, -} +VERSION = '2.2.1' +CI_WIKI_NAME = 'Hitachi_VSP_CI' +PARAM_PREFIX = 'hitachi' +VENDOR_NAME = 'Hitachi' DRIVER_PREFIX = 'HBSD' +DRIVER_FILE_PREFIX = 'hbsd' TARGET_PREFIX = 'HBSD-' +HDP_VOL_ATTR = 'HDP' +HDT_VOL_ATTR = 'HDT' +NVOL_LDEV_TYPE = 'DP-VOL' TARGET_IQN_SUFFIX = '.hbsd-target' +PAIR_ATTR = 'HTI' + GIGABYTE_PER_BLOCK_SIZE = units.Gi / 512 NORMAL_LDEV_TYPE = 'Normal' -NVOL_LDEV_TYPE = 'DP-VOL' INFO_SUFFIX = 'I' WARNING_SUFFIX = 'W' @@ -51,13 +48,7 @@ ERROR_SUFFIX = 'E' PORT_ID_LENGTH = 5 - -class HBSDError(exception.VolumeDriverException): - message = _("HBSD error occurred. %(message)s") - - -class HBSDBusy(HBSDError): - message = _("Device or resource is busy.") +BUSY_MESSAGE = "Device or resource is busy." @enum.unique @@ -464,18 +455,6 @@ def timed_out(start_time, timeout): return timeutils.is_older_than(start_time, timeout) -def import_object(conf, driver_info, db): - """Import a class and return an instance of it.""" - os.environ['LANG'] = 'C' - cli = _DRIVERS.get('REST') - return importutils.import_object( - '%(dir)s.%(proto)s' % { - 'dir': _DRIVER_DIR, - 'proto': cli[driver_info['proto']], - }, - conf, driver_info, db) - - def check_opt_value(conf, names): """Check if the parameter names and values are valid.""" for name in names: @@ -486,24 +465,6 @@ def check_opt_value(conf, names): output_log(MSG.INVALID_PARAMETER, param=name) -def check_opts(conf, opts): - """Check if the specified configuration is valid.""" - names = [] - for opt in opts: - if opt.required and not conf.safe_get(opt.name): - msg = output_log(MSG.INVALID_PARAMETER, param=opt.name) - raise HBSDError(msg) - names.append(opt.name) - check_opt_value(conf, names) - - -def require_target_existed(targets): - """Check if the target list includes one or more members.""" - if not targets['list']: - msg = output_log(MSG.NO_CONNECTED_TARGET) - raise HBSDError(msg) - - def build_initiator_target_map(connector, target_wwns, lookup_service): """Return a dictionary mapping server-wwns and lists of storage-wwns.""" init_targ_map = {}