Hi Gris, Nice work!
Notes: so far from taking a clean git repo and applying this patch and running on a box I got access too (not your box): * autogen.sh fails, plugin/hpsa/Makefile.am:1: error: WITH_HPSA does not appear in AM_CONDITIONAL. I commented that part out to get by, need add to configure.ac * The debug prints make for lots of output :-) * My config must be slightly different from yours? # ./hpsa_lsmplugin --uri hpsa:// list --type systems [('Smart Array P410i in Slot 0 (Embedded)', {'Slot': '0', 'Driver Name': 'hpsa', 'SATA NCQ Supported': 'True', 'RAID 6 (ADG) Status': 'Disabled', 'Expand Priority': 'Medium', 'Surface Scan Delay': '15 secs', 'Drive Write Cache': 'Disabled', 'Cache Board Present': 'False', 'Post Prompt Timeout': '0 secs', 'Total Cache Size': '0 MB', 'Surface Scan Mode': 'Idle', 'Hardware Revision': 'C', 'Serial Number': '50014380100A1560', 'Bus Interface': 'PCI', 'Controller Status': 'OK', 'Driver Supports HP SSD Smart Path': 'False', 'Encryption Supported': 'False', 'Number of Ports': '2 Internal only', 'Rebuild Priority': 'Medium', 'Firmware Version': '5.02', 'Surface Analysis Inconsistency Notification': 'Disabled', 'Wait for Cache Room': 'Disabled', 'Driver Version': '3.4.2'})] [('Smart Array P410i in Slot 0 (Embedded)', {'Controller Status': 'OK'})] PLUGIN_BUG(2): Expected key missing from SmartArray hpssacli output:'Cache Status' My card does not have 'Cache Status' and 'Battery/Capacitor Status' * volumes, volume-raid-info, pools worked * Capabilities failed just like list --type systems, but I see in the code that the capability for volume raid info is missing * I'm getting an 'UNKNOWN' raid type for my config, => 'Fault Tolerance': '1' * What about doing this to accommodate card differences? diff --git a/plugin/hpsa/hpsa.py b/plugin/hpsa/hpsa.py index cfb176c..8c0297e 100644 --- a/plugin/hpsa/hpsa.py +++ b/plugin/hpsa/hpsa.py @@ -281,10 +281,11 @@ class SmartArray(IPlugin): check_list = [ 'Controller Status', 'Cache Status', 'Battery/Capacitor Status'] for key_name in check_list: - if ctrl_status[key_name] != 'OK': - # TODO(Gris Ge): Beg HP for possible values - status = System.STATUS_OTHER - status_info += ctrl_status[key_name] + if key_name in ctrl_status: + if ctrl_status[key_name] != 'OK': + # TODO(Gris Ge): Beg HP for possible values + status = System.STATUS_OTHER + status_info += ctrl_status[key_name] if status != System.STATUS_OTHER: status = System.STATUS_OK Thanks! -Tony On 03/12/2015 11:37 AM, Gris Ge wrote: > * Do not commit. This is just a demo. > > * With support of: > * systems() > * pools() > * volumes() > * disks() with Disk.STATUS_FREE > * volume_raid_info() > > * A lot of TODOs in code. I am seeking a hpsa server with a lot of disks.[1] > > [1] If anyone have a server with faulty disk or spare disk, > please email me the output of 'hpssacli show config detail'. > > Patches is based on: > [PATCH V2 0/7] Add new disk status: STATUS_FREE > > Signed-off-by: Gris Ge <f...@redhat.com> > --- > config/pluginconf.d/hpsa.conf | 1 + > configure.ac | 11 + > plugin/hpsa/Makefile.am | 8 + > plugin/hpsa/__init__.py | 1 + > plugin/hpsa/hpsa.py | 523 > ++++++++++++++++++++++++++++++++++++++++++ > plugin/hpsa/hpsa_lsmplugin | 37 +++ > plugin/hpsa/utils.py | 55 +++++ > 7 files changed, 636 insertions(+) > create mode 100644 config/pluginconf.d/hpsa.conf > create mode 100644 plugin/hpsa/Makefile.am > create mode 100644 plugin/hpsa/__init__.py > create mode 100644 plugin/hpsa/hpsa.py > create mode 100755 plugin/hpsa/hpsa_lsmplugin > create mode 100644 plugin/hpsa/utils.py > > diff --git a/config/pluginconf.d/hpsa.conf b/config/pluginconf.d/hpsa.conf > new file mode 100644 > index 0000000..35b52d4 > --- /dev/null > +++ b/config/pluginconf.d/hpsa.conf > @@ -0,0 +1 @@ > +require-root-privilege = true; > diff --git a/configure.ac b/configure.ac > index 74e6811..56a4fba 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -190,6 +190,16 @@ AC_ARG_WITH([megaraid], > [], > [with_megaraid=yes]) > > +dnl > ========================================================================== > +dnl Add option '--without-hpsa' to exclude hpsa plugin. > +dnl > ========================================================================== > + > +AC_ARG_WITH([hpsa], > + [AS_HELP_STRING([--without-hpsa], > + [Do not build the HP SmartArray plugin])], > + [], > + [with_hpsa=yes]) > + > AM_CONDITIONAL([WITH_MEGARAID], [test "x$with_megaraid" = "xyes"]) > > dnl > ========================================================================== > @@ -221,6 +231,7 @@ AC_OUTPUT(libstoragemgmt.pc \ > plugin/Makefile \ > plugin/simc/Makefile \ > plugin/megaraid/Makefile \ > + plugin/hpsa/Makefile \ > daemon/Makefile \ > config/Makefile \ > doc/Makefile \ > diff --git a/plugin/hpsa/Makefile.am b/plugin/hpsa/Makefile.am > new file mode 100644 > index 0000000..3076cbc > --- /dev/null > +++ b/plugin/hpsa/Makefile.am > @@ -0,0 +1,8 @@ > +if WITH_HPSA > +plugindir = $(pythondir)/lsm/plugin > +hpsadir = $(plugindir)/hpsa > + > +hpsa_PYTHON = __init__.py hpsa.py utils.py > + > +dist_bin_SCRIPTS= hpsa_lsmplugin > +endif > diff --git a/plugin/hpsa/__init__.py b/plugin/hpsa/__init__.py > new file mode 100644 > index 0000000..61332b4 > --- /dev/null > +++ b/plugin/hpsa/__init__.py > @@ -0,0 +1 @@ > +from lsm.plugin.hpsa.hpsa import SmartArray > diff --git a/plugin/hpsa/hpsa.py b/plugin/hpsa/hpsa.py > new file mode 100644 > index 0000000..cfb176c > --- /dev/null > +++ b/plugin/hpsa/hpsa.py > @@ -0,0 +1,523 @@ > +# Copyright (C) 2015 Red Hat, Inc. > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or any later version. > +# > +# This library is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > +# > +# Author: Gris Ge <f...@redhat.com> > + > +import os > +from string import strip > +import re > +import errno > + > +from lsm import (uri_parse, search_property, size_human_2_size_bytes, > + Capabilities, LsmError, ErrorNumber, System, Client, > + Disk, VERSION, search_property, IPlugin, Pool, Volume) > + > +from lsm.plugin.hpsa.utils import cmd_exec, ExecError, file_read > + > +# Naming scheme > + > + > +def _handle_errors(method): > + def _wrapper(*args, **kwargs): > + try: > + return method(*args, **kwargs) > + except LsmError: > + raise > + except KeyError as key_error: > + raise LsmError( > + ErrorNumber.PLUGIN_BUG, > + "Expected key missing from SmartArray hpssacli output:%s" % > + key_error) > + except ExecError as exec_error: > + raise LsmError(ErrorNumber.PLUGIN_BUG, str(exec_error)) > + except Exception as common_error: > + raise LsmError( > + ErrorNumber.PLUGIN_BUG, > + "Got unexpected error %s" % common_error) > + > + return _wrapper > + > + > +def _disk_type_of(hp_disk): > + disk_interface = hp_disk['Interface Type'] > + if disk_interface == 'SATA': > + return Disk.TYPE_SATA > + elif disk_interface == 'Solid State SATA': > + return Disk.TYPE_SSD > + elif disk_interface == 'SAS': > + return Disk.TYPE_SAS > + > + return Disk.TYPE_UNKNOWN > + > + > +def _disk_status_of(hp_disk, flag_free): > + # TODO(Gris Ge): Need more document or test for non-OK disks. > + if hp_disk['Status'] == 'OK': > + disk_status = Disk.STATUS_OK > + else: > + disk_status = Disk.STATUS_OTHER > + > + if flag_free: > + disk_status |= Disk.STATUS_FREE > + > + return disk_status > + > + > +def _hp_size_to_lsm(hp_size): > + """ > + HP Using 'TB, GB, MB, KB' and etc, for LSM, they are 'TiB' and etc. > + Return int of block bytes > + """ > + re_regex = re.compile("^([0-9\.]+) +([EPTGMK])B$") > + re_match = re_regex.match(hp_size) > + if re_match: > + return size_human_2_size_bytes( > + "%s%siB" % (re_match.group(1), re_match.group(2))) > + > + raise LsmError( > + ErrorNumber.PLUGIN_BUG, > + "_hp_size_to_lsm(): Got unexpected HP size string %s" % > + hp_size) > + > + > +def _pool_status_of(hp_array): > + """ > + Return (status, status_info) > + """ > + if hp_array['Status'] == 'OK': > + return Pool.STATUS_OK, '' > + else: > + # TODO(Gris Ge): Try degrade a RAID or fail a RAID. > + return Pool.STATUS_OTHER, hp_array['Status'] > + > + > +def _pool_id_of(sys_id, array_name): > + return "%s:%s" % (sys_id, array_name.replace(' ', '')) > + > + > +def _hp_raid_type_to_lsm(hp_ld): > + """ > + Based on this property: > + Fault Tolerance: 0/5/6/1+0 > + """ > + hp_raid_level = hp_ld['Fault Tolerance'] > + if hp_raid_level == '0': > + return Volume.RAID_TYPE_RAID0 > + elif hp_raid_level == '5': > + return Volume.RAID_TYPE_RAID5 > + elif hp_raid_level == '6': > + return Volume.RAID_TYPE_RAID6 > + elif hp_raid_level == '1+0': > + return Volume.RAID_TYPE_RAID10 > + > + return Volume.RAID_TYPE_UNKNOWN > + > + > +def _parse_hpssacli_output(output): > + """ > + Got a output string of hpssacli to dictionary(nested). > + """ > + output_lines = [ l for l in output.split("\n") if l ] > + > + data = {} > + > + # Detemine indention level > + top_indention_level= sorted( > + set( > + len(line) - len(line.lstrip()) > + for line in output_lines))[0] > + > + indent_2_data = { > + top_indention_level: data > + } > + > + for line_num in range(len(output_lines)): > + cur_line = output_lines[line_num] > + if cur_line.strip() == 'None attached': > + continue > + if line_num + 1 == len(output_lines): > + nxt_line = '' > + else: > + nxt_line = output_lines[line_num + 1] > + > + cur_indent_count = len(cur_line) - len(cur_line.lstrip()) > + nxt_indent_count = len(nxt_line) - len(nxt_line.lstrip()) > + > + cur_line_splitted = cur_line.split(": ") > + cur_data_pointer = indent_2_data[cur_indent_count] > + > + if nxt_indent_count > cur_indent_count: > + nxt_line_splitted = nxt_line.split(": ") > + if len(nxt_line_splitted) == 1: > + new_data = [] > + else: > + new_data = {} > + > + if cur_line.lstrip() not in cur_data_pointer: > + cur_data_pointer[cur_line.lstrip()] = new_data > + indent_2_data[nxt_indent_count] = new_data > + elif type(cur_data_pointer[cur_line.lstrip()]) != type(new_data): > + raise LsmError( > + ErrorNumber.PLUGIN_BUG, > + "_parse_hpssacli_output(): Unexpected line '%s%s\n'" % > + cur_line, nxt_line) > + else: > + if len(cur_line_splitted) == 1: > + if type(indent_2_data[cur_indent_count]) != list: > + raise Exception("not a list: '%s'" % cur_line) > + cur_data_pointer.append(cur_line.lstrip()) > + else: > + cur_data_pointer[cur_line_splitted[0].lstrip()] = \ > + ": ".join(cur_line_splitted[1:]).strip() > + return data > + > + > +class SmartArray(IPlugin): > + _DEFAULT_BIN_PATHS = [ > + "/usr/sbin/hpssacli", "/opt/hp/hpssacli/bld/hpssacli"] > + > + def __init__(self): > + self._sacli_bin = None > + > + def _find_sacli(self): > + """ > + Try _DEFAULT_MDADM_BIN_PATHS > + """ > + for cur_path in SmartArray._DEFAULT_BIN_PATHS: > + if os.path.lexists(cur_path): > + self._sacli_bin = cur_path > + > + if not self._sacli_bin: > + raise LsmError( > + ErrorNumber.INVALID_ARGUMENT, > + "SmartArray sacli is not installed correctly") > + > + @_handle_errors > + def plugin_register(self, uri, password, timeout, > flags=Client.FLAG_RSVD): > + if os.geteuid() != 0: > + raise LsmError( > + ErrorNumber.INVALID_ARGUMENT, > + "This plugin requires root privilege both daemon and client") > + uri_parsed = uri_parse(uri) > + self._sacli_bin = uri_parsed.get('parameters', {}).get('sacli') > + if not self._sacli_bin: > + self._find_sacli() > + > + self._sacli_exec(['version'], flag_convert=False) > + > + @_handle_errors > + def plugin_unregister(self, flags=Client.FLAG_RSVD): > + pass > + > + @_handle_errors > + def job_status(self, job_id, flags=Client.FLAG_RSVD): > + raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet") > + > + @_handle_errors > + def job_free(self, job_id, flags=Client.FLAG_RSVD): > + pass > + > + @_handle_errors > + def plugin_info(self, flags=Client.FLAG_RSVD): > + return "LSI SmartArray Plugin", VERSION > + > + @_handle_errors > + def time_out_set(self, ms, flags=Client.FLAG_RSVD): > + raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet") > + > + @_handle_errors > + def time_out_get(self, flags=Client.FLAG_RSVD): > + raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported yet") > + > + @_handle_errors > + def capabilities(self, system, flags=Client.FLAG_RSVD): > + cur_lsm_syss = self.systems() > + if system.id not in list(s.id for s in cur_lsm_syss): > + raise LsmError( > + ErrorNumber.NOT_FOUND_SYSTEM, > + "System not found") > + cap = Capabilities() > + cap.set(Capabilities.DISKS) > + cap.set(Capabilities.VOLUMES) > + return cap > + > + def _sacli_exec(self, sacli_cmds, flag_convert=True): > + """ > + If flag_convert is True, convert data into dict. > + """ > + sacli_cmds.insert(0, self._sacli_bin) > + try: > + output = cmd_exec(sacli_cmds) > + except OSError as os_error: > + if os_error.errno == errno.ENOENT: > + raise LsmError( > + ErrorNumber.INVALID_ARGUMENT, > + "hpssacli binary '%s' is not exist or executable." % > + self._sacli_bin) > + else: > + raise > + > + if flag_convert: > + return _parse_hpssacli_output(output) > + else: > + return output > + > + @staticmethod > + def _lsm_status_of_ctrl(ctrl_status): > + status_info = '' > + status = System.STATUS_UNKNOWN > + check_list = [ > + 'Controller Status', 'Cache Status', 'Battery/Capacitor Status'] > + for key_name in check_list: > + if ctrl_status[key_name] != 'OK': > + # TODO(Gris Ge): Beg HP for possible values > + status = System.STATUS_OTHER > + status_info += ctrl_status[key_name] > + if status != System.STATUS_OTHER: > + status = System.STATUS_OK > + > + return status, status_info > + > + def _sys_id_of_ctrl_num(self, ctrl_num, ctrl_show_all_output=None): > + if ctrl_show_all_output is None: > + return self._sacli_exec( > + ["/c%d" % ctrl_num, "show"])['Serial Number'] > + else: > + return ctrl_show_all_output['Basics']['Serial Number'] > + > + @_handle_errors > + def systems(self, flags=0): > + """ > + Depend on command: > + hpssacli ctrl all show detail > + hpssacli ctrl all show status > + """ > + rc_lsm_syss = [] > + ctrl_all_show = self._sacli_exec( > + ["ctrl", "all", "show", "detail"]) > + ctrl_all_status = self._sacli_exec( > + ["ctrl", "all", "show", "status"]) > + print ctrl_all_show.items() > + print ctrl_all_status.items() > + > + for ctrl_name in ctrl_all_show.keys(): > + ctrl_data = ctrl_all_show[ctrl_name] > + sys_id = ctrl_data['Serial Number'] > + (status, status_info) = SmartArray._lsm_status_of_ctrl( > + ctrl_all_status[ctrl_name]) > + > + plugin_data = "%s" % ctrl_data['Slot'] > + > + rc_lsm_syss.append( > + System(sys_id, ctrl_name, status, status_info, plugin_data)) > + > + return rc_lsm_syss > + > + @staticmethod > + def _hp_disk_to_lsm_disk(hp_disk, sys_id, ctrl_num, key_name, > + flag_free=False): > + disk_id = hp_disk['Serial Number'] > + disk_num = key_name[len("physicaldrive "):] > + disk_name = "%s %s" % (hp_disk['Model'], disk_num) > + disk_type = _disk_type_of(hp_disk) > + blk_size = int(hp_disk['Native Block Size']) > + blk_count = int(_hp_size_to_lsm(hp_disk['Size']) / blk_size) > + status = _disk_status_of(hp_disk, flag_free) > + plugin_data = "%s:%s" % (ctrl_num, disk_num) > + > + return Disk( > + disk_id, disk_name, disk_type, blk_size, blk_count, > + status, sys_id, plugin_data) > + > + @_handle_errors > + def disks(self, search_key=None, search_value=None, > + flags=Client.FLAG_RSVD): > + """ > + Depend on command: > + hpssacli ctrl all show config detail > + """ > + # TODO(Gris Ge): Need real test on spare disk and free disk. > + # The free disks is purely base on HP document. > + rc_lsm_disks = [] > + ctrl_all_conf = self._sacli_exec( > + ["ctrl", "all", "show", "config", "detail"]) > + for ctrl_data in ctrl_all_conf.values(): > + sys_id = ctrl_data['Serial Number'] > + ctrl_num = ctrl_data['Slot'] > + for key_name in ctrl_data.keys(): > + if key_name.startswith("Array:"): > + for array_key_name in ctrl_data[key_name].keys(): > + if array_key_name.startswith("physicaldrive"): > + rc_lsm_disks.append( > + SmartArray._hp_disk_to_lsm_disk( > + ctrl_data[key_name][array_key_name], > + sys_id, ctrl_num, array_key_name, > + flag_free=False)) > + > + if key_name == 'unassigned': > + for array_key_name in ctrl_data[key_name].keys(): > + if array_key_name.startswith("physicaldrive"): > + rc_lsm_disks.append( > + SmartArray._hp_disk_to_lsm_disk( > + ctrl_data[key_name][array_key_name], > + sys_id, ctrl_num, array_key_name, > + flag_free=False)) > + > + return search_property(rc_lsm_disks, search_key, search_value) > + > + def _hp_array_to_lsm_pool(self, hp_array, array_name, sys_id, ctrl_num): > + print hp_array.items() > + pool_id = _pool_id_of(sys_id, array_name) > + name = array_name > + elem_type = Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_VOLUME_FULL > + unsupported_actions = 0 > + # TODO(Gris Ge): HP does not provide a precise number of bytes. > + free_space = _hp_size_to_lsm(hp_array['Unused Space']) > + total_space = free_space > + for key_name in hp_array.keys(): > + if key_name.startswith('Logical Drive'): > + total_space += _hp_size_to_lsm(hp_array[key_name]['Size']) > + > + (status, status_info) = _pool_status_of(hp_array) > + > + plugin_data = "%s:%s" % ( > + ctrl_num, array_name[len("Array: "):]) > + > + return Pool( > + pool_id, name, elem_type, unsupported_actions, > + total_space, free_space, status, status_info, > + sys_id, plugin_data) > + > + @_handle_errors > + def pools(self, search_key=None, search_value=None, > + flags=Client.FLAG_RSVD): > + """ > + Depend on command: > + hpssacli ctrl all show config detail > + """ > + lsm_pools = [] > + ctrl_all_conf = self._sacli_exec( > + ["ctrl", "all", "show", "config", "detail"]) > + for ctrl_data in ctrl_all_conf.values(): > + sys_id = ctrl_data['Serial Number'] > + ctrl_num = ctrl_data['Slot'] > + for key_name in ctrl_data.keys(): > + if key_name.startswith("Array:"): > + lsm_pools.append( > + self._hp_array_to_lsm_pool( > + ctrl_data[key_name], key_name, sys_id, ctrl_num)) > + > + return search_property(lsm_pools, search_key, search_value) > + > + @staticmethod > + def _hp_ld_to_lsm_vol(hp_ld, pool_id, sys_id, ctrl_num, array_num, > + hp_ld_name): > + ld_num = hp_ld_name[len("Logical Drive: "):] > + name = hp_ld_name > + vpd83 = hp_ld['Unique Identifier'].lower() > + vol_id = vpd83 > + # No document or command output indicate block size > + # of volume. So we try to read from linux kernel, if failed > + # try 512 and roughly calculate the sector count. > + sd_name_regex = re.compile("/dev/(sd[a-z]+)") > + regex_match = sd_name_regex.search(hp_ld['Disk Name']) > + if regex_match: > + sd_name = regex_match.group(1) > + block_size = int(file_read( > + "/sys/block/%s/queue/logical_block_size" % sd_name)) > + num_of_blocks = int(file_read("/sys/block/%s/size" % sd_name)) > + else: > + block_size = 512 > + num_of_blocks = int(_hp_size_to_lsm(hp_ld['Size']) / block_size) > + > + # HP SmartArray does not allow disabling volume. > + admin_state = Volume.ADMIN_STATE_ENABLED > + > + plugin_data = "%s:%s:%s" % (ctrl_num, array_num, ld_num) > + > + return Volume( > + vol_id, name, vpd83, block_size, num_of_blocks, admin_state, > + sys_id, pool_id, plugin_data) > + > + @_handle_errors > + def volumes(self, search_key=None, search_value=None, flags=0): > + """ > + Depend on command: > + hpssacli ctrl all show config detail > + """ > + lsm_vols = [] > + ctrl_all_conf = self._sacli_exec( > + ["ctrl", "all", "show", "config", "detail"]) > + for ctrl_data in ctrl_all_conf.values(): > + ctrl_num = ctrl_data['Slot'] > + sys_id = ctrl_data['Serial Number'] > + for key_name in ctrl_data.keys(): > + if not key_name.startswith("Array:"): > + continue > + pool_id = _pool_id_of(sys_id, key_name) > + array_num = key_name[len('Array: '):] > + for array_key_name in ctrl_data[key_name].keys(): > + if not array_key_name.startswith("Logical Drive"): > + continue > + lsm_vols.append( > + SmartArray._hp_ld_to_lsm_vol( > + ctrl_data[key_name][array_key_name], > + pool_id, sys_id, ctrl_num, array_num, > + array_key_name)) > + > + return search_property(lsm_vols, search_key, search_value) > + > + @_handle_errors > + def volume_raid_info(self, volume, flags=Client.FLAG_RSVD): > + """ > + Depend on command: > + hpssacli ctrl slot=0 show config detail > + """ > + if not volume.plugin_data: > + raise LsmError( > + ErrorNumber.INVALID_ARGUMENT, > + "Ilegal input volume argument: missing plugin_data property") > + > + (ctrl_num, array_num, ld_num) = volume.plugin_data.split(":") > + > + ctrl_conf = self._sacli_exec( > + ["ctrl", "slot=%s" % ctrl_num, "show", "config", "detail"]) > + ctrl_data = ctrl_conf.values()[0] > + disk_count = 0 > + flag_found = False > + for key_name in ctrl_data.keys(): > + if key_name != "Array: %s" % array_num: > + continue > + for array_key_name in ctrl_data[key_name].keys(): > + if array_key_name == "Logical Drive: %s" % ld_num: > + hp_ld = ctrl_data[key_name][array_key_name] > + flag_found = True > + raid_type = _hp_raid_type_to_lsm( > + hp_ld) > + strip_size = _hp_size_to_lsm( > + hp_ld['Strip Size']) > + stripe_size = _hp_size_to_lsm( > + hp_ld['Full Stripe Size']) > + elif array_key_name.startswith("physicaldrive"): > + hp_disk = ctrl_data[key_name][array_key_name] > + if hp_disk['Drive Type'] == 'Data Drive': > + disk_count += 1 > + > + if flag_found is False: > + raise LsmError( > + ErrorNumber.NOT_FOUND_VOLUME, > + "Volume not found") > + > + return [raid_type, strip_size, disk_count, strip_size, stripe_size] > diff --git a/plugin/hpsa/hpsa_lsmplugin b/plugin/hpsa/hpsa_lsmplugin > new file mode 100755 > index 0000000..07230f5 > --- /dev/null > +++ b/plugin/hpsa/hpsa_lsmplugin > @@ -0,0 +1,37 @@ > +#!/usr/bin/env python2 > +# Copyright (C) 2015 Red Hat, Inc. > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or any later version. > +# > +# This library is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > +# > +# Author: tasleson > +# Gris Ge <f...@redhat.com> > + > +import sys > +import syslog > +import traceback > + > +try: > + from lsm import PluginRunner > + from lsm.plugin.hpsa import SmartArray > + > + if __name__ == '__main__': > + PluginRunner(SmartArray, sys.argv).run() > +except Exception: > + #This should be quite rare, but when it does happen this is pretty > + #key in understanding what happened, especially when it happens when > + #running from the daemon. > + msg = str(traceback.format_exc()) > + syslog.syslog(syslog.LOG_ERR, msg) > + sys.stderr.write(msg) > + sys.exit(1) > diff --git a/plugin/hpsa/utils.py b/plugin/hpsa/utils.py > new file mode 100644 > index 0000000..23ae6cd > --- /dev/null > +++ b/plugin/hpsa/utils.py > @@ -0,0 +1,55 @@ > +## Copyright (C) 2015 Red Hat, Inc. > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or any later version. > +# > +# This library is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +# Lesser General Public License for more details. > +# > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > +# > +# Author: Gris Ge <f...@redhat.com> > + > +import subprocess > +import os > + > + > +def cmd_exec(cmds): > + """ > + Execute provided command and return the STDOUT as string. > + Raise ExecError if command return code is not zero > + """ > + cmd_popen = subprocess.Popen( > + cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE, > + env={"PATH": os.getenv("PATH")}) > + str_stdout = "".join(list(cmd_popen.stdout)).strip() > + str_stderr = "".join(list(cmd_popen.stderr)).strip() > + errno = cmd_popen.wait() > + if errno != 0: > + raise ExecError(" ".join(cmds), errno, str_stdout, str_stderr) > + return str_stdout > + > + > +def file_read(file_path): > + """ > + Read file and return string of file content. > + Use 'cat' command to better utilize the ExecError. > + """ > + return cmd_exec(['cat', file_path]) > + > +class ExecError(Exception): > + def __init__(self, cmd, errno, stdout, stderr, *args, **kwargs): > + Exception.__init__(self, *args, **kwargs) > + self.cmd = cmd > + self.errno = errno > + self.stdout = stdout > + self.stderr = stderr > + > + def __str__(self): > + return "cmd: '%s', errno: %d, stdout: '%s', stderr: '%s'" % \ > + (self.cmd, self.errno, self.stdout, self.stderr) > ------------------------------------------------------------------------------ Dive into the World of Parallel Programming The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ Libstoragemgmt-devel mailing list Libstoragemgmt-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libstoragemgmt-devel