00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 import os
00018 import json
00019 import re
00020 import errno
00021 import math
00022
00023 from lsm import (uri_parse, search_property, size_human_2_size_bytes,
00024 Capabilities, LsmError, ErrorNumber, System, Client,
00025 Disk, VERSION, IPlugin, Pool, Volume)
00026
00027 from lsm.plugin.megaraid.utils import cmd_exec, ExecError
00028
00029
00030
00031
00032
00033
00034
00035 def _handle_errors(method):
00036 def _wrapper(*args, **kwargs):
00037 try:
00038 return method(*args, **kwargs)
00039 except LsmError:
00040 raise
00041 except KeyError as key_error:
00042 raise LsmError(
00043 ErrorNumber.PLUGIN_BUG,
00044 "Expected key missing from MegaRAID storcli output:%s" %
00045 key_error)
00046 except ExecError as exec_error:
00047 raise LsmError(ErrorNumber.PLUGIN_BUG, str(exec_error))
00048 except Exception as common_error:
00049 raise LsmError(
00050 ErrorNumber.PLUGIN_BUG,
00051 "Got unexpected error %s" % common_error)
00052
00053 return _wrapper
00054
00055
00056 def _blk_count_of(mega_disk_size):
00057 blk_count_regex = re.compile("(0x[0-9a-f]+) Sectors")
00058 blk_count_search = blk_count_regex.search(mega_disk_size)
00059 if blk_count_search:
00060 return int(blk_count_search.group(1), 16)
00061 return Disk.BLOCK_COUNT_NOT_FOUND
00062
00063
00064 def _disk_type_of(disk_show_basic_dict):
00065 """
00066 Return the 'Drive /c0/e64/s0' entry of '/c0/e64/s0 show all'
00067 """
00068 disk_media = disk_show_basic_dict['Med']
00069 disk_interface = disk_show_basic_dict['Intf']
00070 if disk_media == 'HDD':
00071 if disk_interface == 'SATA':
00072 return Disk.TYPE_SATA
00073 elif disk_interface == 'SAS':
00074 return Disk.TYPE_SAS
00075 elif disk_interface == 'Parallel SCSI':
00076 return Disk.TYPE_SCSI
00077 elif disk_interface == 'FC':
00078 return Disk.TYPE_FC
00079 else:
00080 return Disk.TYPE_HDD
00081 elif disk_media == 'SSD':
00082 return Disk.TYPE_SSD
00083
00084 return Disk.TYPE_UNKNOWN
00085
00086 _DISK_STATE_MAP = {
00087 'Onln': Disk.STATUS_OK,
00088 'Offln': Disk.STATUS_ERROR,
00089 'GHS': Disk.STATUS_SPARE_DISK | Disk.STATUS_OK,
00090 'DHS': Disk.STATUS_SPARE_DISK | Disk.STATUS_OK,
00091 'UGood': Disk.STATUS_FREE | Disk.STATUS_OK,
00092 'UBad': Disk.STATUS_FREE | Disk.STATUS_ERROR,
00093 'Rbld': Disk.STATUS_RECONSTRUCT,
00094 }
00095
00096
00097 def _disk_status_of(disk_show_basic_dict, disk_show_stat_dict):
00098 disk_status = _DISK_STATE_MAP.get(
00099 disk_show_basic_dict['State'], 0)
00100
00101 if disk_show_stat_dict['Media Error Count'] or \
00102 disk_show_stat_dict['Other Error Count'] or \
00103 disk_show_stat_dict['S.M.A.R.T alert flagged by drive'] != 'No':
00104 disk_status -= Disk.STATUS_OK
00105 disk_status |= Disk.STATUS_ERROR
00106
00107 elif disk_show_stat_dict['Predictive Failure Count']:
00108 disk_status -= Disk.STATUS_OK
00109 disk_status |= Disk.STATUS_PREDICTIVE_FAILURE
00110
00111 if disk_show_basic_dict['Sp'] == 'D':
00112 disk_status |= Disk.STATUS_STOPPED
00113
00114 if disk_show_basic_dict['Sp'] == 'F':
00115 disk_status |= Disk.STATUS_OTHER
00116
00117 if disk_status == 0:
00118 disk_status = Disk.STATUS_UNKNOWN
00119
00120 return disk_status
00121
00122
00123 def _mega_size_to_lsm(mega_size):
00124 """
00125 LSI Using 'TB, GB, MB, KB' and etc, for LSM, they are 'TiB' and etc.
00126 Return int of block bytes
00127 """
00128 re_regex = re.compile("^([0-9.]+) ([EPTGMK])B$")
00129 re_match = re_regex.match(mega_size)
00130 if re_match:
00131 return size_human_2_size_bytes(
00132 "%s%siB" % (re_match.group(1), re_match.group(2)))
00133
00134 raise LsmError(
00135 ErrorNumber.PLUGIN_BUG,
00136 "_mega_size_to_lsm(): Got unexpected LSI size string %s" %
00137 mega_size)
00138
00139
00140 _POOL_STATUS_MAP = {
00141 'Onln': Pool.STATUS_OK,
00142 'Dgrd': Pool.STATUS_DEGRADED | Pool.STATUS_OK,
00143 'Pdgd': Pool.STATUS_DEGRADED | Pool.STATUS_OK,
00144 'Offln': Pool.STATUS_ERROR,
00145 'Rbld': Pool.STATUS_RECONSTRUCTING | Pool.STATUS_DEGRADED | Pool.STATUS_OK,
00146 'Optl': Pool.STATUS_OK,
00147 }
00148
00149
00150 def _pool_status_of(dg_top):
00151 """
00152 Return status
00153 """
00154 if dg_top['State'] in _POOL_STATUS_MAP.keys():
00155 return _POOL_STATUS_MAP[dg_top['State']]
00156 return Pool.STATUS_UNKNOWN
00157
00158
00159 def _pool_id_of(dg_id, sys_id):
00160 return "%s:DG%s" % (sys_id, dg_id)
00161
00162
00163 _RAID_TYPE_MAP = {
00164 'RAID0': Volume.RAID_TYPE_RAID0,
00165 'RAID1': Volume.RAID_TYPE_RAID1,
00166 'RAID5': Volume.RAID_TYPE_RAID5,
00167 'RAID6': Volume.RAID_TYPE_RAID6,
00168 'RAID00': Volume.RAID_TYPE_RAID0,
00169
00170
00171
00172 'RAID10': Volume.RAID_TYPE_RAID10,
00173 'RAID50': Volume.RAID_TYPE_RAID50,
00174 'RAID60': Volume.RAID_TYPE_RAID60,
00175 }
00176
00177 _LSM_RAID_TYPE_CONV = {
00178 Volume.RAID_TYPE_RAID0: 'RAID0',
00179 Volume.RAID_TYPE_RAID1: 'RAID1',
00180 Volume.RAID_TYPE_RAID5: 'RAID5',
00181 Volume.RAID_TYPE_RAID6: 'RAID6',
00182 Volume.RAID_TYPE_RAID50: 'RAID50',
00183 Volume.RAID_TYPE_RAID60: 'RAID60',
00184 Volume.RAID_TYPE_RAID10: 'RAID10',
00185 }
00186
00187
00188 def _mega_raid_type_to_lsm(vd_basic_info, vd_prop_info):
00189 raid_type = _RAID_TYPE_MAP.get(
00190 vd_basic_info['TYPE'], Volume.RAID_TYPE_UNKNOWN)
00191
00192
00193 if raid_type == Volume.RAID_TYPE_RAID1 and \
00194 int(vd_prop_info['Number of Drives Per Span']) >= 4:
00195 raid_type = Volume.RAID_TYPE_RAID10
00196
00197 return raid_type
00198
00199
00200 def _lsm_raid_type_to_mega(lsm_raid_type):
00201 try:
00202 return _LSM_RAID_TYPE_CONV[lsm_raid_type]
00203 except KeyError:
00204 raise LsmError(
00205 ErrorNumber.NO_SUPPORT,
00206 "RAID type %d not supported" % lsm_raid_type)
00207
00208
00209 class MegaRAID(IPlugin):
00210 _DEFAULT_BIN_PATHS = [
00211 "/opt/MegaRAID/storcli/storcli64", "/opt/MegaRAID/storcli/storcli",
00212 "/opt/MegaRAID/perccli/perccli64", "/opt/MegaRAID/perccli/perccli"]
00213 _CMD_JSON_OUTPUT_SWITCH = 'J'
00214
00215 def __init__(self):
00216 self._storcli_bin = None
00217
00218 def _find_storcli(self):
00219 """
00220 Try _DEFAULT_BIN_PATHS
00221 """
00222 for cur_path in MegaRAID._DEFAULT_BIN_PATHS:
00223 if os.path.lexists(cur_path):
00224 self._storcli_bin = cur_path
00225
00226 if not self._storcli_bin:
00227 raise LsmError(
00228 ErrorNumber.INVALID_ARGUMENT,
00229 "MegaRAID storcli is not installed correctly")
00230
00231 @_handle_errors
00232 def plugin_register(self, uri, password, timeout, flags=Client.FLAG_RSVD):
00233 if os.geteuid() != 0:
00234 raise LsmError(
00235 ErrorNumber.INVALID_ARGUMENT,
00236 "This plugin requires root privilege both daemon and client")
00237 uri_parsed = uri_parse(uri)
00238 self._storcli_bin = uri_parsed.get('parameters', {}).get('storcli')
00239 if not self._storcli_bin:
00240 self._find_storcli()
00241
00242
00243
00244 os.chdir("/tmp")
00245 self._storcli_exec(['-v'], flag_json=False)
00246
00247 @_handle_errors
00248 def plugin_unregister(self, flags=Client.FLAG_RSVD):
00249 pass
00250
00251 @_handle_errors
00252 def job_status(self, job_id, flags=Client.FLAG_RSVD):
00253 raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet")
00254
00255 @_handle_errors
00256 def job_free(self, job_id, flags=Client.FLAG_RSVD):
00257 pass
00258
00259 @_handle_errors
00260 def plugin_info(self, flags=Client.FLAG_RSVD):
00261 return "LSI MegaRAID Plugin", VERSION
00262
00263 @_handle_errors
00264 def time_out_set(self, ms, flags=Client.FLAG_RSVD):
00265 raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet")
00266
00267 @_handle_errors
00268 def time_out_get(self, flags=Client.FLAG_RSVD):
00269 raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet")
00270
00271 @_handle_errors
00272 def capabilities(self, system, flags=Client.FLAG_RSVD):
00273 cur_lsm_syss = self.systems()
00274 if system.id not in list(s.id for s in cur_lsm_syss):
00275 raise LsmError(
00276 ErrorNumber.NOT_FOUND_SYSTEM,
00277 "System not found")
00278 cap = Capabilities()
00279 cap.set(Capabilities.DISKS)
00280 cap.set(Capabilities.VOLUMES)
00281 cap.set(Capabilities.VOLUME_RAID_INFO)
00282 cap.set(Capabilities.POOL_MEMBER_INFO)
00283 cap.set(Capabilities.VOLUME_RAID_CREATE)
00284 return cap
00285
00286 def _storcli_exec(self, storcli_cmds, flag_json=True):
00287 storcli_cmds.insert(0, self._storcli_bin)
00288 if flag_json:
00289 storcli_cmds.append(MegaRAID._CMD_JSON_OUTPUT_SWITCH)
00290 try:
00291 output = cmd_exec(storcli_cmds)
00292 except OSError as os_error:
00293 if os_error.errno == errno.ENOENT:
00294 raise LsmError(
00295 ErrorNumber.INVALID_ARGUMENT,
00296 "storcli binary '%s' is not exist or executable." %
00297 self._storcli_bin)
00298 else:
00299 raise
00300
00301 output = re.sub("[^\x20-\x7e]", " ", output)
00302
00303 if flag_json:
00304 output_dict = json.loads(output)
00305 ctrl_output = output_dict.get('Controllers')
00306 if len(ctrl_output) != 1:
00307 raise LsmError(
00308 ErrorNumber.PLUGIN_BUG,
00309 "_storcli_exec(): Unexpected output from MegaRAID "
00310 "storcli: %s" % output_dict)
00311
00312 rc_status = ctrl_output[0].get('Command Status')
00313 if rc_status.get('Status') != 'Success':
00314 raise LsmError(
00315 ErrorNumber.PLUGIN_BUG,
00316 "MegaRAID storcli failed with error %d: %s" %
00317 (rc_status['Status Code'], rc_status['Description']))
00318 real_data = ctrl_output[0].get('Response Data')
00319 if real_data and 'Response Data' in real_data.keys():
00320 return real_data['Response Data']
00321
00322 return real_data
00323 else:
00324 return output
00325
00326 def _ctrl_count(self):
00327 ctrl_count = self._storcli_exec(
00328 ["show", "ctrlcount"]).get("Controller Count")
00329 if ctrl_count < 1:
00330 raise LsmError(
00331 ErrorNumber.NOT_FOUND_SYSTEM,
00332 "No MegaRAID controller detected by %s" % self._storcli_bin)
00333 return ctrl_count
00334
00335 def _lsm_status_of_ctrl(self, ctrl_show_all_output):
00336 lsi_status_info = ctrl_show_all_output['Status']
00337 status_info = ''
00338 status = System.STATUS_UNKNOWN
00339 if lsi_status_info['Controller Status'] == 'Optimal':
00340 status = System.STATUS_OK
00341 else:
00342
00343 status_info = "%s: " % lsi_status_info['Controller Status']
00344 for key_name in lsi_status_info.keys():
00345 if key_name == 'Controller Status':
00346 continue
00347 if lsi_status_info[key_name] != 0 and \
00348 lsi_status_info[key_name] != 'No' and \
00349 lsi_status_info[key_name] != 'NA':
00350 status_info += " %s:%s" % (
00351 key_name, lsi_status_info[key_name])
00352
00353 return status, status_info
00354
00355 def _sys_id_of_ctrl_num(self, ctrl_num, ctrl_show_all_output=None):
00356 if ctrl_show_all_output is None:
00357 return self._storcli_exec(
00358 ["/c%d" % ctrl_num, "show"])['Serial Number']
00359 else:
00360 return ctrl_show_all_output['Basics']['Serial Number']
00361
00362 @_handle_errors
00363 def systems(self, flags=Client.FLAG_RSVD):
00364 rc_lsm_syss = []
00365 for ctrl_num in range(self._ctrl_count()):
00366 ctrl_show_all_output = self._storcli_exec(
00367 ["/c%d" % ctrl_num, "show", "all"])
00368 sys_id = self._sys_id_of_ctrl_num(ctrl_num, ctrl_show_all_output)
00369 sys_name = "%s %s %s ver: %s" % (
00370 ctrl_show_all_output['Basics']['Model'],
00371 ctrl_show_all_output['Bus']['Host Interface'],
00372 ctrl_show_all_output['Basics']['PCI Address'],
00373 ctrl_show_all_output['Version']['Firmware Package Build'],
00374 )
00375 (status, status_info) = self._lsm_status_of_ctrl(
00376 ctrl_show_all_output)
00377 plugin_data = "/c%d" % ctrl_num
00378
00379
00380
00381 rc_lsm_syss.append(
00382 System(sys_id, sys_name, status, status_info, plugin_data))
00383
00384 return rc_lsm_syss
00385
00386 @_handle_errors
00387 def disks(self, search_key=None, search_value=None,
00388 flags=Client.FLAG_RSVD):
00389 rc_lsm_disks = []
00390 mega_disk_path_regex = re.compile(
00391 r"^Drive (\/c[0-9]+\/e[0-9]+\/s[0-9]+) - Detailed Information$")
00392
00393 for ctrl_num in range(self._ctrl_count()):
00394 sys_id = self._sys_id_of_ctrl_num(ctrl_num)
00395
00396 disk_show_output = self._storcli_exec(
00397 ["/c%d/eall/sall" % ctrl_num, "show", "all"])
00398 for drive_name in disk_show_output.keys():
00399 re_match = mega_disk_path_regex.match(drive_name)
00400 if not re_match:
00401 continue
00402
00403 mega_disk_path = re_match.group(1)
00404
00405 disk_show_basic_dict = disk_show_output[
00406 "Drive %s" % mega_disk_path][0]
00407 disk_show_attr_dict = disk_show_output[drive_name][
00408 'Drive %s Device attributes' % mega_disk_path]
00409 disk_show_stat_dict = disk_show_output[drive_name][
00410 'Drive %s State' % mega_disk_path]
00411
00412 disk_id = disk_show_attr_dict['SN'].strip()
00413 disk_name = "Disk %s %s %s" % (
00414 disk_show_basic_dict['DID'],
00415 disk_show_attr_dict['Manufacturer Id'].strip(),
00416 disk_show_attr_dict['Model Number'])
00417 disk_type = _disk_type_of(disk_show_basic_dict)
00418 blk_size = size_human_2_size_bytes(
00419 disk_show_basic_dict['SeSz'])
00420 blk_count = _blk_count_of(disk_show_attr_dict['Coerced size'])
00421 status = _disk_status_of(
00422 disk_show_basic_dict, disk_show_stat_dict)
00423
00424 plugin_data = "%s:%s" % (
00425 ctrl_num, disk_show_basic_dict['EID:Slt'])
00426
00427 rc_lsm_disks.append(
00428 Disk(
00429 disk_id, disk_name, disk_type, blk_size, blk_count,
00430 status, sys_id, plugin_data))
00431
00432 return search_property(rc_lsm_disks, search_key, search_value)
00433
00434 @staticmethod
00435 def _dg_free_size(dg_num, free_space_list):
00436 """
00437 Get information from 'FREE SPACE DETAILS' of /c0/dall show all.
00438 """
00439 for free_space in free_space_list:
00440 if int(free_space['DG']) == int(dg_num):
00441 return _mega_size_to_lsm(free_space['Size'])
00442
00443 return 0
00444
00445 def _dg_top_to_lsm_pool(self, dg_top, free_space_list, ctrl_num):
00446 sys_id = self._sys_id_of_ctrl_num(ctrl_num)
00447 pool_id = _pool_id_of(dg_top['DG'], sys_id)
00448 name = '%s Disk Group %s' % (dg_top['Type'], dg_top['DG'])
00449 elem_type = Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_VOLUME_FULL
00450 unsupported_actions = 0
00451
00452
00453
00454 total_space = _mega_size_to_lsm(dg_top['Size'])
00455 free_space = MegaRAID._dg_free_size(dg_top['DG'], free_space_list)
00456 status = _pool_status_of(dg_top)
00457 status_info = ''
00458 if status == Pool.STATUS_UNKNOWN:
00459 status_info = dg_top['State']
00460
00461 plugin_data = "/c%d/d%s" % (ctrl_num, dg_top['DG'])
00462
00463 return Pool(
00464 pool_id, name, elem_type, unsupported_actions,
00465 total_space, free_space, status, status_info,
00466 sys_id, plugin_data)
00467
00468 @_handle_errors
00469 def pools(self, search_key=None, search_value=None,
00470 flags=Client.FLAG_RSVD):
00471 lsm_pools = []
00472 for ctrl_num in range(self._ctrl_count()):
00473 dg_show_output = self._storcli_exec(
00474 ["/c%d/dall" % ctrl_num, "show", "all"])
00475 free_space_list = dg_show_output.get('FREE SPACE DETAILS', [])
00476 if 'TOPOLOGY' not in dg_show_output:
00477 continue
00478 for dg_top in dg_show_output['TOPOLOGY']:
00479 if dg_top['Arr'] != '-':
00480 continue
00481 if dg_top['DG'] == '-':
00482 continue
00483 lsm_pools.append(
00484 self._dg_top_to_lsm_pool(
00485 dg_top, free_space_list, ctrl_num))
00486
00487 return search_property(lsm_pools, search_key, search_value)
00488
00489 @staticmethod
00490 def _vd_to_lsm_vol(vd_id, dg_id, sys_id, vd_basic_info, vd_pd_info_list,
00491 vd_prop_info, vd_path):
00492
00493 vol_id = "%s:VD%d" % (sys_id, vd_id)
00494 name = "VD %d" % vd_id
00495 if 'Name' in vd_basic_info.keys() and vd_basic_info['Name']:
00496 name += ": %s" % vd_basic_info['Name']
00497
00498 vpd83 = ''
00499 block_size = size_human_2_size_bytes(vd_pd_info_list[0]['SeSz'])
00500 num_of_blocks = vd_prop_info['Number of Blocks']
00501 admin_state = Volume.ADMIN_STATE_ENABLED
00502 if vd_prop_info['Exposed to OS'] != 'Yes' or \
00503 vd_basic_info['Access'] != 'RW':
00504 admin_state = Volume.ADMIN_STATE_DISABLED
00505 pool_id = _pool_id_of(dg_id, sys_id)
00506 plugin_data = vd_path
00507 return Volume(
00508 vol_id, name, vpd83, block_size, num_of_blocks, admin_state,
00509 sys_id, pool_id, plugin_data)
00510
00511 @_handle_errors
00512 def volumes(self, search_key=None, search_value=None,
00513 flags=Client.FLAG_RSVD):
00514 lsm_vols = []
00515 for ctrl_num in range(self._ctrl_count()):
00516 vol_show_output = self._storcli_exec(
00517 ["/c%d/vall" % ctrl_num, "show", "all"])
00518 sys_id = self._sys_id_of_ctrl_num(ctrl_num)
00519 if vol_show_output is None or len(vol_show_output) == 0:
00520 continue
00521 for key_name in vol_show_output.keys():
00522 if key_name.startswith('/c'):
00523 vd_basic_info = vol_show_output[key_name][0]
00524 (dg_id, vd_id) = vd_basic_info['DG/VD'].split('/')
00525 dg_id = int(dg_id)
00526 vd_id = int(vd_id)
00527 vd_pd_info_list = vol_show_output['PDs for VD %d' % vd_id]
00528
00529 vd_prop_info = vol_show_output['VD%d Properties' % vd_id]
00530
00531 lsm_vols.append(
00532 MegaRAID._vd_to_lsm_vol(
00533 vd_id, dg_id, sys_id, vd_basic_info,
00534 vd_pd_info_list, vd_prop_info, key_name))
00535
00536 return search_property(lsm_vols, search_key, search_value)
00537
00538 @_handle_errors
00539 def volume_raid_info(self, volume, flags=Client.FLAG_RSVD):
00540 if not volume.plugin_data:
00541 raise LsmError(
00542 ErrorNumber.INVALID_ARGUMENT,
00543 "Ilegal input volume argument: missing plugin_data property")
00544
00545 vd_path = volume.plugin_data
00546 vol_show_output = self._storcli_exec([vd_path, "show", "all"])
00547 vd_basic_info = vol_show_output[vd_path][0]
00548 vd_id = int(vd_basic_info['DG/VD'].split('/')[-1])
00549 vd_prop_info = vol_show_output['VD%d Properties' % vd_id]
00550
00551 raid_type = _mega_raid_type_to_lsm(vd_basic_info, vd_prop_info)
00552 strip_size = _mega_size_to_lsm(vd_prop_info['Strip Size'])
00553 disk_count = (
00554 int(vd_prop_info['Number of Drives Per Span']) *
00555 int(vd_prop_info['Span Depth']))
00556 if raid_type == Volume.RAID_TYPE_RAID0:
00557 strip_count = disk_count
00558 elif raid_type == Volume.RAID_TYPE_RAID1:
00559 strip_count = 1
00560 elif raid_type == Volume.RAID_TYPE_RAID5:
00561 strip_count = disk_count - 1
00562 elif raid_type == Volume.RAID_TYPE_RAID6:
00563 strip_count = disk_count - 2
00564 elif raid_type == Volume.RAID_TYPE_RAID50:
00565 strip_count = (
00566 (int(vd_prop_info['Number of Drives Per Span']) - 1) *
00567 int(vd_prop_info['Span Depth']))
00568 elif raid_type == Volume.RAID_TYPE_RAID60:
00569 strip_count = (
00570 (int(vd_prop_info['Number of Drives Per Span']) - 2) *
00571 int(vd_prop_info['Span Depth']))
00572 elif raid_type == Volume.RAID_TYPE_RAID10:
00573 strip_count = (
00574 int(vd_prop_info['Number of Drives Per Span']) / 2 *
00575 int(vd_prop_info['Span Depth']))
00576 else:
00577
00578 raise LsmError(
00579 ErrorNumber.PLUGIN_BUG,
00580 "volume_raid_info(): Got unexpected RAID type: %s" %
00581 vd_basic_info['TYPE'])
00582
00583 return [
00584 raid_type, strip_size, disk_count, strip_size,
00585 strip_size * strip_count]
00586
00587 @_handle_errors
00588 def pool_member_info(self, pool, flags=Client.FLAG_RSVD):
00589 lsi_dg_path = pool.plugin_data
00590
00591 try:
00592 dg_show_all_output = self._storcli_exec(
00593 [lsi_dg_path, "show", "all"])
00594 except ExecError as exec_error:
00595 try:
00596 json_output = json.loads(exec_error.stdout)
00597 detail_error = json_output[
00598 'Controllers'][0]['Command Status']['Detailed Status']
00599 except Exception:
00600 raise exec_error
00601
00602 if detail_error and detail_error[0]['Status'] == 'Not found':
00603 raise LsmError(
00604 ErrorNumber.NOT_FOUND_POOL,
00605 "Pool not found")
00606 raise
00607
00608 ctrl_num = lsi_dg_path.split('/')[1][1:]
00609 lsm_disk_map = {}
00610 disk_ids = []
00611 for lsm_disk in self.disks():
00612 lsm_disk_map[lsm_disk.plugin_data] = lsm_disk.id
00613
00614 for dg_disk_info in dg_show_all_output['DG Drive LIST']:
00615 cur_lsi_disk_id = "%s:%s" % (ctrl_num, dg_disk_info['EID:Slt'])
00616 if cur_lsi_disk_id in lsm_disk_map.keys():
00617 disk_ids.append(lsm_disk_map[cur_lsi_disk_id])
00618 else:
00619 raise LsmError(
00620 ErrorNumber.PLUGIN_BUG,
00621 "pool_member_info(): Failed to find disk id of %s" %
00622 cur_lsi_disk_id)
00623
00624 raid_type = Volume.RAID_TYPE_UNKNOWN
00625 dg_num = lsi_dg_path.split('/')[2][1:]
00626 for dg_top in dg_show_all_output['TOPOLOGY']:
00627 if dg_top['Arr'] == '-' and \
00628 dg_top['Row'] == '-' and \
00629 int(dg_top['DG']) == int(dg_num):
00630 raid_type = _RAID_TYPE_MAP.get(
00631 dg_top['Type'], Volume.RAID_TYPE_UNKNOWN)
00632 break
00633
00634 if raid_type == Volume.RAID_TYPE_RAID1 and len(disk_ids) >= 4:
00635 raid_type = Volume.RAID_TYPE_RAID10
00636
00637 return raid_type, Pool.MEMBER_TYPE_DISK, disk_ids
00638
00639 def _vcr_cap_get(self, mega_sys_path):
00640 cap_output = self._storcli_exec(
00641 [mega_sys_path, "show", "all"])['Capabilities']
00642
00643 mega_raid_types = \
00644 cap_output['RAID Level Supported'].replace(', \n', '').split(', ')
00645
00646 supported_raid_types = []
00647 for cur_mega_raid_type in _RAID_TYPE_MAP.keys():
00648 if cur_mega_raid_type in mega_raid_types:
00649 supported_raid_types.append(
00650 _RAID_TYPE_MAP[cur_mega_raid_type])
00651
00652 supported_raid_types = sorted(list(set(supported_raid_types)))
00653
00654 min_strip_size = _mega_size_to_lsm(cap_output['Min Strip Size'])
00655 max_strip_size = _mega_size_to_lsm(cap_output['Max Strip Size'])
00656
00657 supported_strip_sizes = list(
00658 min_strip_size * (2 ** i)
00659 for i in range(
00660 0, int(math.log(max_strip_size / min_strip_size, 2) + 1)))
00661
00662
00663
00664
00665
00666 return supported_raid_types, supported_strip_sizes
00667
00668 @_handle_errors
00669 def volume_raid_create_cap_get(self, system, flags=Client.FLAG_RSVD):
00670 """
00671 Depend on the 'Capabilities' section of "storcli /c0 show all" output.
00672 """
00673 cur_lsm_syss = list(s for s in self.systems() if s.id == system.id)
00674 if len(cur_lsm_syss) != 1:
00675 raise LsmError(
00676 ErrorNumber.NOT_FOUND_SYSTEM,
00677 "System not found")
00678
00679 lsm_sys = cur_lsm_syss[0]
00680 return self._vcr_cap_get(lsm_sys.plugin_data)
00681
00682 @_handle_errors
00683 def volume_raid_create(self, name, raid_type, disks, strip_size,
00684 flags=Client.FLAG_RSVD):
00685 """
00686 Work flow:
00687 1. Create RAID volume
00688 storcli /c0 add vd RAID10 drives=252:1-4 pdperarray=2 J
00689 2. Find out pool/DG base on one disk.
00690 storcli /c0/e252/s1 show J
00691 3. Find out the volume/VD base on pool/DG using self.volumes()
00692 """
00693 mega_raid_type = _lsm_raid_type_to_mega(raid_type)
00694 ctrl_num = None
00695 slot_nums = []
00696 enclosure_num = None
00697
00698 for disk in disks:
00699 if not disk.plugin_data:
00700 raise LsmError(
00701 ErrorNumber.INVALID_ARGUMENT,
00702 "Illegal input disks argument: missing plugin_data "
00703 "property")
00704
00705 (cur_ctrl_num, cur_enclosure_num, slot_num) = \
00706 disk.plugin_data.split(':')
00707
00708 cur_ctrl_num = int(cur_ctrl_num)
00709 cur_enclosure_num = int(cur_enclosure_num)
00710
00711 if ctrl_num is not None and cur_ctrl_num != ctrl_num:
00712 raise LsmError(
00713 ErrorNumber.INVALID_ARGUMENT,
00714 "Illegal input disks argument: disks are not from the "
00715 "same controller/system.")
00716
00717 if enclosure_num is not None and \
00718 cur_enclosure_num != enclosure_num:
00719 raise LsmError(
00720 ErrorNumber.INVALID_ARGUMENT,
00721 "Illegal input disks argument: disks are not from the "
00722 "same disk enclosure.")
00723
00724 ctrl_num = cur_ctrl_num
00725 enclosure_num = cur_enclosure_num
00726 slot_nums.append(slot_num)
00727
00728
00729 name = re.sub('[^0-9a-zA-Z_\-]+', '', name)[:15]
00730
00731 cmds = [
00732 "/c%s" % ctrl_num, "add", "vd", mega_raid_type,
00733 'size=all', "name=%s" % name,
00734 "drives=%d:%s" % (enclosure_num, ','.join(slot_nums))]
00735
00736 if raid_type == Volume.RAID_TYPE_RAID10 or \
00737 raid_type == Volume.RAID_TYPE_RAID50 or \
00738 raid_type == Volume.RAID_TYPE_RAID60:
00739 cmds.append("pdperarray=%d" % int(len(disks) / 2))
00740
00741 if strip_size != Volume.VCR_STRIP_SIZE_DEFAULT:
00742 cmds.append("strip=%d" % int(strip_size / 1024))
00743
00744 try:
00745 self._storcli_exec(cmds)
00746 except ExecError:
00747 req_disk_ids = [d.id for d in disks]
00748 for cur_disk in self.disks():
00749 if cur_disk.id in req_disk_ids and \
00750 not cur_disk.status & Disk.STATUS_FREE:
00751 raise LsmError(
00752 ErrorNumber.DISK_NOT_FREE,
00753 "Disk %s is not in STATUS_FREE state" % cur_disk.id)
00754
00755 supported_raid_types, supported_strip_sizes = \
00756 self._vcr_cap_get("/c%s" % ctrl_num)
00757
00758 if raid_type not in supported_raid_types:
00759 raise LsmError(
00760 ErrorNumber.NO_SUPPORT,
00761 "Provided 'raid_type' is not supported")
00762
00763 if strip_size != Volume.VCR_STRIP_SIZE_DEFAULT and \
00764 strip_size not in supported_strip_sizes:
00765 raise LsmError(
00766 ErrorNumber.NO_SUPPORT,
00767 "Provided 'strip_size' is not supported")
00768
00769 raise
00770
00771
00772 dg_show_output = self._storcli_exec(
00773 ["/c%s/e%s/s%s" % tuple(disks[0].plugin_data.split(":")), "show"])
00774
00775 dg_id = dg_show_output['Drive Information'][0]['DG']
00776 if dg_id == '-':
00777 raise LsmError(
00778 ErrorNumber.PLUGIN_BUG,
00779 "volume_raid_create(): No error found in output, "
00780 "but RAID is not created: %s" % dg_show_output.items())
00781 else:
00782 dg_id = int(dg_id)
00783
00784 pool_id = _pool_id_of(dg_id, self._sys_id_of_ctrl_num(ctrl_num))
00785
00786 lsm_vols = self.volumes(search_key='pool_id', search_value=pool_id)
00787 if len(lsm_vols) != 1:
00788 raise LsmError(
00789 ErrorNumber.PLUGIN_BUG,
00790 "volume_raid_create(): Got unexpected volume count(not 1) "
00791 "when creating RAID volume")
00792
00793 return lsm_vols[0]