00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 import os
00018 import errno
00019 import re
00020
00021 from lsm import (
00022 IPlugin, Client, Capabilities, VERSION, LsmError, ErrorNumber, uri_parse,
00023 System, Pool, size_human_2_size_bytes, search_property, Volume, Disk)
00024
00025 from lsm.plugin.hpsa.utils import cmd_exec, ExecError, file_read
00026
00027
00028 def _handle_errors(method):
00029 def _wrapper(*args, **kwargs):
00030 try:
00031 return method(*args, **kwargs)
00032 except LsmError:
00033 raise
00034 except KeyError as key_error:
00035 raise LsmError(
00036 ErrorNumber.PLUGIN_BUG,
00037 "Expected key missing from SmartArray hpssacli output:%s" %
00038 key_error)
00039 except ExecError as exec_error:
00040 if 'No controllers detected' in exec_error.stdout:
00041 raise LsmError(
00042 ErrorNumber.NOT_FOUND_SYSTEM,
00043 "No HP SmartArray deteceted by hpssacli.")
00044 else:
00045 raise LsmError(ErrorNumber.PLUGIN_BUG, str(exec_error))
00046 except Exception as common_error:
00047 raise LsmError(
00048 ErrorNumber.PLUGIN_BUG,
00049 "Got unexpected error %s" % common_error)
00050
00051 return _wrapper
00052
00053
00054 def _sys_status_of(hp_ctrl_status):
00055 """
00056 Base on data of "hpssacli ctrl all show status"
00057 """
00058 status_info = ''
00059 status = System.STATUS_UNKNOWN
00060 check_list = [
00061 'Controller Status', 'Cache Status', 'Battery/Capacitor Status']
00062 for key_name in check_list:
00063 if key_name in hp_ctrl_status and hp_ctrl_status[key_name] != 'OK':
00064
00065 status = System.STATUS_OTHER
00066 status_info += hp_ctrl_status[key_name]
00067
00068 if status != System.STATUS_OTHER:
00069 status = System.STATUS_OK
00070
00071 return status, status_info
00072
00073
00074 def _parse_hpssacli_output(output):
00075 """
00076 Got a output string of hpssacli to dictionary(nested).
00077 Skipped these line:
00078 1. Starts with 'Note:'
00079 This is just a message right after controller. We don't neet it
00080 yet.
00081 2. The 'Physical Drives' line.
00082 It should indented after 'Internal Drive Cage' like.
00083 If not ignored, we might got duplication line error.
00084 After ignored, it's phsycial disks will directly stored as
00085 key of 'Internal Drive Cage' dictionary.
00086 """
00087 output_lines = [
00088 l for l in output.split("\n")
00089 if l and not l.startswith('Note:') and
00090 not l.strip() == 'Physical Drives']
00091
00092 data = {}
00093
00094
00095 top_indention_level = sorted(
00096 set(
00097 len(line) - len(line.lstrip())
00098 for line in output_lines))[0]
00099
00100 indent_2_data = {
00101 top_indention_level: data
00102 }
00103
00104 for line_num in range(len(output_lines)):
00105 cur_line = output_lines[line_num]
00106 if cur_line.strip() == 'None attached':
00107 continue
00108 if line_num + 1 == len(output_lines):
00109 nxt_line = ''
00110 else:
00111 nxt_line = output_lines[line_num + 1]
00112
00113 cur_indent_count = len(cur_line) - len(cur_line.lstrip())
00114 nxt_indent_count = len(nxt_line) - len(nxt_line.lstrip())
00115
00116 cur_line_splitted = cur_line.split(": ")
00117 cur_data_pointer = indent_2_data[cur_indent_count]
00118
00119 if nxt_indent_count > cur_indent_count:
00120 nxt_line_splitted = nxt_line.split(": ")
00121 new_data = {}
00122
00123 if cur_line.lstrip() not in cur_data_pointer:
00124 cur_data_pointer[cur_line.lstrip()] = new_data
00125 indent_2_data[nxt_indent_count] = new_data
00126 else:
00127 raise LsmError(
00128 ErrorNumber.PLUGIN_BUG,
00129 "_parse_hpssacli_output(): Found duplicate line %s" %
00130 cur_line)
00131 else:
00132 if len(cur_line_splitted) == 1:
00133 cur_data_pointer[cur_line.lstrip()] = None
00134 else:
00135 cur_data_pointer[cur_line_splitted[0].lstrip()] = \
00136 ": ".join(cur_line_splitted[1:]).strip()
00137 return data
00138
00139
00140 def _hp_size_to_lsm(hp_size):
00141 """
00142 HP Using 'TB, GB, MB, KB' and etc, for LSM, they are 'TiB' and etc.
00143 Return int of block bytes
00144 """
00145 re_regex = re.compile("^([0-9.]+) +([EPTGMK])B")
00146 re_match = re_regex.match(hp_size)
00147 if re_match:
00148 return size_human_2_size_bytes(
00149 "%s%siB" % (re_match.group(1), re_match.group(2)))
00150
00151 raise LsmError(
00152 ErrorNumber.PLUGIN_BUG,
00153 "_hp_size_to_lsm(): Got unexpected HP size string %s" %
00154 hp_size)
00155
00156
00157 def _pool_status_of(hp_array):
00158 """
00159 Return (status, status_info)
00160 """
00161 if hp_array['Status'] == 'OK':
00162 return Pool.STATUS_OK, ''
00163 else:
00164
00165 return Pool.STATUS_OTHER, hp_array['Status']
00166
00167
00168 def _pool_id_of(sys_id, array_name):
00169 return "%s:%s" % (sys_id, array_name.replace(' ', ''))
00170
00171
00172 def _disk_type_of(hp_disk):
00173 disk_interface = hp_disk['Interface Type']
00174 if disk_interface == 'SATA':
00175 return Disk.TYPE_SATA
00176 elif disk_interface == 'Solid State SATA':
00177 return Disk.TYPE_SSD
00178 elif disk_interface == 'SAS':
00179 return Disk.TYPE_SAS
00180
00181 return Disk.TYPE_UNKNOWN
00182
00183
00184 def _disk_status_of(hp_disk, flag_free):
00185
00186 if hp_disk['Status'] == 'OK':
00187 disk_status = Disk.STATUS_OK
00188 else:
00189 disk_status = Disk.STATUS_OTHER
00190
00191 if flag_free:
00192 disk_status |= Disk.STATUS_FREE
00193
00194 return disk_status
00195
00196
00197 _HP_RAID_LEVEL_CONV = {
00198 '0': Volume.RAID_TYPE_RAID0,
00199
00200
00201 '1': Volume.RAID_TYPE_RAID1,
00202 '5': Volume.RAID_TYPE_RAID5,
00203 '6': Volume.RAID_TYPE_RAID6,
00204 '1+0': Volume.RAID_TYPE_RAID10,
00205 '50': Volume.RAID_TYPE_RAID50,
00206 '60': Volume.RAID_TYPE_RAID60,
00207 }
00208
00209
00210 _HP_VENDOR_RAID_LEVELS = ['1adm', '1+0adm']
00211
00212
00213 _LSM_RAID_TYPE_CONV = dict(
00214 zip(_HP_RAID_LEVEL_CONV.values(), _HP_RAID_LEVEL_CONV.keys()))
00215
00216
00217 def _hp_raid_level_to_lsm(hp_ld):
00218 """
00219 Based on this property:
00220 Fault Tolerance: 0/1/5/6/1+0
00221 """
00222 hp_raid_level = hp_ld['Fault Tolerance']
00223
00224 if hp_raid_level in _HP_VENDOR_RAID_LEVELS:
00225 return Volume.RAID_TYPE_OTHER
00226
00227 return _HP_RAID_LEVEL_CONV.get(hp_raid_level, Volume.RAID_TYPE_UNKNOWN)
00228
00229
00230 def _lsm_raid_type_to_hp(raid_type):
00231 try:
00232 return _LSM_RAID_TYPE_CONV[raid_type]
00233 except KeyError:
00234 raise LsmError(
00235 ErrorNumber.NO_SUPPORT,
00236 "Not supported raid type %d" % raid_type)
00237
00238
00239 class SmartArray(IPlugin):
00240 _DEFAULT_BIN_PATHS = [
00241 "/usr/sbin/hpssacli", "/opt/hp/hpssacli/bld/hpssacli"]
00242
00243 def __init__(self):
00244 self._sacli_bin = None
00245
00246 def _find_sacli(self):
00247 """
00248 Try _DEFAULT_MDADM_BIN_PATHS
00249 """
00250 for cur_path in SmartArray._DEFAULT_BIN_PATHS:
00251 if os.path.lexists(cur_path):
00252 self._sacli_bin = cur_path
00253
00254 if not self._sacli_bin:
00255 raise LsmError(
00256 ErrorNumber.INVALID_ARGUMENT,
00257 "SmartArray sacli is not installed correctly")
00258
00259 @_handle_errors
00260 def plugin_register(self, uri, password, timeout, flags=Client.FLAG_RSVD):
00261 if os.geteuid() != 0:
00262 raise LsmError(
00263 ErrorNumber.INVALID_ARGUMENT,
00264 "This plugin requires root privilege both daemon and client")
00265 uri_parsed = uri_parse(uri)
00266 self._sacli_bin = uri_parsed.get('parameters', {}).get('hpssacli')
00267 if not self._sacli_bin:
00268 self._find_sacli()
00269
00270 self._sacli_exec(['version'], flag_convert=False)
00271
00272 @_handle_errors
00273 def plugin_unregister(self, flags=Client.FLAG_RSVD):
00274 pass
00275
00276 @_handle_errors
00277 def job_status(self, job_id, flags=Client.FLAG_RSVD):
00278 raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet")
00279
00280 @_handle_errors
00281 def job_free(self, job_id, flags=Client.FLAG_RSVD):
00282 pass
00283
00284 @_handle_errors
00285 def plugin_info(self, flags=Client.FLAG_RSVD):
00286 return "HP SmartArray Plugin", VERSION
00287
00288 @_handle_errors
00289 def time_out_set(self, ms, flags=Client.FLAG_RSVD):
00290 raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet")
00291
00292 @_handle_errors
00293 def time_out_get(self, flags=Client.FLAG_RSVD):
00294 raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet")
00295
00296 @_handle_errors
00297 def capabilities(self, system, flags=Client.FLAG_RSVD):
00298 cur_lsm_syss = self.systems()
00299 if system.id not in list(s.id for s in cur_lsm_syss):
00300 raise LsmError(
00301 ErrorNumber.NOT_FOUND_SYSTEM,
00302 "System not found")
00303 cap = Capabilities()
00304 cap.set(Capabilities.VOLUMES)
00305 cap.set(Capabilities.DISKS)
00306 cap.set(Capabilities.VOLUME_RAID_INFO)
00307 cap.set(Capabilities.POOL_MEMBER_INFO)
00308 cap.set(Capabilities.VOLUME_RAID_CREATE)
00309 return cap
00310
00311 def _sacli_exec(self, sacli_cmds, flag_convert=True):
00312 """
00313 If flag_convert is True, convert data into dict.
00314 """
00315 sacli_cmds.insert(0, self._sacli_bin)
00316 try:
00317 output = cmd_exec(sacli_cmds)
00318 except OSError as os_error:
00319 if os_error.errno == errno.ENOENT:
00320 raise LsmError(
00321 ErrorNumber.INVALID_ARGUMENT,
00322 "hpssacli binary '%s' is not exist or executable." %
00323 self._sacli_bin)
00324 else:
00325 raise
00326
00327 if flag_convert:
00328 return _parse_hpssacli_output(output)
00329 else:
00330 return output
00331
00332 @_handle_errors
00333 def systems(self, flags=0):
00334 """
00335 Depend on command:
00336 hpssacli ctrl all show detail
00337 hpssacli ctrl all show status
00338 """
00339 rc_lsm_syss = []
00340 ctrl_all_show = self._sacli_exec(
00341 ["ctrl", "all", "show", "detail"])
00342 ctrl_all_status = self._sacli_exec(
00343 ["ctrl", "all", "show", "status"])
00344
00345 for ctrl_name in ctrl_all_show.keys():
00346 ctrl_data = ctrl_all_show[ctrl_name]
00347 sys_id = ctrl_data['Serial Number']
00348 (status, status_info) = _sys_status_of(ctrl_all_status[ctrl_name])
00349
00350 plugin_data = "%s" % ctrl_data['Slot']
00351
00352 rc_lsm_syss.append(
00353 System(sys_id, ctrl_name, status, status_info, plugin_data))
00354
00355 return rc_lsm_syss
00356
00357 @staticmethod
00358 def _hp_array_to_lsm_pool(hp_array, array_name, sys_id, ctrl_num):
00359 pool_id = _pool_id_of(sys_id, array_name)
00360 name = array_name
00361 elem_type = Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_VOLUME_FULL
00362 unsupported_actions = 0
00363
00364 free_space = _hp_size_to_lsm(hp_array['Unused Space'])
00365 total_space = free_space
00366 for key_name in hp_array.keys():
00367 if key_name.startswith('Logical Drive'):
00368 total_space += _hp_size_to_lsm(hp_array[key_name]['Size'])
00369
00370 (status, status_info) = _pool_status_of(hp_array)
00371
00372 plugin_data = "%s:%s" % (
00373 ctrl_num, array_name[len("Array: "):])
00374
00375 return Pool(
00376 pool_id, name, elem_type, unsupported_actions,
00377 total_space, free_space, status, status_info,
00378 sys_id, plugin_data)
00379
00380 @_handle_errors
00381 def pools(self, search_key=None, search_value=None,
00382 flags=Client.FLAG_RSVD):
00383 """
00384 Depend on command:
00385 hpssacli ctrl all show config detail
00386 """
00387 lsm_pools = []
00388 ctrl_all_conf = self._sacli_exec(
00389 ["ctrl", "all", "show", "config", "detail"])
00390 for ctrl_data in ctrl_all_conf.values():
00391 sys_id = ctrl_data['Serial Number']
00392 ctrl_num = ctrl_data['Slot']
00393 for key_name in ctrl_data.keys():
00394 if key_name.startswith("Array:"):
00395 lsm_pools.append(
00396 SmartArray._hp_array_to_lsm_pool(
00397 ctrl_data[key_name], key_name, sys_id, ctrl_num))
00398
00399 return search_property(lsm_pools, search_key, search_value)
00400
00401 @staticmethod
00402 def _hp_ld_to_lsm_vol(hp_ld, pool_id, sys_id, ctrl_num, array_num,
00403 hp_ld_name):
00404 ld_num = hp_ld_name[len("Logical Drive: "):]
00405 vpd83 = hp_ld['Unique Identifier'].lower()
00406
00407
00408
00409 regex_match = re.compile("/dev/(sd[a-z]+)").search(hp_ld['Disk Name'])
00410 vol_name = hp_ld_name
00411 if regex_match:
00412 sd_name = regex_match.group(1)
00413 block_size = int(file_read(
00414 "/sys/block/%s/queue/logical_block_size" % sd_name))
00415 num_of_blocks = int(file_read("/sys/block/%s/size" % sd_name))
00416 vol_name += ": /dev/%s" % sd_name
00417 else:
00418 block_size = 512
00419 num_of_blocks = int(_hp_size_to_lsm(hp_ld['Size']) / block_size)
00420
00421 plugin_data = "%s:%s:%s" % (ctrl_num, array_num, ld_num)
00422
00423
00424 return Volume(
00425 vpd83, vol_name, vpd83, block_size, num_of_blocks,
00426 Volume.ADMIN_STATE_ENABLED, sys_id, pool_id, plugin_data)
00427
00428 @_handle_errors
00429 def volumes(self, search_key=None, search_value=None,
00430 flags=Client.FLAG_RSVD):
00431 """
00432 Depend on command:
00433 hpssacli ctrl all show config detail
00434 """
00435 lsm_vols = []
00436 ctrl_all_conf = self._sacli_exec(
00437 ["ctrl", "all", "show", "config", "detail"])
00438 for ctrl_data in ctrl_all_conf.values():
00439 ctrl_num = ctrl_data['Slot']
00440 sys_id = ctrl_data['Serial Number']
00441 for key_name in ctrl_data.keys():
00442 if not key_name.startswith("Array:"):
00443 continue
00444 pool_id = _pool_id_of(sys_id, key_name)
00445 array_num = key_name[len('Array: '):]
00446 for array_key_name in ctrl_data[key_name].keys():
00447 if not array_key_name.startswith("Logical Drive"):
00448 continue
00449 lsm_vols.append(
00450 SmartArray._hp_ld_to_lsm_vol(
00451 ctrl_data[key_name][array_key_name],
00452 pool_id, sys_id, ctrl_num, array_num,
00453 array_key_name))
00454
00455 return search_property(lsm_vols, search_key, search_value)
00456
00457 @staticmethod
00458 def _hp_disk_to_lsm_disk(hp_disk, sys_id, ctrl_num, key_name,
00459 flag_free=False):
00460 disk_id = hp_disk['Serial Number']
00461 disk_num = key_name[len("physicaldrive "):]
00462 disk_name = "%s %s" % (hp_disk['Model'], disk_num)
00463 disk_type = _disk_type_of(hp_disk)
00464 blk_size = int(hp_disk['Native Block Size'])
00465 blk_count = int(_hp_size_to_lsm(hp_disk['Size']) / blk_size)
00466 status = _disk_status_of(hp_disk, flag_free)
00467 plugin_data = "%s:%s" % (ctrl_num, disk_num)
00468
00469 return Disk(
00470 disk_id, disk_name, disk_type, blk_size, blk_count,
00471 status, sys_id, plugin_data)
00472
00473 @_handle_errors
00474 def disks(self, search_key=None, search_value=None,
00475 flags=Client.FLAG_RSVD):
00476 """
00477 Depend on command:
00478 hpssacli ctrl all show config detail
00479 """
00480
00481 rc_lsm_disks = []
00482 ctrl_all_conf = self._sacli_exec(
00483 ["ctrl", "all", "show", "config", "detail"])
00484 for ctrl_data in ctrl_all_conf.values():
00485 sys_id = ctrl_data['Serial Number']
00486 ctrl_num = ctrl_data['Slot']
00487 for key_name in ctrl_data.keys():
00488 if key_name.startswith("Array:"):
00489 for array_key_name in ctrl_data[key_name].keys():
00490 if array_key_name.startswith("physicaldrive"):
00491 rc_lsm_disks.append(
00492 SmartArray._hp_disk_to_lsm_disk(
00493 ctrl_data[key_name][array_key_name],
00494 sys_id, ctrl_num, array_key_name,
00495 flag_free=False))
00496
00497 if key_name == 'unassigned':
00498 for array_key_name in ctrl_data[key_name].keys():
00499 if array_key_name.startswith("physicaldrive"):
00500 rc_lsm_disks.append(
00501 SmartArray._hp_disk_to_lsm_disk(
00502 ctrl_data[key_name][array_key_name],
00503 sys_id, ctrl_num, array_key_name,
00504 flag_free=True))
00505
00506 return search_property(rc_lsm_disks, search_key, search_value)
00507
00508 @_handle_errors
00509 def volume_raid_info(self, volume, flags=Client.FLAG_RSVD):
00510 """
00511 Depend on command:
00512 hpssacli ctrl slot=0 show config detail
00513 """
00514 if not volume.plugin_data:
00515 raise LsmError(
00516 ErrorNumber.INVALID_ARGUMENT,
00517 "Ilegal input volume argument: missing plugin_data property")
00518
00519 (ctrl_num, array_num, ld_num) = volume.plugin_data.split(":")
00520 ctrl_data = self._sacli_exec(
00521 ["ctrl", "slot=%s" % ctrl_num, "show", "config", "detail"]
00522 ).values()[0]
00523
00524 disk_count = 0
00525 strip_size = Volume.STRIP_SIZE_UNKNOWN
00526 stripe_size = Volume.OPT_IO_SIZE_UNKNOWN
00527 raid_type = Volume.RAID_TYPE_UNKNOWN
00528 for key_name in ctrl_data.keys():
00529 if key_name != "Array: %s" % array_num:
00530 continue
00531 for array_key_name in ctrl_data[key_name].keys():
00532 if array_key_name == "Logical Drive: %s" % ld_num:
00533 hp_ld = ctrl_data[key_name][array_key_name]
00534 raid_type = _hp_raid_level_to_lsm(hp_ld)
00535 strip_size = _hp_size_to_lsm(hp_ld['Strip Size'])
00536 stripe_size = _hp_size_to_lsm(hp_ld['Full Stripe Size'])
00537 elif array_key_name.startswith("physicaldrive"):
00538 hp_disk = ctrl_data[key_name][array_key_name]
00539 if hp_disk['Drive Type'] == 'Data Drive':
00540 disk_count += 1
00541
00542 if disk_count == 0:
00543 if strip_size == Volume.STRIP_SIZE_UNKNOWN:
00544 raise LsmError(
00545 ErrorNumber.PLUGIN_BUG,
00546 "volume_raid_info(): Got logical drive %s entry, " %
00547 ld_num + "but no physicaldrive entry: %s" %
00548 ctrl_data.items())
00549
00550 raise LsmError(
00551 ErrorNumber.NOT_FOUND_VOLUME,
00552 "Volume not found")
00553
00554 return [raid_type, strip_size, disk_count, strip_size, stripe_size]
00555
00556 @_handle_errors
00557 def pool_member_info(self, pool, flags=Client.FLAG_RSVD):
00558 """
00559 Depend on command:
00560 hpssacli ctrl slot=0 show config detail
00561 """
00562 if not pool.plugin_data:
00563 raise LsmError(
00564 ErrorNumber.INVALID_ARGUMENT,
00565 "Ilegal input volume argument: missing plugin_data property")
00566
00567 (ctrl_num, array_num) = pool.plugin_data.split(":")
00568 ctrl_data = self._sacli_exec(
00569 ["ctrl", "slot=%s" % ctrl_num, "show", "config", "detail"]
00570 ).values()[0]
00571
00572 disk_ids = []
00573 raid_type = Volume.RAID_TYPE_UNKNOWN
00574 for key_name in ctrl_data.keys():
00575 if key_name == "Array: %s" % array_num:
00576 for array_key_name in ctrl_data[key_name].keys():
00577 if array_key_name.startswith("Logical Drive: ") and \
00578 raid_type == Volume.RAID_TYPE_UNKNOWN:
00579 raid_type = _hp_raid_level_to_lsm(
00580 ctrl_data[key_name][array_key_name])
00581 elif array_key_name.startswith("physicaldrive"):
00582 hp_disk = ctrl_data[key_name][array_key_name]
00583 if hp_disk['Drive Type'] == 'Data Drive':
00584 disk_ids.append(hp_disk['Serial Number'])
00585 break
00586
00587 if len(disk_ids) == 0:
00588 raise LsmError(
00589 ErrorNumber.NOT_FOUND_POOL,
00590 "Pool not found")
00591
00592 return raid_type, Pool.MEMBER_TYPE_DISK, disk_ids
00593
00594 def _vrc_cap_get(self, ctrl_num):
00595 supported_raid_types = [
00596 Volume.RAID_TYPE_RAID0, Volume.RAID_TYPE_RAID1,
00597 Volume.RAID_TYPE_RAID5, Volume.RAID_TYPE_RAID50,
00598 Volume.RAID_TYPE_RAID10]
00599
00600 supported_strip_sizes = [
00601 8 * 1024, 16 * 1024, 32 * 1024, 64 * 1024,
00602 128 * 1024, 256 * 1024, 512 * 1024, 1024 * 1024]
00603
00604 ctrl_conf = self._sacli_exec([
00605 "ctrl", "slot=%s" % ctrl_num, "show", "config", "detail"]
00606 ).values()[0]
00607
00608 if 'RAID 6 (ADG) Status' in ctrl_conf and \
00609 ctrl_conf['RAID 6 (ADG) Status'] == 'Enabled':
00610 supported_raid_types.extend(
00611 [Volume.RAID_TYPE_RAID6, Volume.RAID_TYPE_RAID60])
00612
00613 return supported_raid_types, supported_strip_sizes
00614
00615 @_handle_errors
00616 def volume_raid_create_cap_get(self, system, flags=Client.FLAG_RSVD):
00617 """
00618 Depends on this command:
00619 hpssacli ctrl slot=0 show config detail
00620 All hpsa support RAID 1, 10, 5, 50.
00621 If "RAID 6 (ADG) Status: Enabled", it will support RAID 6 and 60.
00622 For HP tribile mirror(RAID 1adm and RAID10adm), LSM does support
00623 that yet.
00624 No command output or document indication special or exceptional
00625 support of strip size, assuming all hpsa cards support documented
00626 strip sizes.
00627 """
00628 if not system.plugin_data:
00629 raise LsmError(
00630 ErrorNumber.INVALID_ARGUMENT,
00631 "Ilegal input system argument: missing plugin_data property")
00632 return self._vrc_cap_get(system.plugin_data)
00633
00634 @_handle_errors
00635 def volume_raid_create(self, name, raid_type, disks, strip_size,
00636 flags=Client.FLAG_RSVD):
00637 """
00638 Depends on these commands:
00639 1. Create LD
00640 hpssacli ctrl slot=0 create type=ld \
00641 drives=1i:1:13,1i:1:14 size=max raid=1+0 ss=64
00642
00643 2. Find out the system ID.
00644
00645 3. Find out the pool fist disk belong.
00646 hpssacli ctrl slot=0 pd 1i:1:13 show
00647
00648 4. List all volumes for this new pool.
00649 self.volumes(search_key='pool_id', search_value=pool_id)
00650
00651 The 'name' argument will be ignored.
00652 TODO(Gris Ge): These code only tested for creating 1 disk RAID 0.
00653 """
00654 hp_raid_level = _lsm_raid_type_to_hp(raid_type)
00655 hp_disk_ids = []
00656 ctrl_num = None
00657 for disk in disks:
00658 if not disk.plugin_data:
00659 raise LsmError(
00660 ErrorNumber.INVALID_ARGUMENT,
00661 "Illegal input disks argument: missing plugin_data "
00662 "property")
00663 (cur_ctrl_num, hp_disk_id) = disk.plugin_data.split(':', 1)
00664 if ctrl_num and cur_ctrl_num != ctrl_num:
00665 raise LsmError(
00666 ErrorNumber.INVALID_ARGUMENT,
00667 "Illegal input disks argument: disks are not from the "
00668 "same controller/system.")
00669
00670 ctrl_num = cur_ctrl_num
00671 hp_disk_ids.append(hp_disk_id)
00672
00673 cmds = [
00674 "ctrl", "slot=%s" % ctrl_num, "create", "type=ld",
00675 "drives=%s" % ','.join(hp_disk_ids), 'size=max',
00676 'raid=%s' % hp_raid_level]
00677
00678 if strip_size != Volume.VCR_STRIP_SIZE_DEFAULT:
00679 cmds.append("ss=%d" % int(strip_size / 1024))
00680
00681 try:
00682 self._sacli_exec(cmds, flag_convert=False)
00683 except ExecError:
00684
00685 requested_disk_ids = [d.id for d in disks]
00686 for cur_disk in self.disks():
00687 if cur_disk.id in requested_disk_ids and \
00688 not cur_disk.status & Disk.STATUS_FREE:
00689 raise LsmError(
00690 ErrorNumber.DISK_NOT_FREE,
00691 "Disk %s is not in STATUS_FREE state" % cur_disk.id)
00692
00693
00694 supported_raid_types, supported_strip_sizes = \
00695 self._vrc_cap_get(ctrl_num)
00696
00697 if raid_type not in supported_raid_types:
00698 raise LsmError(
00699 ErrorNumber.NO_SUPPORT,
00700 "Provided raid_type is not supported")
00701
00702 if strip_size != Volume.VCR_STRIP_SIZE_DEFAULT and \
00703 strip_size not in supported_strip_sizes:
00704 raise LsmError(
00705 ErrorNumber.NO_SUPPORT,
00706 "Provided strip_size is not supported")
00707
00708 raise
00709
00710
00711 sys_output = self._sacli_exec(
00712 ['ctrl', "slot=%s" % ctrl_num, 'show'])
00713
00714 sys_id = sys_output.values()[0]['Serial Number']
00715
00716
00717
00718 pd_output = self._sacli_exec(
00719 ['ctrl', "slot=%s" % ctrl_num, 'pd', hp_disk_ids[0], 'show'])
00720
00721 if pd_output.values()[0].keys()[0].lower().startswith("array "):
00722 hp_array_id = pd_output.values()[0].keys()[0][len("array "):]
00723 hp_array_id = "Array:%s" % hp_array_id
00724 else:
00725 raise LsmError(
00726 ErrorNumber.PLUGIN_BUG,
00727 "volume_raid_create(): Failed to find out the array ID of "
00728 "new array: %s" % pd_output.items())
00729
00730 pool_id = _pool_id_of(sys_id, hp_array_id)
00731
00732 lsm_vols = self.volumes(search_key='pool_id', search_value=pool_id)
00733
00734 if len(lsm_vols) != 1:
00735 raise LsmError(
00736 ErrorNumber.PLUGIN_BUG,
00737 "volume_raid_create(): Got unexpected count(not 1) of new "
00738 "volumes: %s" % lsm_vols)
00739 return lsm_vols[0]