Skip to content

Commit

Permalink
fix when there is more than 2000 volumes rest would timeout issue and…
Browse files Browse the repository at this point in the history
… change volume name as volume id when the volume name is none (#448)

* fix when there is more than 2000 volumes rest would timeout issue and change volume name as volume id when the volume name is none

Co-authored-by: Ashit Kumar <akopensrc@gmail.com>
  • Loading branch information
jiangyutan and kumarashit authored Jan 6, 2021
1 parent 34bdef6 commit 3ac30de
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 179 deletions.
4 changes: 2 additions & 2 deletions delfin/drivers/hitachi/vsp/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
# 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.
SOCKET_TIMEOUT = 30
SOCKET_TIMEOUT = 90
ERROR_SESSION_INVALID_CODE = 403
ERROR_SESSION_IS_BEING_USED_CODE = 409
BLOCK_SIZE = 512
MAX_LDEV_NUMBER_OF_RESTAPI = 16383
LDEV_NUMBER_OF_PER_REQUEST = 300
SUPPORTED_VSP_SERIES = ('VSP G350', 'VSP G370', 'VSP G700', 'VSP G900',
'VSP F350', 'VSP F370', 'VSP F700', 'VSP F900')
71 changes: 49 additions & 22 deletions delfin/drivers/hitachi/vsp/rest_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(self, **kwargs):
def call(self, url, data=None, method=None,
calltimeout=consts.SOCKET_TIMEOUT):
try:
res = self.do_call(url, data, method, calltimeout)
res = self.call_with_token(url, data, method, calltimeout)
if (res.status_code == consts.ERROR_SESSION_INVALID_CODE
or res.status_code ==
consts.ERROR_SESSION_IS_BEING_USED_CODE):
Expand All @@ -53,11 +53,8 @@ def call(self, url, data=None, method=None,
if method == 'DELETE' and RestHandler. \
LOGOUT_URL in url:
return res
self.rest_auth_token = None
access_session = self.login()
if access_session is not None:
res = self. \
do_call(url, data, method, calltimeout)
if self.get_token():
res = self.call_with_token(url, data, method, calltimeout)
else:
LOG.error('Login error,get access_session failed')
elif res.status_code == 503:
Expand All @@ -70,17 +67,33 @@ def call(self, url, data=None, method=None,
LOG.error(err_msg)
raise e

def call_with_token(self, url, data, method, calltimeout):
auth_key = None
if self.session:
auth_key = self.session.headers.get(RestHandler.AUTH_KEY, None)
if auth_key:
self.session.headers[RestHandler.AUTH_KEY] \
= cryptor.decode(auth_key)
res = self. \
do_call(url, data, method, calltimeout)
if auth_key:
self.session.headers[RestHandler.AUTH_KEY] = auth_key
return res

def get_rest_info(self, url, timeout=consts.SOCKET_TIMEOUT, data=None):
result_json = None
if self.session and url != RestHandler.COMM_URL:
auth_key = self.session.headers.get(RestHandler.AUTH_KEY, None)
if auth_key is None:
self.get_token()
res = self.call(url, data, 'GET', timeout)
if res.status_code == 200:
result_json = res.json()
return result_json

def login(self):
def get_token(self):
try:
self.get_device_id()
access_session = self.rest_auth_token
succeed = False
if self.san_address:
url = '%s/%s/sessions' % \
(RestHandler.COMM_URL,
Expand All @@ -94,15 +107,16 @@ def login(self):
requests.auth.HTTPBasicAuth(
self.rest_username,
cryptor.decode(self.rest_password))
res = self. \
do_call(url, data, 'POST', 10)
res = self.call_with_token(url, data, 'POST', 30)
if res.status_code == 200:
succeed = True
result = res.json()
self.session_id = result.get('sessionId')
self.session_id = cryptor.encode(
result.get('sessionId'))
access_session = 'Session %s' % result.get('token')
self.rest_auth_token = access_session
self.session.headers[
RestHandler.AUTH_KEY] = access_session
RestHandler.AUTH_KEY] = cryptor.encode(
access_session)
else:
LOG.error("Login error. URL: %(url)s\n"
"Reason: %(reason)s.",
Expand All @@ -112,9 +126,18 @@ def login(self):
else:
raise exception.BadResponse(res.text)
else:
LOG.error('Login Parameter error')
LOG.error('Token Parameter error')

return access_session
return succeed
except Exception as e:
LOG.error("Get token error: %s", six.text_type(e))
raise e

def login(self):
try:
succeed = False
succeed = self.get_device_id()
return succeed
except Exception as e:
LOG.error("Login error: %s", six.text_type(e))
raise e
Expand All @@ -126,15 +149,15 @@ def logout(self):
url = '%s/%s/sessions/%s' % \
(RestHandler.COMM_URL,
self.storage_device_id,
self.session_id)
cryptor.decode(self.session_id))
if self.san_address:
self.call(url, method='DELETE')
url = None
self.session_id = None
self.storage_device_id = None
self.device_model = None
self.serial_number = None
self.session = None
self.rest_auth_token = None
else:
LOG.error('logout error:session id not found')
except Exception as err:
Expand All @@ -144,11 +167,13 @@ def logout(self):

def get_device_id(self):
try:
succeed = False
if self.session is None:
self.init_http_head()
storage_systems = self.get_system_info()
system_info = storage_systems.get('data')
for system in system_info:
succeed = True
if system.get('model') in consts.SUPPORTED_VSP_SERIES:
if system.get('ctl1Ip') == self.rest_host or \
system.get('ctl2Ip') == self.rest_host:
Expand All @@ -163,6 +188,7 @@ def get_device_id(self):
break
if self.storage_device_id is None:
LOG.error("Get device id fail,model or something is wrong")
return succeed
except Exception as e:
LOG.error("Get device id error: %s", six.text_type(e))
raise e
Expand All @@ -189,10 +215,11 @@ def get_all_pools(self):
result_json = self.get_rest_info(url)
return result_json

def get_all_volumes(self):
url = '%s/%s/ldevs?ldevOption=defined&count=%s' % \
(RestHandler.COMM_URL, self.storage_device_id,
consts.MAX_LDEV_NUMBER_OF_RESTAPI)
def get_volumes(self, head_id,
max_number=consts.LDEV_NUMBER_OF_PER_REQUEST):
url = '%s/%s/ldevs?headLdevId=%s&count=%s' % \
(RestHandler.COMM_URL, self.storage_device_id, head_id,
max_number)
result_json = self.get_rest_info(url)
return result_json

Expand Down
45 changes: 36 additions & 9 deletions delfin/drivers/hitachi/vsp/vsp_stor.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,36 @@ def list_storage_pools(self, context):
LOG.error(err_msg)
raise exception.InvalidResults(err_msg)

@staticmethod
def to_vsp_lun_id_format(lun_id):
hex_str = hex(lun_id)
result = ''
hex_lun_id = hex_str[2::].rjust(6, '0')
is_first = True
for i in range(0, len(hex_lun_id), 2):
if is_first is True:
result = '%s' % (hex_lun_id[i:i + 2])
is_first = False
else:
result = '%s:%s' % (result, hex_lun_id[i:i + 2])
return result

def list_volumes(self, context):
try:
volumes_info = self.rest_handler.get_all_volumes()
head_id = 0
is_end = False
volume_list = []
while is_end is False:
is_end = self.get_volumes_paginated(volume_list, head_id)
head_id += consts.LDEV_NUMBER_OF_PER_REQUEST
return volume_list

volume_list = []
def get_volumes_paginated(self, volume_list, head_id):
try:
volumes_info = self.rest_handler.get_volumes(head_id)
volumes = volumes_info.get('data')
for volume in volumes:
if volume.get('emulationType') == 'NOT DEFINED':
continue
return True
orig_pool_id = volume.get('poolId')
compressed = False
deduplicated = False
Expand All @@ -190,17 +211,19 @@ def list_volumes(self, context):
# Because there is only subscribed capacity in device,so free
# capacity always 0
free_cap = 0
native_volume_id = HitachiVspDriver.to_vsp_lun_id_format(
volume.get('ldevId'))
if volume.get('label'):
name = volume.get('label')
else:
name = 'ldev_%s' % str(volume.get('ldevId'))
name = native_volume_id

v = {
'name': name,
'storage_id': self.storage_id,
'description': 'Hitachi VSP volume',
'status': status,
'native_volume_id': str(volume.get('ldevId')),
'native_volume_id': str(native_volume_id),
'native_storage_pool_id': orig_pool_id,
'type': vol_type,
'total_capacity': total_cap,
Expand All @@ -211,8 +234,7 @@ def list_volumes(self, context):
}

volume_list.append(v)

return volume_list
return False
except exception.DelfinException as err:
err_msg = "Failed to get volumes metrics from hitachi vsp: %s" % \
(six.text_type(err))
Expand All @@ -236,7 +258,7 @@ def parse_queried_alerts(alerts, alert_list, query_para=None):
continue
a = {
'location': alert.get('location'),
'alarm_id': alert.get('alertId'),
'alert_id': alert.get('alertId'),
'sequence_number': alert.get('alertIndex'),
'description': alert.get('errorDetail'),
'alert_name': alert.get('errorSection'),
Expand All @@ -263,6 +285,11 @@ def list_alerts(self, context, query_para=None):
alert_list, query_para)
HitachiVspDriver.parse_queried_alerts(alerts_info_dkc,
alert_list, query_para)
else:
err_msg = "list_alerts is not supported in model %s" % \
self.rest_handler.device_model
LOG.error(err_msg)
raise NotImplementedError(err_msg)

return alert_list

Expand Down
Loading

0 comments on commit 3ac30de

Please sign in to comment.