Hitachi: bugfix and refactoring for add maintenance parameters

This patch is bugfixing and refactoring for the following patch:
https://review.opendev.org/c/openstack/cinder/+/786873

Fixing:
- Adding get_driver_options(), to hbsd_fc.py/hbsd_iscsi.py, which was
 commented in https://review.opendev.org/c/openstack/cinder/+/815614/
- Fixing help massages by commented in hbsd_rest.py
- Fixing error messages for the parameters "hitachi_target_ports" and
 "hitachi_compute_target_ports" to support OEM driver code
 in hbsd_common.py

Refactoring:
- Fixing to not change ALL_CAPS variables and to use config values
 directly by commented in hbsd_rest.py

Change-Id: Id0a4ff9d6a1846a714f23c05c607a8809470978d
This commit is contained in:
Atsushi Kawai 2022-03-04 01:50:22 +00:00
parent b49fb59a6b
commit 11d26b9f59
7 changed files with 113 additions and 92 deletions

View File

@ -37,6 +37,7 @@ 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_rest_fc
from cinder.volume import volume_types
from cinder.volume import volume_utils
from cinder.zonemanager import utils as fczm_utils
@ -1106,3 +1107,12 @@ class HBSDRESTFCDriverTest(test.TestCase):
[{'id': TEST_SNAPSHOT[0]['id'], 'status': 'deleted'}]
)
self.assertTupleEqual(actual, ret)
@mock.patch.object(hbsd_fc.HBSDFCDriver, "_get_oslo_driver_opts")
def test_get_driver_options(self, _get_oslo_driver_opts):
_get_oslo_driver_opts.return_value = []
ret = self.driver.get_driver_options()
actual = (hbsd_common.COMMON_VOLUME_OPTS +
hbsd_rest.REST_VOLUME_OPTS +
hbsd_rest_fc.FC_VOLUME_OPTS)
self.assertEqual(actual, ret)

View File

@ -912,3 +912,11 @@ class HBSDRESTISCSIDriverTest(test.TestCase):
[{'id': TEST_SNAPSHOT[0]['id'], 'status': 'deleted'}]
)
self.assertTupleEqual(actual, ret)
@mock.patch.object(hbsd_iscsi.HBSDISCSIDriver, "_get_oslo_driver_opts")
def test_get_driver_options(self, _get_oslo_driver_opts):
_get_oslo_driver_opts.return_value = []
ret = self.driver.get_driver_options()
actual = (hbsd_common.COMMON_VOLUME_OPTS +
hbsd_rest.REST_VOLUME_OPTS)
self.assertEqual(actual, ret)

View File

@ -490,15 +490,15 @@ class HBSDCommon():
not self.conf.hitachi_compute_target_ports):
msg = utils.output_log(
MSG.INVALID_PARAMETER,
param='hitachi_target_ports or '
'hitachi_compute_target_ports')
param=self.driver_info['param_prefix'] + '_target_ports or ' +
self.driver_info['param_prefix'] + '_compute_target_ports')
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')
param=self.driver_info['param_prefix'] + '_group_delete or '
+ self.driver_info['param_prefix'] + '_group_create')
self.raise_error(msg)
for opt in self._required_common_opts:
if not self.conf.safe_get(opt):

View File

@ -21,6 +21,7 @@ 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 as rest
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
@ -90,6 +91,18 @@ class HBSDFCDriver(driver.FibreChannelDriver):
def _init_common(self, conf, db):
return rest_fc.HBSDRESTFC(conf, _DRIVER_INFO, db)
@staticmethod
def get_driver_options():
additional_opts = HBSDFCDriver._get_oslo_driver_opts(
*(common._INHERITED_VOLUME_OPTS +
rest._REQUIRED_REST_OPTS +
['driver_ssl_cert_verify', 'driver_ssl_cert_path',
'san_api_port', ]))
return (common.COMMON_VOLUME_OPTS +
rest.REST_VOLUME_OPTS +
rest_fc.FC_VOLUME_OPTS +
additional_opts)
def check_for_setup_error(self):
pass

View File

@ -21,6 +21,7 @@ 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 as rest
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
@ -89,6 +90,17 @@ class HBSDISCSIDriver(driver.ISCSIDriver):
def _init_common(self, conf, db):
return rest_iscsi.HBSDRESTISCSI(conf, _DRIVER_INFO, db)
@staticmethod
def get_driver_options():
additional_opts = HBSDISCSIDriver._get_oslo_driver_opts(
*(common._INHERITED_VOLUME_OPTS +
rest._REQUIRED_REST_OPTS +
['driver_ssl_cert_verify', 'driver_ssl_cert_path',
'san_api_port', ]))
return (common.COMMON_VOLUME_OPTS +
rest.REST_VOLUME_OPTS +
additional_opts)
def check_for_setup_error(self):
pass

View File

@ -17,6 +17,7 @@
from collections import defaultdict
from oslo_config import cfg
from oslo_config import types
from oslo_log import log as logging
from oslo_service import loopingcall
from oslo_utils import excutils
@ -89,9 +90,9 @@ REST_VOLUME_OPTS = [
cfg.BoolOpt(
'hitachi_rest_disable_io_wait',
default=True,
help='It may take some time to detach volume after I/O. '
'This option will allow detaching volume to complete '
'immediately.'),
help='This option will allow detaching volume immediately. '
'If set False, storage may take few minutes to detach volume '
'after I/O.'),
cfg.BoolOpt(
'hitachi_rest_tcp_keepalive',
default=True,
@ -103,11 +104,13 @@ REST_VOLUME_OPTS = [
cfg.IntOpt(
'hitachi_lun_timeout',
default=_LUN_TIMEOUT,
help='Maximum wait time in seconds for adding a LUN to complete.'),
help='Maximum wait time in seconds for adding a LUN mapping to '
'the server.'),
cfg.IntOpt(
'hitachi_lun_retry_interval',
default=_LUN_RETRY_INTERVAL,
help='Retry interval in seconds for REST API adding a LUN.'),
help='Retry interval in seconds for REST API adding a LUN mapping to '
'the server.'),
cfg.IntOpt(
'hitachi_restore_timeout',
default=_RESTORE_TIMEOUT,
@ -121,12 +124,12 @@ REST_VOLUME_OPTS = [
cfg.IntOpt(
'hitachi_lock_timeout',
default=rest_api._LOCK_TIMEOUT,
help='Maximum wait time in seconds for a storage unlocked.'),
help='Maximum wait time in seconds for storage to be logined or '
'unlocked.'),
cfg.IntOpt(
'hitachi_rest_timeout',
default=rest_api._REST_TIMEOUT,
help='Maximum wait time in seconds for REST API execution to '
'complete.'),
help='Maximum wait time in seconds for each REST API request.'),
cfg.IntOpt(
'hitachi_extend_timeout',
default=rest_api._EXTEND_TIMEOUT,
@ -139,21 +142,22 @@ REST_VOLUME_OPTS = [
cfg.IntOpt(
'hitachi_rest_connect_timeout',
default=rest_api._DEFAULT_CONNECT_TIMEOUT,
help='Maximum wait time in seconds for REST API connection to '
'complete.'),
help='Maximum wait time in seconds for connecting to '
'REST API session.'),
cfg.IntOpt(
'hitachi_rest_job_api_response_timeout',
default=rest_api._JOB_API_RESPONSE_TIMEOUT,
help='Maximum wait time in seconds for a response from REST API.'),
help='Maximum wait time in seconds for a response against '
'async methods from REST API, for example PUT and DELETE.'),
cfg.IntOpt(
'hitachi_rest_get_api_response_timeout',
default=rest_api._GET_API_RESPONSE_TIMEOUT,
help='Maximum wait time in seconds for a response against GET method '
'of REST API.'),
help='Maximum wait time in seconds for a response against '
'sync methods, for example GET'),
cfg.IntOpt(
'hitachi_rest_server_busy_timeout',
default=rest_api._REST_SERVER_BUSY_TIMEOUT,
help='Maximum wait time in seconds when REST API returned busy.'),
help='Maximum wait time in seconds when REST API returns busy.'),
cfg.IntOpt(
'hitachi_rest_keep_session_loop_interval',
default=rest_api._KEEP_SESSION_LOOP_INTERVAL,
@ -176,8 +180,9 @@ REST_VOLUME_OPTS = [
help='Maximum number of transmissions for TCP keepalive packet.'),
cfg.ListOpt(
'hitachi_host_mode_options',
item_type=types.Integer(),
default=[],
help='host mode option for host group or iSCSI target'),
help='Host mode option for host group or iSCSI target.'),
]
_REQUIRED_REST_OPTS = [
@ -240,8 +245,6 @@ class HBSDREST(common.HBSDCommon):
self.client = None
self.init_timer_values()
def setup_client(self):
"""Initialize RestApiClient."""
verify = self.conf.driver_ssl_cert_verify
@ -251,6 +254,7 @@ class HBSDREST(common.HBSDCommon):
verify = verify_path
self.verify = verify
self.client = rest_api.RestApiClient(
self.conf,
self.conf.san_ip,
self.conf.san_api_port,
self.conf.hitachi_storage_id,
@ -320,7 +324,8 @@ class HBSDREST(common.HBSDCommon):
"""Wait until the S-VOL status changes to the specified status."""
interval = kwargs.pop(
'interval', self.conf.hitachi_copy_check_interval)
timeout = kwargs.pop('timeout', _STATE_TRANSITION_TIMEOUT)
timeout = kwargs.pop(
'timeout', self.conf.hitachi_state_transition_timeout)
def _wait_for_copy_pair_status(
start_time, ldev, status, timeout):
@ -445,7 +450,7 @@ class HBSDREST(common.HBSDCommon):
ldev_info['attributes']):
raise loopingcall.LoopingCallDone()
if utils.timed_out(
start_time, _STATE_TRANSITION_TIMEOUT):
start_time, self.conf.hitachi_state_transition_timeout):
raise loopingcall.LoopingCallDone(False)
loop = loopingcall.FixedIntervalLoopingCall(
@ -513,8 +518,8 @@ class HBSDREST(common.HBSDCommon):
assigned_lun, errobj = self.client.add_lun(
port, gid, ldev, lun=lun,
ignore_error=ignore_error,
interval=_LUN_RETRY_INTERVAL,
timeout=_LUN_TIMEOUT)
interval=self.conf.hitachi_lun_retry_interval,
timeout=self.conf.hitachi_lun_timeout)
err_code = utils.safe_get_err_code(errobj)
if lun is None:
if err_code == _LU_PATH_DEFINED:
@ -593,10 +598,10 @@ class HBSDREST(common.HBSDCommon):
def unmap_ldev(self, targets, ldev):
"""Delete the LUN between the specified LDEV and port-gid."""
interval = _LUN_RETRY_INTERVAL
interval = self.conf.hitachi_lun_retry_interval
ignore_return_code = [EX_ENOOBJ]
ignore_message_id = [rest_api.MSGID_SPECIFIED_OBJECT_DOES_NOT_EXIST]
timeout = _STATE_TRANSITION_TIMEOUT
timeout = self.conf.hitachi_state_transition_timeout
for target in targets['list']:
port = target['portId']
gid = target['hostGroupNumber']
@ -858,7 +863,7 @@ class HBSDREST(common.HBSDCommon):
return False
if ldev_info['snapshotPoolId'] is not None:
_, svol_info = self._get_copy_pair_info(ldev)
if svol_info and svol_info[0]['status'] == 'PSUP':
if svol_info and svol_info[0]['status'] in ('SMPP', 'PSUP'):
self._wait_copy_pair_deleting(ldev)
return False
else:
@ -874,7 +879,7 @@ class HBSDREST(common.HBSDCommon):
self.client.restore_snapshot(pvol, mun, body)
self._wait_copy_pair_status(
svol, PSUS, timeout=_RESTORE_TIMEOUT,
svol, PSUS, timeout=self.conf.hitachi_restore_timeout,
interval=self.conf.hitachi_async_copy_check_interval)
def has_snap_pair(self, pvol, svol):
@ -1165,45 +1170,3 @@ class HBSDREST(common.HBSDCommon):
return self._create_cgsnapshot(context, group_snapshot, snapshots)
else:
return self._create_non_cgsnapshot(group_snapshot, snapshots)
def init_timer_values(self):
global _LUN_TIMEOUT, _LUN_RETRY_INTERVAL
global _RESTORE_TIMEOUT, _STATE_TRANSITION_TIMEOUT
_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')

View File

@ -100,13 +100,19 @@ def _build_base_url(ip_addr, ip_port):
class KeepAliveAdapter(HTTPAdapter):
options = HTTPConnection.default_socket_options + [
def __init__(self, conf):
self.options = HTTPConnection.default_socket_options + [
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, _TCP_KEEPIDLE),
(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, _TCP_KEEPINTVL),
(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, _TCP_KEEPCNT),
(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE,
conf.hitachi_rest_tcp_keepidle),
(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL,
conf.hitachi_rest_tcp_keepintvl),
(socket.IPPROTO_TCP, socket.TCP_KEEPCNT,
conf.hitachi_rest_tcp_keepcnt),
]
super(KeepAliveAdapter, self).__init__()
def init_poolmanager(self, connections, maxsize, block=False):
self.poolmanager = PoolManager(num_pools=connections,
maxsize=maxsize,
@ -218,10 +224,11 @@ class ResponseData(dict):
class RestApiClient():
def __init__(self, ip_addr, ip_port, storage_device_id,
def __init__(self, conf, ip_addr, ip_port, storage_device_id,
user_id, user_pass, driver_prefix, tcp_keepalive=False,
verify=False, connect_timeout=_DEFAULT_CONNECT_TIMEOUT):
verify=False):
"""Initialize instance variables."""
self.conf = conf
self.ip_addr = ip_addr
self.ip_port = ip_port
self.storage_id = storage_device_id
@ -230,7 +237,7 @@ class RestApiClient():
self.user_pass = user_pass
self.tcp_keepalive = tcp_keepalive
self.verify = verify
self.connect_timeout = connect_timeout
self.connect_timeout = self.conf.hitachi_rest_connect_timeout
self.login_lock = threading.Lock()
self.keep_session_loop = loopingcall.FixedIntervalLoopingCall(
self._keep_session)
@ -276,22 +283,24 @@ class RestApiClient():
kwargs.setdefault('ignore_all_errors', False)
kwargs.setdefault('timeout_message', None)
kwargs.setdefault('no_log', False)
kwargs.setdefault('timeout', _REST_TIMEOUT)
kwargs.setdefault('timeout', self.conf.hitachi_rest_timeout)
headers = dict(self.headers)
if async_:
read_timeout = _JOB_API_RESPONSE_TIMEOUT
read_timeout = self.conf.hitachi_rest_job_api_response_timeout
headers.update({
"Response-Max-Wait": str(_JOB_API_RESPONSE_TIMEOUT),
"Response-Max-Wait": str(
self.conf.hitachi_rest_job_api_response_timeout),
"Response-Job-Status": "Completed;"})
else:
read_timeout = _GET_API_RESPONSE_TIMEOUT
read_timeout = self.conf.hitachi_rest_get_api_response_timeout
auth_data = kwargs.get('auth', self.get_my_session())
timeout = (self.connect_timeout, read_timeout)
interval = kwargs.get('interval', _EXEC_RETRY_INTERVAL)
interval = kwargs.get(
'interval', self.conf.hitachi_exec_retry_interval)
retry = True
start_time = timeutils.utcnow()
watch = timeutils.StopWatch()
@ -301,7 +310,7 @@ class RestApiClient():
try:
with requests.Session() as session:
if self.tcp_keepalive:
session.mount(_HTTPS, KeepAliveAdapter())
session.mount(_HTTPS, KeepAliveAdapter(self.conf))
rsp = session.request(method, url,
params=params,
json=body,
@ -350,7 +359,8 @@ class RestApiClient():
errobj = response['errobj']
if response.is_locked():
if (kwargs['no_retry'] or
utils.timed_out(start_time, _LOCK_TIMEOUT)):
utils.timed_out(
start_time, self.conf.hitachi_lock_timeout)):
msg = utils.output_log(MSG.REST_API_FAILED,
no_log=kwargs['no_log'],
method=method, url=url,
@ -387,10 +397,13 @@ class RestApiClient():
retry = True
if retry and response.is_rest_server_busy():
if utils.timed_out(start_time, _REST_SERVER_BUSY_TIMEOUT):
if utils.timed_out(
start_time, self.conf.hitachi_rest_server_busy_timeout):
retry = False
elif retry and response.get_err_code() in (ANOTHER_LDEV_MAPPED, ):
if utils.timed_out(start_time, _ANOTHER_LDEV_MAPPED_RETRY_TIMEOUT):
if utils.timed_out(
start_time,
self.conf.hitachi_rest_another_ldev_mapped_retry_timeout):
LOG.debug(
"Another LDEV is already mapped to the specified LUN.")
retry = False
@ -471,7 +484,8 @@ class RestApiClient():
}
auth = (self.user_id, self.user_pass)
rsp, err = self._request("POST", url, auth=auth, no_relogin=True,
do_raise=do_raise, timeout=_LOCK_TIMEOUT)
do_raise=do_raise,
timeout=self.conf.hitachi_lock_timeout)
if not err:
self.set_my_session(self.Session(rsp["sessionId"], rsp["token"]))
return True
@ -529,7 +543,8 @@ class RestApiClient():
def enter_keep_session(self):
"""Begin the keeping of a session."""
self.keep_session_loop.start(_KEEP_SESSION_LOOP_INTERVAL)
self.keep_session_loop.start(
self.conf.hitachi_rest_keep_session_loop_interval)
LOG.debug('enter_keep_session')
def _get_object(self, url, params=None, **kwargs):
@ -623,7 +638,7 @@ class RestApiClient():
'id': ldev_id,
'action': 'expand',
}
self._invoke(url, body=body, timeout=_EXTEND_TIMEOUT)
self._invoke(url, body=body, timeout=self.conf.hitachi_extend_timeout)
def get_ports(self, params=None):
"""Get a list of port information."""