Discussion:
[Libstoragemgmt-devel] [PATCH 2/4] update Python lsm.System class base on Python API wiki
Tony Asleson
2014-04-09 23:13:21 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Storing wiki Markdown documents in docstring. I will create a tool to
extract docstring and assemble out the identical Markdown string of our
wiki page. The docstring could be viewed via help(lsm.System) in python
interactive mode.
* Recoded lsm.System.status constants.
* Added lsm.System.status_info property.

Signed-off-by: Gris Ge <***@redhat.com>
Signed-off-by: Tony Asleson <***@redhat.com>
---
include/libstoragemgmt/libstoragemgmt_types.h | 16 +++--
lsm/lsm/_data.py | 91 ++++++++++++++++++++++++---
2 files changed, 94 insertions(+), 13 deletions(-)

diff --git a/include/libstoragemgmt/libstoragemgmt_types.h b/include/libstoragemgmt/libstoragemgmt_types.h
index 4a77dca..5e2389d 100644
--- a/include/libstoragemgmt/libstoragemgmt_types.h
+++ b/include/libstoragemgmt/libstoragemgmt_types.h
@@ -161,12 +161,16 @@ typedef enum {
* Different states a system status can be in.
* Bit field, can be in multiple states at the same time.
*/
-#define LSM_SYSTEM_STATUS_UNKNOWN 0x00000000 /**< System status unknown */
-#define LSM_SYSTEM_STATUS_OK 0x00000001 /**< System status OK */
-#define LSM_SYSTEM_STATUS_DEGRADED 0x00000002 /**< System is degraded */
-#define LSM_SYSTEM_STATUS_ERROR 0x00000004 /**< System has error(s) */
-#define LSM_SYSTEM_STATUS_PREDICTIVE_FAILURE 0x00000008 /**< System has predictive failure(s) */
-#define LSM_SYSTEM_STATUS_VENDOR_SPECIFIC 0x00000010 /**< Vendor specific status code */
+#define LSM_SYSTEM_STATUS_UNKNOWN 0x00000001 /**< Unknown */
+#define LSM_SYSTEM_STATUS_OK 0x00000002 /**< OK */
+#define LSM_SYSTEM_STATUS_ERROR 0x00000004 /**< Error(s) exist */
+#define LSM_SYSTEM_STATUS_DEGRADED 0x00000008 /**< Degraded */
+#define LSM_SYSTEM_STATUS_PREDICTIVE_FAILURE 0x00000010 /**< System has predictive failure(s) */
+#define LSM_SYSTEM_STATUS_STRESSED 0x00000020 /**< Temp or excessive IO */
+#define LSM_SYSTEM_STATUS_STARTING 0x00000040 /**< Booting */
+#define LSM_SYSTEM_STATUS_STOPPING 0x00000080 /**< Shutting down */
+#define LSM_SYSTEM_STATUS_STOPPED 0x00000100 /**< Stopped by admin */
+#define LSM_SYSTEM_STATUS_OTHER 0x00000200 /**< Vendor specific */

/**< \enum lsm_initiator_type Different types of initiator IDs */
typedef enum {
diff --git a/lsm/lsm/_data.py b/lsm/lsm/_data.py
index 6e314ba..9d3915c 100644
--- a/lsm/lsm/_data.py
+++ b/lsm/lsm/_data.py
@@ -672,10 +672,86 @@ class Volume(IData):
@default_property('id', doc="Unique identifier")
@default_property('name', doc="User defined system name")
@default_property('status', doc="Enumerated status of system")
+@default_property('status_info', doc="Detail status information of system")
class System(IData):
- (STATUS_UNKNOWN, STATUS_OK, STATUS_DEGRADED, STATUS_ERROR,
- STATUS_PREDICTIVE_FAILURE, STATUS_VENDOR_SPECIFIC) = \
- (0x0, 0x1, 0x2, 0x4, 0x8, 0x10)
+ """
+### 11.3 System -- lsm.System
+
+#### 11.3.1 System Properties
+ * id
+ String. Free form string used to identify certain system at plugin level.
+ Plugin can use this property for performance improvement
+ when concerting between LSM object to internal object. When displaying this
+ property to user, use the ID hashed string(like md5) is suggested.
+ * name
+ String. Human friendly name for this system.
+ * status
+ Integer. Byte Map(Check Appendix.D). The health status of system.
+ Could be any combination of these values:
+ * **lsm.System.STATUS_UNKNOWN**
+ Plugin failed to determine the status.
+ * **lsm.System.STATUS_OK**
+ Everything is OK.
+ * **lsm.System.STATUS_ERROR**
+ System is having errors which causing 'Data Unavailable' or 'Data Lose'.
+ Example:
+ * A RAID5 pool lose two disks.
+ * All controllers down.
+ * Internal hardware(like, memory) down and no redundant part.
+ The 'status_info' property will explain the detail.
+ * **lsm.System.STATUS_DEGRADED**
+ System is still functional but lose protection of redundant parts,
+ Example:
+ * One or more controller offline, but existing controller is taking
+ over all works.
+ * A RAID 5 pool lose 1 disk, no spare disk or spare disk is rebuilding.
+ * One or more battery changed from online to offline.
+ The 'status_info' property will explain the detail.
+ * **lsm.System.STATUS_PREDICTIVE_FAILURE**
+ System is still functional and protected by redundant parts, but
+ certain parts will soon be unfunctional.
+ * One or more battery voltage low.
+ * SMART information indicate some disk is dieing.
+ The 'status_info' property will explain the detail.
+ * **lsm.System.STATUS_STRESSED**
+ System is having too much I/O in progress or temperature exceeded the
+ limit. The 'status_info' property will explain the detail.
+ * **lsm.System.STATUS_STARTING**
+ System is booting up.
+ * **lsm.System.STATUS_STOPPING**
+ System is shutting down.
+ * **lsm.System.STATUS_STOPPED**
+ System is stopped by administrator.
+ * **lsm.System.STATUS_OTHER**
+ Vendor specifice status. The 'status_info' property will explain the
+ detail.
+ * status_info
+ String. Free form string used for explaining system status. For example:
+ "Disk <disk_id> is in Offline state. Battery X is near end of life"
+
+##### 11.3.2 System Optional Properties
+
+The lsm.System class does not have any optional properties yet.
+
+##### 11.3.3 System Extra Constants
+
+The lsm.System class does not have any extra constants.
+
+##### 11.3.4 System Class Methods
+
+The lsm.System class does not have class methods.
+ """
+
+ STATUS_UNKNOWN = 1 << 0
+ STATUS_OK = 1 << 1
+ STATUS_ERROR = 1 << 2
+ STATUS_DEGRADED = 1 << 3
+ STATUS_PREDICTIVE_FAILURE = 1 << 4
+ STATUS_STRESSED = 1 << 5
+ STATUS_STARTING = 1 << 6
+ STATUS_STOPPING = 1 << 7
+ STATUS_STOPPED = 1 << 8
+ STATUS_OTHER = 1 << 9

@staticmethod
def _status_to_str(status):
@@ -698,10 +774,11 @@ class System(IData):

return rc

- def __init__(self, _id, _name, _status):
- self._id = _id # For SMI-S this is the CIM_ComputerSystem->Name
- self._name = _name # For SMI-S , CIM_ComputerSystem->ElementName
- self._status = _status # OperationalStatus
+ def __init__(self, _id, _name, _status, _status_info=''):
+ self._id = _id
+ self._name = _name
+ self._status = _status
+ self._status_info = _status_info

_MAN_PROPERTIES_2_HEADER = {
'id': 'ID',
--
1.8.2.1
Tony Asleson
2014-04-09 23:13:23 UTC
Permalink
Signed-off-by: Tony Asleson <***@redhat.com>
---
libstoragemgmt.spec.in | 1 +
lsm/Makefile.am | 1 +
lsm/lsm/_cmdline.py | 11 ++++---
lsm/lsm/lsmcli_data_display.py | 71 ++++++++++++++++++++++--------------------
test/cmdtest.py | 2 +-
5 files changed, 47 insertions(+), 39 deletions(-)

diff --git a/libstoragemgmt.spec.in b/libstoragemgmt.spec.in
index ff02f92..57ee743 100644
--- a/libstoragemgmt.spec.in
+++ b/libstoragemgmt.spec.in
@@ -326,6 +326,7 @@ fi
%{python_sitelib}/lsm/_common.*
%{python_sitelib}/lsm/_data.*
%{python_sitelib}/lsm/_iplugin.*
+%{python_sitelib}/lsm/lsmcli_data_display.*
%{python_sitelib}/lsm/_pluginrunner.*
%{python_sitelib}/lsm/simulator.*
%{python_sitelib}/lsm/simarray.*
diff --git a/lsm/Makefile.am b/lsm/Makefile.am
index 2006c4d..029e87b 100644
--- a/lsm/Makefile.am
+++ b/lsm/Makefile.am
@@ -19,6 +19,7 @@ lsm_PYTHON = lsm/__init__.py \
lsm/_data.py \
lsm/eseries.py \
lsm/_iplugin.py \
+ lsm/lsmcli_data_display.py \
lsm/na.py \
lsm/nstor.py \
lsm/ontap.py \
diff --git a/lsm/lsm/_cmdline.py b/lsm/lsm/_cmdline.py
index 93a928f..ecc1e92 100644
--- a/lsm/lsm/_cmdline.py
+++ b/lsm/lsm/_cmdline.py
@@ -166,9 +166,10 @@ cmds = (
],
optional=[
dict(name=('-a', '--all'),
- help='Retrieve and display in scrit friendly way with ' +
+ help='Retrieve and display in script friendly way with ' +
'all information including optional data if available',
default=False,
+ dest='all',
action='store_true'),
dict(fs_id_opt),
],
@@ -811,11 +812,13 @@ class CmdLine:
# plug-in to plug-in.
# @param objects Data, first row is header all other data.
def display_data(self, objects, extra_properties=None):
+ display_all = False
+
if len(objects) == 0:
return

if hasattr(self.args, 'all') and self.args.all:
- self.args.script = True
+ display_all = True

flag_with_header = True
if self.args.sep:
@@ -830,8 +833,8 @@ class CmdLine:
flag_new_way_works = DisplayData.display_data(
objects, display_way=display_way, flag_human=self.args.human,
flag_enum=self.args.enum, extra_properties=extra_properties,
- spliter=self.args.sep, flag_with_header=flag_with_header,
- flag_dsp_all_data=self.args.all)
+ splitter=self.args.sep, flag_with_header=flag_with_header,
+ flag_dsp_all_data=display_all)

if flag_new_way_works:
return
diff --git a/lsm/lsm/lsmcli_data_display.py b/lsm/lsm/lsmcli_data_display.py
index 09b1a24..810f590 100644
--- a/lsm/lsm/lsmcli_data_display.py
+++ b/lsm/lsm/lsmcli_data_display.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Red Hat, Inc.
+# Copyright (C) 2014 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
@@ -20,13 +20,14 @@ from collections import OrderedDict

from lsm import System, size_bytes_2_size_human

-class EnumConvert:
- BIT_MAP_STRING_SPLITER = ','
+
+class EnumConvert(object):
+ BIT_MAP_STRING_SPLITTER = ','

@staticmethod
def _txt_a(txt, append):
if len(txt):
- return txt + EnumConvert.BIT_MAP_STRING_SPLITER + append
+ return txt + EnumConvert.BIT_MAP_STRING_SPLITTER + append
else:
return append

@@ -54,9 +55,10 @@ class EnumConvert:
return EnumConvert.SYSTEM_STATUS_CONV[System.STATUS_UNKNOWN]
return rc

-class DisplayData:

- def __init__():
+class DisplayData(object):
+
+ def __init__(self):
pass

@staticmethod
@@ -68,12 +70,12 @@ class DisplayData:
except IOError:
sys.exit(1)

- DISPLAY_WAY_COLUME = 0
+ DISPLAY_WAY_COLUMN = 0
DISPLAY_WAY_SCRIPT = 1

- DISPLAY_WAY_DEFAULT = DISPLAY_WAY_COLUME
+ DISPLAY_WAY_DEFAULT = DISPLAY_WAY_COLUMN

- DEFAULT_SPLITER=' | '
+ DEFAULT_SPLITTER = ' | '

SYSTEM_MAN_HEADER = OrderedDict()
SYSTEM_MAN_HEADER['id'] = 'ID'
@@ -148,7 +150,7 @@ class DisplayData:

for key in display_headers.keys():
key_str = display_headers[key]
- value = DisplayData._get_man_pro_value(
+ value = DisplayData._get_man_pro_value(
obj, key, value_conv_enum, value_conv_human, flag_human,
flag_enum)
data_dict[key_str] = value
@@ -158,7 +160,7 @@ class DisplayData:
if key in display_headers.keys():
continue
key_str = mandatory_headers[key]
- value = DisplayData._get_man_pro_value(
+ value = DisplayData._get_man_pro_value(
obj, key, value_conv_enum, value_conv_human, flag_human,
flag_enum)
data_dict[key_str] = value
@@ -176,7 +178,7 @@ class DisplayData:
if key in display_headers.keys():
continue
key_str = mandatory_headers[key]
- value = DisplayData._get_man_pro_value(
+ value = DisplayData._get_man_pro_value(
obj, key, value_conv_enum, value_conv_human,
flag_human, flag_enum)
data_dict[key_str] = value
@@ -193,7 +195,7 @@ class DisplayData:
def display_data(objs, display_way=None,
flag_human=True, flag_enum=False,
extra_properties=None,
- spliter=None,
+ splitter=None,
flag_with_header=True,
flag_dsp_all_data=False):
if len(objs) == 0:
@@ -202,8 +204,8 @@ class DisplayData:
if display_way is None:
display_way = DisplayData.DISPLAY_WAY_DEFAULT

- if spliter is None:
- spliter = DisplayData.DEFAULT_SPLITER
+ if splitter is None:
+ splitter = DisplayData.DEFAULT_SPLITTER

data_dict_list = []
if type(objs[0]) in DisplayData.VALUE_CONVERT.keys():
@@ -215,14 +217,14 @@ class DisplayData:
else:
return None
if display_way == DisplayData.DISPLAY_WAY_SCRIPT:
- DisplayData._display_data_script_way(data_dict_list, spliter)
- elif display_way == DisplayData.DISPLAY_WAY_COLUME:
- DisplayData._display_data_colume_way(
- data_dict_list, spliter, flag_with_header)
+ DisplayData._display_data_script_way(data_dict_list, splitter)
+ elif display_way == DisplayData.DISPLAY_WAY_COLUMN:
+ DisplayData._display_data_column_way(
+ data_dict_list, splitter, flag_with_header)
return True

@staticmethod
- def _display_data_script_way(data_dict_list, spliter):
+ def _display_data_script_way(data_dict_list, splitter):
key_column_width = 1
value_column_width = 1

@@ -245,40 +247,41 @@ class DisplayData:
value_column_width = cur_value_width

row_format = '%%-%ds%s%%-%ds' % (key_column_width,
- spliter,
+ splitter,
value_column_width)
sub_row_format = '%s%s%%-%ds' % (' ' * key_column_width,
- spliter,
+ splitter,
value_column_width)
- obj_spliter = '%s%s%s' % ('-' * key_column_width,
- '-' * len(spliter),
+ obj_splitter = '%s%s%s' % ('-' * key_column_width,
+ '-' * len(splitter),
'-' * value_column_width)

for data_dict in data_dict_list:
- DisplayData._out(obj_spliter)
+ DisplayData._out(obj_splitter)
for key_name in data_dict:
value = data_dict[key_name]
if isinstance(value, list):
flag_first_data = True
for sub_value in value:
if flag_first_data:
- out(row_format % (key_name, str(sub_value)))
+ DisplayData._out(row_format %
+ (key_name, str(sub_value)))
flag_first_data = False
else:
DisplayData._out(sub_row_format % str(sub_value))
else:
DisplayData._out(row_format % (key_name, str(value)))
- DisplayData._out(obj_spliter)
+ DisplayData._out(obj_splitter)

@staticmethod
- def _display_data_colume_way(data_dict_list, spliter, flag_with_header):
+ def _display_data_column_way(data_dict_list, splitter, flag_with_header):
if len(data_dict_list) == 0:
return
two_d_list = []

item_count = len(data_dict_list[0].keys())

- # detemin how many lines we will print
+ # determine how many lines we will print
row_width = 0
for data_dict in data_dict_list:
cur_max_wd = 0
@@ -329,16 +332,16 @@ class DisplayData:

# display two_list
row_formats = []
- header_spliter = ''
+ header_splitter = ''
for column_index in range(0, len(two_d_list[0])):
max_width = DisplayData._find_max_width(two_d_list, column_index)
row_formats.extend(['%%-%ds' % max_width])
- header_spliter += '-' * max_width
+ header_splitter += '-' * max_width
if column_index != (len(two_d_list[0]) - 1):
- header_spliter += '-' * len(spliter)
+ header_splitter += '-' * len(splitter)

- row_format = spliter.join(row_formats)
+ row_format = splitter.join(row_formats)
for row_index in range(0, len(two_d_list)):
DisplayData._out(row_format % tuple(two_d_list[row_index]))
if row_index == 0 and flag_with_header:
- DisplayData._out(header_spliter)
+ DisplayData._out(header_splitter)
diff --git a/test/cmdtest.py b/test/cmdtest.py
index 89f8862..9a9edd1 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -431,7 +431,7 @@ def display_check(display_list, system_id):
call([cmd, 'list', '--type', 'SNAPSHOTS', '--fs', fs_id])

if 'POOLS' in display_list:
- call([cmd, '-H', '-t' + sep, 'list', '--type', 'POOLS', '-o'])
+ call([cmd, '-H', '-t' + sep, 'list', '--type', 'POOLS', '-a'])


def test_display(cap, system_id):
--
1.8.2.1
Tony Asleson
2014-04-09 23:13:22 UTC
Permalink
From: Gris Ge <***@redhat.com>

* value conversion about lsm.System has been moved from _data.py to
DisplayData(lsmcli_data_display.py).
* Will move other classes with the progress of API review.
* Use OrderedDict to simplified the codes. (Tested on RHEL 6)
* For DisplayData not supported classes, it will fall back to old display
codes.
* Simplified the future works with two steps only:
1. Add enumerate type to string conversion methods into EnumConvert.
# staticmethod decorator does not allow using function reference within
# the same class. So we move it out to EnumConvert class.
2. Update DisplayData.VALUE_CONVERT by following the sample of
lsm.System.

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/_cmdline.py | 33 +++-
lsm/lsm/_data.py | 38 -----
lsm/lsm/lsmcli_data_display.py | 344 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 371 insertions(+), 44 deletions(-)
create mode 100644 lsm/lsm/lsmcli_data_display.py

diff --git a/lsm/lsm/_cmdline.py b/lsm/lsm/_cmdline.py
index 49e736e..93a928f 100644
--- a/lsm/lsm/_cmdline.py
+++ b/lsm/lsm/_cmdline.py
@@ -28,6 +28,7 @@ from lsm import (Client, Pool, VERSION, LsmError, Capabilities, Disk,

from _data import PlugData
from _common import getch, size_human_2_size_bytes, Proxy
+from lsmcli_data_display import DisplayData

##@package lsm.cmdline

@@ -164,8 +165,9 @@ cmds = (
type=str.upper),
],
optional=[
- dict(name=('-o', '--optional'),
- help='Retrieve additional optional info if available',
+ dict(name=('-a', '--all'),
+ help='Retrieve and display in scrit friendly way with ' +
+ 'all information including optional data if available',
default=False,
action='store_true'),
dict(fs_id_opt),
@@ -808,13 +810,32 @@ class CmdLine:
# Tries to make the output better when it varies considerably from
# plug-in to plug-in.
# @param objects Data, first row is header all other data.
- def display_data(self, objects):
+ def display_data(self, objects, extra_properties=None):
if len(objects) == 0:
return

- if hasattr(self.args, 'optional') and self.args.optional:
+ if hasattr(self.args, 'all') and self.args.all:
self.args.script = True

+ flag_with_header = True
+ if self.args.sep:
+ flag_with_header = False
+ if self.args.header:
+ flag_with_header = True
+
+ display_way = DisplayData.DISPLAY_WAY_DEFAULT
+ if self.args.script:
+ display_way = DisplayData.DISPLAY_WAY_SCRIPT
+
+ flag_new_way_works = DisplayData.display_data(
+ objects, display_way=display_way, flag_human=self.args.human,
+ flag_enum=self.args.enum, extra_properties=extra_properties,
+ spliter=self.args.sep, flag_with_header=flag_with_header,
+ flag_dsp_all_data=self.args.all)
+
+ if flag_new_way_works:
+ return
+
# Assuming all objects are from the same class.
key_2_str = objects[0]._str_of_key()
key_seq = objects[0]._key_display_sequence()
@@ -1057,7 +1078,7 @@ class CmdLine:
if args.type == 'VOLUMES':
self.display_data(self.c.volumes())
elif args.type == 'POOLS':
- if args.optional is True:
+ if args.all:
self.display_data(
self.c.pools(Pool.RETRIEVE_FULL_INFO))
else:
@@ -1081,7 +1102,7 @@ class CmdLine:
elif args.type == 'SYSTEMS':
self.display_data(self.c.systems())
elif args.type == 'DISKS':
- if args.optional:
+ if args.all:
self.display_data(
self.c.disks(Disk.RETRIEVE_FULL_INFO))
else:
diff --git a/lsm/lsm/_data.py b/lsm/lsm/_data.py
index 9d3915c..25bee2a 100644
--- a/lsm/lsm/_data.py
+++ b/lsm/lsm/_data.py
@@ -753,50 +753,12 @@ The lsm.System class does not have class methods.
STATUS_STOPPED = 1 << 8
STATUS_OTHER = 1 << 9

- @staticmethod
- def _status_to_str(status):
- if status == 0:
- return "Unknown"
- elif status == 1:
- return "OK"
- else:
- rc = ""
- if status & System.STATUS_OK:
- rc = txt_a(rc, "OK")
- if status & System.STATUS_DEGRADED:
- rc = txt_a(rc, "Degraded")
- if status & System.STATUS_ERROR:
- rc = txt_a(rc, "Error")
- if status & System.STATUS_PREDICTIVE_FAILURE:
- rc = txt_a(rc, "Predictive failure")
- if status & System.STATUS_VENDOR_SPECIFIC:
- rc = txt_a(rc, "Vendor specific status")
-
- return rc
-
def __init__(self, _id, _name, _status, _status_info=''):
self._id = _id
self._name = _name
self._status = _status
self._status_info = _status_info

- _MAN_PROPERTIES_2_HEADER = {
- 'id': 'ID',
- 'name': 'Name',
- 'status': 'Status',
- }
-
- _MAN_PROPERTIES_SEQUENCE = ['id', 'name', 'status']
-
- def _value_convert(self, key_name, value, human, enum_as_number,
- list_convert):
-
- if enum_as_number is False:
- if key_name == 'status':
- value = System._status_to_str(value)
- return value
-
-
@default_property('id', doc="Unique identifier")
@default_property('name', doc="User supplied name")
@default_property('total_space', doc="Total space in bytes")
diff --git a/lsm/lsm/lsmcli_data_display.py b/lsm/lsm/lsmcli_data_display.py
new file mode 100644
index 0000000..09b1a24
--- /dev/null
+++ b/lsm/lsm/lsmcli_data_display.py
@@ -0,0 +1,344 @@
+# Copyright (C) 2012 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 <***@redhat.com>
+import sys
+from collections import OrderedDict
+
+from lsm import System, size_bytes_2_size_human
+
+class EnumConvert:
+ BIT_MAP_STRING_SPLITER = ','
+
+ @staticmethod
+ def _txt_a(txt, append):
+ if len(txt):
+ return txt + EnumConvert.BIT_MAP_STRING_SPLITER + append
+ else:
+ return append
+
+ SYSTEM_STATUS_CONV = {
+ System.STATUS_UNKNOWN: 'Unknown',
+ System.STATUS_OK: 'OK',
+ System.STATUS_ERROR: 'Error',
+ System.STATUS_DEGRADED: 'Degraded',
+ System.STATUS_PREDICTIVE_FAILURE: 'Predictive failure',
+ System.STATUS_STRESSED: 'Stressed',
+ System.STATUS_STARTING: 'Starting',
+ System.STATUS_STOPPING: 'Stopping',
+ System.STATUS_STOPPED: 'Stopped',
+ System.STATUS_OTHER: 'Other',
+ }
+
+ @staticmethod
+ def system_status_to_str(system_status):
+ rc = ''
+ for cur_sys_status in EnumConvert.SYSTEM_STATUS_CONV.keys():
+ if system_status & cur_sys_status:
+ rc = EnumConvert._txt_a(rc,
+ EnumConvert.SYSTEM_STATUS_CONV[cur_sys_status])
+ if rc == '':
+ return EnumConvert.SYSTEM_STATUS_CONV[System.STATUS_UNKNOWN]
+ return rc
+
+class DisplayData:
+
+ def __init__():
+ pass
+
+ @staticmethod
+ def _out(msg):
+ try:
+ sys.stdout.write(str(msg))
+ sys.stdout.write("\n")
+ sys.stdout.flush()
+ except IOError:
+ sys.exit(1)
+
+ DISPLAY_WAY_COLUME = 0
+ DISPLAY_WAY_SCRIPT = 1
+
+ DISPLAY_WAY_DEFAULT = DISPLAY_WAY_COLUME
+
+ DEFAULT_SPLITER=' | '
+
+ SYSTEM_MAN_HEADER = OrderedDict()
+ SYSTEM_MAN_HEADER['id'] = 'ID'
+ SYSTEM_MAN_HEADER['name'] = 'Name'
+ SYSTEM_MAN_HEADER['status'] = 'Status'
+ SYSTEM_MAN_HEADER['status_info'] = 'Status Info'
+
+ SYSTEM_OPT_HEADER = OrderedDict()
+
+ SYSTEM_DSP_HEADER = SYSTEM_MAN_HEADER # SYSTEM_DSP_HEADER should be
+ # subset of SYSTEM_MAN_HEADER
+
+ SYSTEM_VALUE_CONV_ENUM = {
+ 'status': EnumConvert.system_status_to_str,
+ }
+
+ SYSTEM_VALUE_CONV_HUMAN = []
+
+ VALUE_CONVERT = {
+ System: {
+ 'mandatory_headers': SYSTEM_MAN_HEADER,
+ 'display_headers': SYSTEM_DSP_HEADER,
+ 'optional_headers': SYSTEM_OPT_HEADER,
+ 'value_conv_enum': SYSTEM_VALUE_CONV_ENUM,
+ 'value_conv_human': SYSTEM_VALUE_CONV_HUMAN,
+ }
+ }
+
+ @staticmethod
+ def _get_man_pro_value(obj, key, value_conv_enum, value_conv_human,
+ flag_human, flag_enum):
+ value = getattr(obj, key)
+ if not flag_enum:
+ if key in value_conv_enum.keys():
+ value = value_conv_enum[key](value)
+ if flag_human:
+ if key in value_conv_human:
+ value = size_bytes_2_size_human(value)
+ return value
+
+ @staticmethod
+ def _get_opt_pro_value(obj, key, value_conv_enum, value_conv_human,
+ flag_human, flag_enum):
+ value = obj.optional_data.get(key)
+ if not flag_enum:
+ if key in value_conv_enum.keys():
+ value = value_conv_enum[key](value)
+ if flag_human:
+ if key in value_conv_human:
+ value = size_bytes_2_size_human(value)
+ return value
+
+ @staticmethod
+ def _find_max_width(two_d_list, column_index):
+ max_width = 1
+ for row_index in range(0, len(two_d_list)):
+ row_data = two_d_list[row_index]
+ if len(row_data[column_index]) > max_width:
+ max_width = len(row_data[column_index])
+ return max_width
+
+ @staticmethod
+ def _data_dict_gen(obj, flag_human, flag_enum, extra_properties=None,
+ flag_dsp_all_data=False):
+ data_dict = OrderedDict()
+ value_convert = DisplayData.VALUE_CONVERT[type(obj)]
+ mandatory_headers = value_convert['mandatory_headers']
+ display_headers = value_convert['display_headers']
+ optional_headers = value_convert['optional_headers']
+ value_conv_enum = value_convert['value_conv_enum']
+ value_conv_human = value_convert['value_conv_human']
+
+ for key in display_headers.keys():
+ key_str = display_headers[key]
+ value = DisplayData._get_man_pro_value(
+ obj, key, value_conv_enum, value_conv_human, flag_human,
+ flag_enum)
+ data_dict[key_str] = value
+
+ if flag_dsp_all_data:
+ for key in mandatory_headers.keys():
+ if key in display_headers.keys():
+ continue
+ key_str = mandatory_headers[key]
+ value = DisplayData._get_man_pro_value(
+ obj, key, value_conv_enum, value_conv_human, flag_human,
+ flag_enum)
+ data_dict[key_str] = value
+
+ for key in optional_headers.keys():
+ key_str = optional_headers[key]
+ value = DisplayData._get_opt_pro_value(
+ obj, key, value_conv_enum, value_conv_human, flag_human,
+ flag_enum)
+ data_dict[key_str] = value
+
+ elif extra_properties:
+ for key in extra_properties:
+ if key in mandatory_headers.keys():
+ if key in display_headers.keys():
+ continue
+ key_str = mandatory_headers[key]
+ value = DisplayData._get_man_pro_value(
+ obj, key, value_conv_enum, value_conv_human,
+ flag_human, flag_enum)
+ data_dict[key_str] = value
+ elif key in optional_headers.keys():
+ key_str = optional_headers[key]
+ value = DisplayData._get_opt_pro_value(
+ obj, key, value_conv_enum, value_conv_human,
+ flag_human, flag_enum)
+ data_dict[key_str] = value
+
+ return data_dict
+
+ @staticmethod
+ def display_data(objs, display_way=None,
+ flag_human=True, flag_enum=False,
+ extra_properties=None,
+ spliter=None,
+ flag_with_header=True,
+ flag_dsp_all_data=False):
+ if len(objs) == 0:
+ return None
+
+ if display_way is None:
+ display_way = DisplayData.DISPLAY_WAY_DEFAULT
+
+ if spliter is None:
+ spliter = DisplayData.DEFAULT_SPLITER
+
+ data_dict_list = []
+ if type(objs[0]) in DisplayData.VALUE_CONVERT.keys():
+ for obj in objs:
+ data_dict = DisplayData._data_dict_gen(
+ obj, flag_human, flag_enum, extra_properties,
+ flag_dsp_all_data)
+ data_dict_list.extend([data_dict])
+ else:
+ return None
+ if display_way == DisplayData.DISPLAY_WAY_SCRIPT:
+ DisplayData._display_data_script_way(data_dict_list, spliter)
+ elif display_way == DisplayData.DISPLAY_WAY_COLUME:
+ DisplayData._display_data_colume_way(
+ data_dict_list, spliter, flag_with_header)
+ return True
+
+ @staticmethod
+ def _display_data_script_way(data_dict_list, spliter):
+ key_column_width = 1
+ value_column_width = 1
+
+ for data_dict in data_dict_list:
+ for key_name in data_dict.keys():
+ # find the max column width of key
+ cur_key_width = len(key_name)
+ if cur_key_width > key_column_width:
+ key_column_width = cur_key_width
+ # find the max column width of value
+ cur_value = data_dict[key_name]
+ cur_value_width = 0
+ if isinstance(cur_value, list):
+ if len(cur_value) == 0:
+ continue
+ cur_value_width = len(str(cur_value[0]))
+ else:
+ cur_value_width = len(str(cur_value))
+ if cur_value_width > value_column_width:
+ value_column_width = cur_value_width
+
+ row_format = '%%-%ds%s%%-%ds' % (key_column_width,
+ spliter,
+ value_column_width)
+ sub_row_format = '%s%s%%-%ds' % (' ' * key_column_width,
+ spliter,
+ value_column_width)
+ obj_spliter = '%s%s%s' % ('-' * key_column_width,
+ '-' * len(spliter),
+ '-' * value_column_width)
+
+ for data_dict in data_dict_list:
+ DisplayData._out(obj_spliter)
+ for key_name in data_dict:
+ value = data_dict[key_name]
+ if isinstance(value, list):
+ flag_first_data = True
+ for sub_value in value:
+ if flag_first_data:
+ out(row_format % (key_name, str(sub_value)))
+ flag_first_data = False
+ else:
+ DisplayData._out(sub_row_format % str(sub_value))
+ else:
+ DisplayData._out(row_format % (key_name, str(value)))
+ DisplayData._out(obj_spliter)
+
+ @staticmethod
+ def _display_data_colume_way(data_dict_list, spliter, flag_with_header):
+ if len(data_dict_list) == 0:
+ return
+ two_d_list = []
+
+ item_count = len(data_dict_list[0].keys())
+
+ # detemin how many lines we will print
+ row_width = 0
+ for data_dict in data_dict_list:
+ cur_max_wd = 0
+ for key_name in data_dict.keys():
+ if isinstance(data_dict[key_name], list):
+ cur_row_width = len(data_dict[key_name])
+ if cur_row_width > cur_max_wd:
+ cur_max_wd = cur_row_width
+ else:
+ pass
+ if cur_max_wd == 0:
+ cur_max_wd = 1
+ row_width += cur_max_wd
+
+ if flag_with_header:
+ # first line for header
+ row_width += 1
+
+ # init 2D list
+ for raw in range(0, row_width):
+ new = []
+ for column in range(0, item_count):
+ new.append([''])
+ two_d_list.append(new)
+
+ # header
+ current_row_num = -1
+ if flag_with_header:
+ two_d_list[0] = data_dict_list[0].keys()
+ current_row_num = 0
+
+ # Fill the 2D list with data_dict_list
+ for data_dict in data_dict_list:
+ current_row_num += 1
+ save_row_num = current_row_num
+ values = data_dict.values()
+ for index in range(0, len(values)):
+ value = values[index]
+ if isinstance(value, list):
+ for sub_index in range(0, len(value)):
+ tmp_row_num = save_row_num + sub_index
+ two_d_list[tmp_row_num][index] = str(value[sub_index])
+
+ if save_row_num + len(value) > current_row_num:
+ current_row_num = save_row_num + len(value) - 1
+ else:
+ two_d_list[save_row_num][index] = str(value)
+
+ # display two_list
+ row_formats = []
+ header_spliter = ''
+ for column_index in range(0, len(two_d_list[0])):
+ max_width = DisplayData._find_max_width(two_d_list, column_index)
+ row_formats.extend(['%%-%ds' % max_width])
+ header_spliter += '-' * max_width
+ if column_index != (len(two_d_list[0]) - 1):
+ header_spliter += '-' * len(spliter)
+
+ row_format = spliter.join(row_formats)
+ for row_index in range(0, len(two_d_list)):
+ DisplayData._out(row_format % tuple(two_d_list[row_index]))
+ if row_index == 0 and flag_with_header:
+ DisplayData._out(header_spliter)
--
1.8.2.1
Loading...