Discussion:
[Libstoragemgmt-devel] [PATCH 00/13] Status clean up for System, Pool, volume.
Gris Ge
2014-08-22 14:23:11 UTC
Permalink
I only did works on C library for System and Pool clean up.
Please kindly help me to sync C library with python changes on volume
status.

Thank you in advance.
Best regards.

Gris Ge (13):
Clean up system status constants
Library: Remove unused pool status
ONTAP plugin: Improve pool query method
SMIS plugin: Clean up pool status query
Python Library: Remove Volume.state, add Volume.admin_state
Python Library: Rename volume_online to volume_enable()
lsmcli: Remove Volume.state, add Volume.admin_state
lsmcli: Add volume-enable and volume-disable commands
nstor: Remove Volume.state, add Volume.admin_state
smis: Remove Volume.state, add Volume.admin_state
targetd: Remove Volume.state, add Volume.admin_state
sim: volume admin status related changes
ontap: volume admin status related changes

.../include/libstoragemgmt/libstoragemgmt_types.h | 10 +-
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 3 +-
plugin/nstor/nstor.py | 21 +--
plugin/ontap/na.py | 58 +-----
plugin/ontap/ontap.py | 207 ++++++++++++---------
plugin/sim/simarray.py | 43 +++--
plugin/sim/simulator.py | 8 +-
plugin/smispy/dmtf.py | 192 +++++++++++++++++++
plugin/smispy/smis.py | 204 ++------------------
plugin/targetd/targetd.py | 15 +-
python_binding/lsm/_client.py | 14 +-
python_binding/lsm/_data.py | 86 +--------
python_binding/lsm/_iplugin.py | 4 +-
tools/lsmcli/cmdline.py | 28 +++
tools/lsmcli/data_display.py | 60 +++---
16 files changed, 439 insertions(+), 515 deletions(-)
create mode 100644 plugin/smispy/dmtf.py
--
2.1.0
Gris Ge
2014-08-22 14:23:12 UTC
Permalink
* Removed these system status as no plugin support it:
stress
starting
stopping
stopped
* Updated SMI-S plugin to fit this change:
1. Split DMTF class to dmtf.py(Makefile and RPM SPEC file updated).
2. If facing other status, will mark as STATUS_OTHER and store the
name into system_info.
I tried on many SMI-S providers, I only got degraded.

Signed-off-by: Gris Ge <***@redhat.com>
---
.../include/libstoragemgmt/libstoragemgmt_types.h | 6 +-
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 3 +-
plugin/smispy/dmtf.py | 192 +++++++++++++++++++++
plugin/smispy/smis.py | 111 ++----------
python_binding/lsm/_data.py | 69 +-------
tools/lsmcli/data_display.py | 4 -
7 files changed, 207 insertions(+), 179 deletions(-)
create mode 100644 plugin/smispy/dmtf.py

diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
index 82a23a8..de163a2 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
@@ -165,11 +165,7 @@ typedef enum {
#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 */
+#define LSM_SYSTEM_STATUS_OTHER 0x00000020 /**< Vendor specific */


typedef enum {
diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 37398f1..479a04d 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -314,6 +314,7 @@ fi
%{python_sitelib}/lsm/plugin/smispy/eseries.*
%{python_sitelib}/lsm/plugin/smispy/smis.*
%{python_sitelib}/lsm/plugin/smispy/smisproxy.*
+%{python_sitelib}/lsm/plugin/smispy/dmtf.*
%{_bindir}/smispy_lsmplugin

%files netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index 96a243a..5a4dca2 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -26,7 +26,8 @@ smispy_PYTHON = \
smispy/__init__.py \
smispy/smis.py \
smispy/smisproxy.py \
- smispy/eseries.py
+ smispy/eseries.py \
+ smispy/dmtf.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
new file mode 100644
index 0000000..0a34ddc
--- /dev/null
+++ b/plugin/smispy/dmtf.py
@@ -0,0 +1,192 @@
+# Copyright (C) 2011-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
+# 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>
+
+# This class handle DMTF CIM constants and convert to LSM type.
+
+from lsm import (System, Pool)
+from pywbem import Uint16
+
+
+class DMTF(object):
+ # CIM_ManagedSystemElement['OperationalStatus']
+ OP_STATUS_UNKNOWN = 0
+ OP_STATUS_OTHER = 1
+ OP_STATUS_OK = 2
+ OP_STATUS_DEGRADED = 3
+ OP_STATUS_STRESSED = 4
+ OP_STATUS_PREDICTIVE_FAILURE = 5
+ OP_STATUS_ERROR = 6
+ OP_STATUS_NON_RECOVERABLE_ERROR = 7
+ OP_STATUS_STARTING = 8
+ OP_STATUS_STOPPING = 9
+ OP_STATUS_STOPPED = 10
+ OP_STATUS_IN_SERVICE = 11
+ OP_STATUS_NO_CONTACT = 12
+ OP_STATUS_LOST_COMMUNICATION = 13
+ OP_STATUS_ABORTED = 14
+ OP_STATUS_DORMANT = 15
+ OP_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16
+ OP_STATUS_COMPLETED = 17
+ OP_STATUS_POWER_MODE = 18
+
+ _OP_STATUS_STR_CONV = {
+ OP_STATUS_UNKNOWN: "UNKNOWN",
+ OP_STATUS_OTHER: "OTHER",
+ OP_STATUS_OK: "OK",
+ OP_STATUS_DEGRADED: "DEGRADED",
+ OP_STATUS_STRESSED: "STRESSED",
+ OP_STATUS_PREDICTIVE_FAILURE: "PREDICTIVE_FAILURE",
+ OP_STATUS_ERROR: "ERROR",
+ OP_STATUS_NON_RECOVERABLE_ERROR: "NON_RECOVERABLE_ERROR",
+ OP_STATUS_STARTING: "STARTING",
+ OP_STATUS_STOPPING: "STOPPING",
+ OP_STATUS_STOPPED: "STOPPED",
+ OP_STATUS_IN_SERVICE: "IN_SERVICE",
+ OP_STATUS_NO_CONTACT: "NO_CONTACT",
+ OP_STATUS_LOST_COMMUNICATION: "LOST_COMMUNICATION",
+ OP_STATUS_ABORTED: "ABORTED",
+ OP_STATUS_DORMANT: "DORMANT",
+ OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: "SUPPORTING_ENTITY_IN_ERROR",
+ OP_STATUS_COMPLETED: "COMPLETED",
+ OP_STATUS_POWER_MODE: "POWER_MODE",
+ }
+
+ @staticmethod
+ def dmtf_op_status_to_str(dmtf_op_status):
+ """
+ Just convert integer to string. NOT ALLOWING provide a list.
+ Return emtpy string is not found.
+ """
+ try:
+ return DMTF._OP_STATUS_STR_CONV[dmtf_op_status]
+ except KeyError:
+ return ''
+
+ _LSM_SYS_OP_STATUS_CONV = {
+ OP_STATUS_OK: System.STATUS_OK,
+ OP_STATUS_ERROR: System.STATUS_ERROR,
+ OP_STATUS_DEGRADED: System.STATUS_DEGRADED,
+ OP_STATUS_NON_RECOVERABLE_ERROR: System.STATUS_ERROR,
+ OP_STATUS_PREDICTIVE_FAILURE: System.STATUS_PREDICTIVE_FAILURE,
+ OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: System.STATUS_ERROR,
+ }
+
+ @staticmethod
+ def _dmtf_op_status_list_conv(conv_dict, dmtf_op_status_list,
+ unknown_value, other_value):
+ status = 0
+ status_info_list = []
+ for dmtf_op_status in dmtf_op_status_list:
+ if dmtf_op_status in conv_dict.keys():
+ status |= conv_dict[dmtf_op_status]
+ else:
+ if dmtf_op_status in DMTF._OP_STATUS_STR_CONV.keys():
+ status |= other_value
+ status_info_list.append(
+ DMTF.dmtf_op_status_to_str(dmtf_op_status))
+ continue
+ if status == 0:
+ status = unknown_value
+ return status, " ".join(status_info_list)
+
+
+ @staticmethod
+ def cim_sys_status_of(dmtf_op_status_list):
+ """
+ Convert CIM_ComputerSystem['OperationalStatus']
+ """
+ return DMTF._dmtf_op_status_list_conv(
+ DMTF._LSM_SYS_OP_STATUS_CONV, dmtf_op_status_list,
+ System.STATUS_UNKNOWN, System.STATUS_OTHER)
+
+ _LSM_POOL_OP_STATUS_CONV = {
+ OP_STATUS_OK: Pool.STATUS_OK,
+ OP_STATUS_ERROR: Pool.STATUS_ERROR,
+ OP_STATUS_DEGRADED: Pool.STATUS_DEGRADED,
+ OP_STATUS_NON_RECOVERABLE_ERROR: Pool.STATUS_ERROR,
+ OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: Pool.STATUS_ERROR,
+ }
+
+ @staticmethod
+ def cim_pool_status_of(dmtf_op_status_list):
+ """
+ Convert CIM_StoragePool['OperationalStatus'] to LSM
+ """
+ return DMTF._dmtf_op_status_list_conv(
+ DMTF._LSM_POOL_OP_STATUS_CONV, dmtf_op_status_list,
+ Pool.STATUS_UNKNOWN, Pool.STATUS_OTHER)
+
+
+ # CIM_StorageHardwareID['IDType']
+ ID_TYPE_OTHER = Uint16(1)
+ ID_TYPE_WWPN = Uint16(2)
+ ID_TYPE_ISCSI = Uint16(5)
+
+ TGT_PORT_USAGE_FRONTEND_ONLY = Uint16(2)
+ TGT_PORT_USAGE_UNRESTRICTED = Uint16(4)
+ # CIM_FCPort['PortDiscriminator']
+ FC_PORT_PORT_DISCRIMINATOR_FCOE = Uint16(10)
+ # CIM_NetworkPort['LinkTechnology']
+ NET_PORT_LINK_TECH_ETHERNET = Uint16(2)
+ # CIM_iSCSIProtocolEndpoint['Role']
+ ISCSI_TGT_ROLE_TARGET = Uint16(3)
+ # CIM_SCSIProtocolController['NameFormat']
+ SPC_NAME_FORMAT_ISCSI = Uint16(3)
+ # CIM_IPProtocolEndpoint['IPv6AddressType']
+ IPV6_ADDR_TYPE_GUA = Uint16(6)
+ # GUA: Global Unicast Address.
+ # 2000::/3
+ IPV6_ADDR_TYPE_6TO4 = Uint16(7)
+ # IPv6 to IPv4 transition
+ # ::ffff:0:0/96
+ # ::ffff:0:0:0/96
+ # 64:ff9b::/96 # well-known prefix
+ # 2002::/16 # 6to4
+ IPV6_ADDR_TYPE_ULA = Uint16(8)
+ # ULA: Unique Local Address, aka Site Local Unicast.
+ # fc00::/7
+
+ # CIM_GroupMaskingMappingService.CreateGroup('Type')
+ MASK_GROUP_TYPE_INIT = Uint16(2)
+ MASK_GROUP_TYPE_TGT = Uint16(3)
+ MASK_GROUP_TYPE_DEV = Uint16(4)
+
+ # CIM_GroupMaskingMappingCapabilities['SupportedDeviceGroupFeatures']
+ # Allowing empty DeviceMaskingGroup associated to SPC
+ GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC = Uint16(5)
+
+ # CIM_GroupMaskingMappingCapabilities['SupportedInitiatorGroupFeatures']
+ # Allowing empty DeviceMaskingGroup
+ GMM_CAP_INIT_MG_ALLOW_EMPTY = Uint16(4)
+ # Allowing empty DeviceMaskingGroup associated to SPC
+ GMM_CAP_INIT_MG_ALLOW_EMPTY_W_SPC = Uint16(5)
+
+ # CIM_GroupMaskingMappingCapabilities['SupportedAsynchronousActions']
+ # and 'SupportedSynchronousActions'. They are using the same value map.
+ GMM_CAP_DELETE_SPC = Uint16(24)
+ GMM_CAP_DELETE_GROUP = Uint16(20)
+
+ # CIM_StorageConfigurationCapabilities['SupportedStorageElementTypes']
+ SCS_CAP_SUP_ST_VOLUME = Uint16(2)
+ SCS_CAP_SUP_THIN_ST_VOLUME = Uint16(5)
+
+ # CIM_StorageConfigurationCapabilities['SupportedAsynchronousActions']
+ # and also for 'SupportedSynchronousActions'
+ SCS_CAP_VOLUME_CREATE = Uint16(5)
+ SCS_CAP_VOLUME_DELETE = Uint16(6)
+ SCS_CAP_VOLUME_MODIFY = Uint16(7)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 5bb02ad..5cc6d09 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -32,6 +32,8 @@ from lsm import (IStorageAreaNetwork, error, uri_parse, LsmError, ErrorNumber,
Capabilities, Disk, VERSION, TargetPort,
search_property)

+from dmtf import DMTF
+
## Variable Naming scheme:
# cim_xxx CIMInstance
# cim_xxx_path CIMInstanceName
@@ -148,68 +150,6 @@ def _lsm_init_id_to_snia(lsm_init_id):
return lsm_init_id.replace(':', '').upper()
return lsm_init_id

-
-class DMTF(object):
- # CIM_StorageHardwareID['IDType']
- ID_TYPE_OTHER = pywbem.Uint16(1)
- ID_TYPE_WWPN = pywbem.Uint16(2)
- ID_TYPE_ISCSI = pywbem.Uint16(5)
-
- TGT_PORT_USAGE_FRONTEND_ONLY = pywbem.Uint16(2)
- TGT_PORT_USAGE_UNRESTRICTED = pywbem.Uint16(4)
- # CIM_FCPort['PortDiscriminator']
- FC_PORT_PORT_DISCRIMINATOR_FCOE = pywbem.Uint16(10)
- # CIM_NetworkPort['LinkTechnology']
- NET_PORT_LINK_TECH_ETHERNET = pywbem.Uint16(2)
- # CIM_iSCSIProtocolEndpoint['Role']
- ISCSI_TGT_ROLE_TARGET = pywbem.Uint16(3)
- # CIM_SCSIProtocolController['NameFormat']
- SPC_NAME_FORMAT_ISCSI = pywbem.Uint16(3)
- # CIM_IPProtocolEndpoint['IPv6AddressType']
- IPV6_ADDR_TYPE_GUA = pywbem.Uint16(6)
- # GUA: Global Unicast Address.
- # 2000::/3
- IPV6_ADDR_TYPE_6TO4 = pywbem.Uint16(7)
- # IPv6 to IPv4 transition
- # ::ffff:0:0/96
- # ::ffff:0:0:0/96
- # 64:ff9b::/96 # well-known prefix
- # 2002::/16 # 6to4
- IPV6_ADDR_TYPE_ULA = pywbem.Uint16(8)
- # ULA: Unique Local Address, aka Site Local Unicast.
- # fc00::/7
-
- # CIM_GroupMaskingMappingService.CreateGroup('Type')
- MASK_GROUP_TYPE_INIT = pywbem.Uint16(2)
- MASK_GROUP_TYPE_TGT = pywbem.Uint16(3)
- MASK_GROUP_TYPE_DEV = pywbem.Uint16(4)
-
- # CIM_GroupMaskingMappingCapabilities['SupportedDeviceGroupFeatures']
- # Allowing empty DeviceMaskingGroup associated to SPC
- GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC = pywbem.Uint16(5)
-
- # CIM_GroupMaskingMappingCapabilities['SupportedInitiatorGroupFeatures']
- # Allowing empty DeviceMaskingGroup
- GMM_CAP_INIT_MG_ALLOW_EMPTY = pywbem.Uint16(4)
- # Allowing empty DeviceMaskingGroup associated to SPC
- GMM_CAP_INIT_MG_ALLOW_EMPTY_W_SPC = pywbem.Uint16(5)
-
- # CIM_GroupMaskingMappingCapabilities['SupportedAsynchronousActions']
- # and 'SupportedSynchronousActions'. They are using the same value map.
- GMM_CAP_DELETE_SPC = pywbem.Uint16(24)
- GMM_CAP_DELETE_GROUP = pywbem.Uint16(20)
-
- # CIM_StorageConfigurationCapabilities['SupportedStorageElementTypes']
- SCS_CAP_SUP_ST_VOLUME = pywbem.Uint16(2)
- SCS_CAP_SUP_THIN_ST_VOLUME = pywbem.Uint16(5)
-
- # CIM_StorageConfigurationCapabilities['SupportedAsynchronousActions']
- # and also for 'SupportedSynchronousActions'
- SCS_CAP_VOLUME_CREATE = pywbem.Uint16(5)
- SCS_CAP_VOLUME_DELETE = pywbem.Uint16(6)
- SCS_CAP_VOLUME_MODIFY = pywbem.Uint16(7)
-
-
def _dmtf_init_type_to_lsm(cim_init):
if 'IDType' in cim_init:
if cim_init['IDType'] == DMTF.ID_TYPE_WWPN:
@@ -244,7 +184,6 @@ def _lsm_init_type_to_dmtf(init_type):
raise LsmError(ErrorNumber.NO_SUPPORT,
"Does not support provided init_type: %d" % init_type)

-
class SNIA(object):
BLK_ROOT_PROFILE = 'Array'
BLK_SRVS_PROFILE = 'Block Services'
@@ -516,28 +455,6 @@ class Smis(IStorageAreaNetwork):
VOL_OP_STATUS_STARTING,
VOL_OP_STATUS_DORMANT) = (2, 3, 6, 8, 15)

- # SMI-S CIM_ComputerSystem OperationalStatus for system
- class SystemOperationalStatus(object):
- UNKNOWN = 0
- OTHER = 1
- OK = 2
- DEGRADED = 3
- STRESSED = 4
- PREDICTIVE_FAILURE = 5
- ERROR = 6
- NON_RECOVERABLE_ERROR = 7
- STARTING = 8
- STOPPING = 9
- STOPPED = 10
- IN_SERVICE = 11
- NO_CONTACT = 12
- LOST_COMMUNICATION = 13
- ABORTED = 14
- DORMANT = 15
- SUPPORTING_ENTITY_IN_ERROR = 16
- COMPLETED = 17
- POWER_MODE = 18
-
# SMI-S ExposePaths device access enumerations
(EXPOSE_PATHS_DA_READ_WRITE, EXPOSE_PATHS_DA_READ_ONLY) = (2, 3)

@@ -1819,26 +1736,18 @@ class Smis(IStorageAreaNetwork):
status, status_info, system_id)

@staticmethod
- def _cim_sys_2_lsm_sys(cim_sys):
+ def _cim_sys_to_lsm(cim_sys):
# In the case of systems we are assuming that the System Name is
# unique.
status = System.STATUS_UNKNOWN
+ status_info = ''

if 'OperationalStatus' in cim_sys:
- for op_st in cim_sys['OperationalStatus']:
- if op_st == Smis.SystemOperationalStatus.OK:
- status |= System.STATUS_OK
- elif op_st == Smis.SystemOperationalStatus.DEGRADED:
- status |= System.STATUS_DEGRADED
- elif (op_st == Smis.SystemOperationalStatus.ERROR or
- op_st == Smis.SystemOperationalStatus.STRESSED or
- op_st ==
- Smis.SystemOperationalStatus.NON_RECOVERABLE_ERROR):
- status |= System.STATUS_ERROR
- elif op_st == Smis.SystemOperationalStatus.PREDICTIVE_FAILURE:
- status |= System.STATUS_PREDICTIVE_FAILURE
-
- return System(cim_sys['Name'], cim_sys['ElementName'], status, '')
+ (status, status_info) = \
+ DMTF.cim_sys_status_of(cim_sys['OperationalStatus'])
+
+ return System(cim_sys['Name'], cim_sys['ElementName'], status,
+ status_info)

def _cim_sys_pros(self):
"""
@@ -1861,7 +1770,7 @@ class Smis(IStorageAreaNetwork):
cim_sys_pros = self._cim_sys_pros()
cim_syss = self._root_cim_syss(cim_sys_pros)

- return [Smis._cim_sys_2_lsm_sys(s) for s in cim_syss]
+ return [Smis._cim_sys_to_lsm(s) for s in cim_syss]

@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 426b809..990e25c 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -272,79 +272,12 @@ class Volume(IData):
@default_property('status_info', doc="Detail status information of system")
@default_property("plugin_data", doc="Private plugin data")
class System(IData):
- """
-### 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.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
+ STATUS_OTHER = 1 << 5

def __init__(self, _id, _name, _status, _status_info, _plugin_data=None):
self._id = _id
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 3c7a83d..4f22812 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -80,10 +80,6 @@ _SYSTEM_STATUS_CONV = {
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',
}
--
2.1.0
Gris Ge
2014-08-22 14:23:13 UTC
Permalink
Remove these status:
LSM_POOL_STATUS_STRESSED/Pool.STATUS_STRESSED
LSM_POOL_STATUS_READ_ONLY/Pool.STATUS_READ_ONLY
LSM_POOL_STATUS_DORMAT/Pool.STATUS_DORMAT
LSM_POOL_STATUS_SHRINKING/Pool.STATUS_SHRINKING

Signed-off-by: Gris Ge <***@redhat.com>
---
.../include/libstoragemgmt/libstoragemgmt_types.h | 4 ----
python_binding/lsm/_data.py | 4 ----
tools/lsmcli/data_display.py | 28 ++++++++++------------
3 files changed, 12 insertions(+), 24 deletions(-)

diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
index de163a2..b665162 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
@@ -226,20 +226,16 @@ typedef enum {
#define LSM_POOL_STATUS_UNKNOWN 0x0000000000000001
#define LSM_POOL_STATUS_OK 0x0000000000000002
#define LSM_POOL_STATUS_OTHER 0x0000000000000004
-#define LSM_POOL_STATUS_STRESSED 0x0000000000000008
#define LSM_POOL_STATUS_DEGRADED 0x0000000000000010
#define LSM_POOL_STATUS_ERROR 0x0000000000000020
/*#define LSM_POOL_AVAILABLE 0x0000000000000040 */
#define LSM_POOL_STATUS_STARTING 0x0000000000000080
#define LSM_POOL_STATUS_STOPPING 0x0000000000000100
#define LSM_POOL_STATUS_STOPPED 0x0000000000000200
-#define LSM_POOL_STATUS_READ_ONLY 0x0000000000000400
-#define LSM_POOL_STATUS_DORMAT 0x0000000000000800
#define LSM_POOL_STATUS_RECONSTRUCTING 0x0000000000001000
#define LSM_POOL_STATUS_VERIFYING 0x0000000000002000
#define LSM_POOL_STATUS_INITIALIZING 0x0000000000004000
#define LSM_POOL_STATUS_GROWING 0x0000000000008000
-#define LSM_POOL_STATUS_SHRINKING 0x0000000000010000
#define LSM_POOL_STATUS_DESTROYING 0x0000000000020000

#define LSM_POOL_ELEMENT_TYPE_UNKNOWN 0x0000000000000001
diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 990e25c..d435c27 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -320,19 +320,15 @@ class Pool(IData):
STATUS_UNKNOWN = 1 << 0
STATUS_OK = 1 << 1
STATUS_OTHER = 1 << 2
- STATUS_STRESSED = 1 < 3
STATUS_DEGRADED = 1 << 4
STATUS_ERROR = 1 << 5
STATUS_STARTING = 1 << 7
STATUS_STOPPING = 1 << 8
STATUS_STOPPED = 1 << 9
- STATUS_READ_ONLY = 1 << 10
- STATUS_DORMANT = 1 << 11
STATUS_RECONSTRUCTING = 1 << 12
STATUS_VERIFYING = 1 << 13
STATUS_INITIALIZING = 1 << 14
STATUS_GROWING = 1 << 15
- STATUS_SHRINKING = 1 << 16
STATUS_DESTROYING = 1 << 17

def __init__(self, _id, _name, _element_type, _total_space, _free_space,
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 4f22812..fc8c361 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -89,23 +89,19 @@ def system_status_to_str(system_status):


_POOL_STATUS_CONV = {
- Pool.STATUS_UNKNOWN: 'UNKNOWN',
+ Pool.STATUS_UNKNOWN: 'Unknown',
Pool.STATUS_OK: 'OK',
- Pool.STATUS_OTHER: 'OTHER',
- Pool.STATUS_STRESSED: 'STRESSED',
- Pool.STATUS_DEGRADED: 'DEGRADED',
- Pool.STATUS_ERROR: 'ERROR',
- Pool.STATUS_STARTING: 'STARTING',
- Pool.STATUS_STOPPING: 'STOPPING',
- Pool.STATUS_STOPPED: 'STOPPED',
- Pool.STATUS_READ_ONLY: 'READ_ONLY',
- Pool.STATUS_DORMANT: 'DORMANT',
- Pool.STATUS_RECONSTRUCTING: 'RECONSTRUCTING',
- Pool.STATUS_VERIFYING: 'VERIFYING',
- Pool.STATUS_INITIALIZING: 'INITIALIZING',
- Pool.STATUS_GROWING: 'GROWING',
- Pool.STATUS_SHRINKING: 'SHRINKING',
- Pool.STATUS_DESTROYING: 'DESTROYING',
+ Pool.STATUS_OTHER: 'Other',
+ Pool.STATUS_DEGRADED: 'Degraded',
+ Pool.STATUS_ERROR: 'Error',
+ Pool.STATUS_STARTING: 'Starting',
+ Pool.STATUS_STOPPING: 'Stopping',
+ Pool.STATUS_STOPPED: 'Stopped',
+ Pool.STATUS_RECONSTRUCTING: 'Reconstructing',
+ Pool.STATUS_VERIFYING: 'Verifying',
+ Pool.STATUS_INITIALIZING: 'Initializing',
+ Pool.STATUS_GROWING: 'Growing',
+ Pool.STATUS_DESTROYING: 'Destroying',
}
--
2.1.0
Gris Ge
2014-08-22 14:23:14 UTC
Permalink
* Use 'raid-status' and 'status' to detect pool status.
* NetApp volume pool status is copy from its aggregate pool status.
* Tested in ONTAP simulator for these status:
STATUS_DEGRADED
STATUS_STOPPED
STATUS_RECONSTRUCTING
STATUS_GROWING
* Change pool.id as the path of NetApp volume.
# This introduced some bug for lsm.Volume.
# It has been fixed by other patches in this patch set.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/ontap/na.py | 2 +-
plugin/ontap/ontap.py | 163 ++++++++++++++++++++++++++------------------------
2 files changed, 86 insertions(+), 79 deletions(-)

diff --git a/plugin/ontap/na.py b/plugin/ontap/na.py
index 16c3587..fcfb9d4 100644
--- a/plugin/ontap/na.py
+++ b/plugin/ontap/na.py
@@ -226,7 +226,7 @@ class Filer(object):
"""
pools = self._invoke('aggr-list-info')
tmp = pools['aggregates']['aggr-info']
- return [p for p in to_list(tmp) if p['mount-state'] == 'online']
+ return to_list(tmp)

def aggregate_volume_names(self, aggr_name):
"""
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index f6caf62..55599de 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -106,47 +106,6 @@ class Ontap(IStorageAreaNetwork, INfs):

VOLUME_PREFIX = '/vol'

- NA_AGGR_STATUS_TO_LSM = {
- 'creating': Pool.STATUS_STARTING,
- 'destroying': Pool.STATUS_DESTROYING,
- 'failed': Pool.STATUS_ERROR,
- 'frozen': Pool.STATUS_OTHER,
- 'inconsistent': Pool.STATUS_DEGRADED,
- 'iron_restricted': Pool.STATUS_OTHER,
- 'mounting': Pool.STATUS_STARTING,
- 'offline': Pool.STATUS_STOPPED,
- 'online': Pool.STATUS_OK,
- 'partial': Pool.STATUS_ERROR,
- 'quiesced': Pool.STATUS_DORMANT,
- 'quiescing': Pool.STATUS_DORMANT,
- 'restricted': Pool.STATUS_DORMANT,
- 'reverted': Pool.STATUS_OTHER,
- 'unknown': Pool.STATUS_UNKNOWN,
- 'unmounted': Pool.STATUS_STOPPED,
- 'unmounting': Pool.STATUS_STOPPING,
- }
-
- # Use information in https://communities.netapp.com/thread/9052
- # (Also found similar documents in ONTAP 7.3 command Manual Page
- # Reference, Volume 1, PDF Page 18.
- NA_AGGR_STATUS_TO_LSM_STATUS_INFO = {
- 'frozen': 'aggregate is temporarily not accepting requests ' +
- 'and is queueing the requests.',
- 'iron_restricted': 'aggregate access is restricted due to ' +
- 'running wafl_iron.',
- 'partial': 'all the disks in the aggregate are not available.',
- 'quiesced': 'aggregate is temporaily not accepting requests and ' +
- 'returns an error for the request.',
- 'quiescing': 'aggregate is in the process on quiescing and not ' +
- 'accessible.',
- 'restricted': 'aggregate is offline for WAFL',
- 'reverted': 'final state of revert before shutting down ONTAP ' +
- 'and is not accessible.',
- 'unmounted': 'aggregate is unmounted and is not accessible.',
- 'unmounting': 'aggregate is in the process of unmounting and is' +
- 'not accessible.'
- }
-
NA_VOL_STATUS_TO_LSM = {
'offline': Pool.STATUS_STOPPED,
'online': Pool.STATUS_OK,
@@ -313,13 +272,6 @@ class Ontap(IStorageAreaNetwork, INfs):
return search_property(
[self._lun(l) for l in luns], search_key, search_value)

- @staticmethod
- def _pool_id(na_xxx):
- """
- Return na_aggr['uuid'] or na_vol['uuid']
- """
- return na_xxx['uuid']
-
# @staticmethod
# def _raid_type_of_na_aggr(na_aggr):
# na_raid_statuses = na_aggr['raid-status'].split(',')
@@ -333,33 +285,88 @@ class Ontap(IStorageAreaNetwork, INfs):
# return Pool.RAID_TYPE_MIXED
# return Pool.RAID_TYPE_UNKNOWN

+ # This is based on NetApp ONTAP Manual pages:
+ # https://library.netapp.com/ecmdocs/ECMP1196890/html/man1/na_aggr.1.html
+ _AGGR_RAID_STATUS_CONV = {
+ 'normal': Pool.STATUS_OK,
+ 'verifying': Pool.STATUS_VERIFYING,
+ 'copying': Pool.STATUS_INITIALIZING,
+ 'ironing': Pool.STATUS_VERIFYING,
+ 'resyncing': Pool.STATUS_RECONSTRUCTING,
+ 'mirror degraded': Pool.STATUS_DEGRADED,
+ 'needs check': Pool.STATUS_ERROR,
+ 'initializing': Pool.STATUS_INITIALIZING,
+ 'growing': Pool.STATUS_GROWING,
+ 'partial': Pool.STATUS_ERROR,
+ 'noparity': Pool.STATUS_OTHER,
+ 'degraded': Pool.STATUS_DEGRADED,
+ 'reconstruct': Pool.STATUS_RECONSTRUCTING,
+ 'out-of-date': Pool.STATUS_OTHER,
+ 'foreign': Pool.STATUS_OTHER,
+ }
+
+ _AGGR_RAID_ST_INFO_CONV = {
+ 'copying': 'The aggregate is currently the target aggregate of an'
+ 'active aggr copy operation. ',
+ 'invalid': 'The aggregate does not contain any volume and no volume'
+ 'can be added to it. Typically this happens after an '
+ 'aborted aggregate copy operation. ',
+ 'needs check': 'A WAFL consistency check needs to be performed on '
+ 'the aggregate. ',
+ 'partial': 'Two or more disks are missing.',
+ # noparity, no document found.
+ 'noparity': 'NetApp ONTAP mark this aggregate as "noparity". ',
+ # out-of-data: no document found.
+ 'out-of-date': 'NetApp ONTAP mark this aggregate as "out-of-date". ',
+ 'foreign': "The disks that the aggregate contains were moved to the"
+ "current node from another node. "
+ }
+
+
@staticmethod
def _status_of_na_aggr(na_aggr):
"""
- Use aggr-info['state'] for Pool.status
+ Use aggr-info['state'] and ['raid-status'] for Pool.status and
+ status_info.
+ Return (status, status_info)
"""
- na_aggr_state = na_aggr['state']
- if na_aggr_state in Ontap.NA_AGGR_STATUS_TO_LSM.keys():
- return Ontap.NA_AGGR_STATUS_TO_LSM[na_aggr_state]
- return Pool.STATUS_UNKNOWN
+ status = 0
+ status_info = ''
+ na_aggr_raid_status_list = list(
+ x.strip() for x in na_aggr['raid-status'].split(',') )
+ for na_aggr_raid_status in na_aggr_raid_status_list:
+ if na_aggr_raid_status in Ontap._AGGR_RAID_STATUS_CONV.keys():
+ status |= Ontap._AGGR_RAID_STATUS_CONV[na_aggr_raid_status]
+ if na_aggr_raid_status in Ontap._AGGR_RAID_ST_INFO_CONV.keys():
+ status_info += \
+ Ontap._AGGR_RAID_ST_INFO_CONV[na_aggr_raid_status]
+
+ # Now check na_aggr['state']
+ na_aggr_state = na_aggr['state'].strip()
+
+ if na_aggr_state == 'online' or na_aggr_state == 'creating':
+ pass
+ elif na_aggr_state == 'offline':
+ # When aggr is marked as offline, the restruction is stoped.
+ if status & Pool.STATUS_RECONSTRUCTING:
+ status -= Pool.STATUS_RECONSTRUCTING
+ status |= Pool.STATUS_DEGRADED
+ status |= Pool.STATUS_STOPPED
+ else:
+ status_info += "%s " % na_aggr_state

- @staticmethod
- def _status_info_of_na_aggr(na_aggr):
- """
- TODO: provides more information on disk failed.
- """
- na_aggr_state = na_aggr['state']
- if na_aggr_state in Ontap.NA_AGGR_STATUS_TO_LSM_STATUS_INFO.keys():
- return Ontap.NA_AGGR_STATUS_TO_LSM_STATUS_INFO[na_aggr_state]
- return ''
+ if status == 0:
+ status = Pool.STATUS_OK
+
+ return status, status_info

def _pool_from_na_aggr(self, na_aggr, na_disks, flags):
- pool_id = self._pool_id(na_aggr)
+ pool_id = na_aggr['name']
pool_name = na_aggr['name']
total_space = int(na_aggr['size-total'])
free_space = int(na_aggr['size-available'])
system_id = self.sys_info.id
- status = self._status_of_na_aggr(na_aggr)
+ (status, status_info) = self._status_of_na_aggr(na_aggr)

element_type = (Pool.ELEMENT_TYPE_POOL | Pool.ELEMENT_TYPE_FS)

@@ -369,14 +376,7 @@ class Ontap(IStorageAreaNetwork, INfs):
element_type = element_type | Pool.ELEMENT_TYPE_SYS_RESERVED

return Pool(pool_id, pool_name, element_type, total_space, free_space,
- status, self._status_info_of_na_aggr(na_aggr), system_id)
-
- @staticmethod
- def _status_of_na_vol(na_vol):
- na_vol_state = na_vol['state']
- if na_vol_state in Ontap.NA_VOL_STATUS_TO_LSM.keys():
- return Ontap.NA_VOL_STATUS_TO_LSM[na_vol_state]
- return Pool.STATUS_UNKNOWN
+ status, status_info, system_id)

@staticmethod
def _status_info_of_na_vol(na_vol):
@@ -395,21 +395,28 @@ class Ontap(IStorageAreaNetwork, INfs):

def _pool_from_na_vol(self, na_vol, na_aggrs, flags):
element_type = Pool.ELEMENT_TYPE_VOLUME
- pool_id = self._pool_id(na_vol)
- pool_name = self._pool_name_of_na_vol(na_vol)
+ pool_name = na_vol['name']
+ pool_id = self._pool_name_of_na_vol(na_vol)
total_space = int(na_vol['size-total'])
free_space = int(na_vol['size-available'])
system_id = self.sys_info.id
- status = self._status_of_na_vol(na_vol)
+ status = Pool.STATUS_UNKNOWN
+ status_info = ''
+ if 'containing-aggregate' in na_vol:
+ for na_aggr in na_aggrs:
+ if na_aggr['name'] == na_vol['containing-aggregate']:
+ status = self._status_of_na_aggr(na_aggr)[0]
+ if not (status & Pool.STATUS_OK):
+ status_info = "Parrent pool '%s'" \
+ % na_aggr['name']

# This volume should be noted that it is reserved for system
# and thus cannot be removed.
if pool_name == '/vol/vol0':
element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED

- return Pool(pool_id, pool_name, element_type,
- total_space, free_space, status,
- self._status_info_of_na_vol(na_vol), system_id)
+ return Pool(pool_id, pool_name, element_type, total_space, free_space,
+ status, status_info, system_id)

@handle_ontap_errors
def capabilities(self, system, flags=0):
--
2.1.0
Gris Ge
2014-08-22 14:23:15 UTC
Permalink
* Just use the same status converting way of system.
# Sorry, actual changes in dmtf.py is included by previous patches of
# this same patch set.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 62 ++-------------------------------------------------
1 file changed, 2 insertions(+), 60 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 5cc6d09..9d8a2d2 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -318,40 +318,6 @@ class Smis(IStorageAreaNetwork):
DMTF_STATUS_COMPLETED = 17
DMTF_STATUS_POWER_MODE = 18

- # We will rework this once SNIA documented these out.
- _DMTF_STATUS_TO_POOL_STATUS = {
- DMTF_STATUS_UNKNOWN: Pool.STATUS_UNKNOWN,
- DMTF_STATUS_OTHER: Pool.STATUS_OTHER,
- DMTF_STATUS_OK: Pool.STATUS_OK,
- DMTF_STATUS_DEGRADED: Pool.STATUS_DEGRADED,
- DMTF_STATUS_STRESSED: Pool.STATUS_STRESSED,
- DMTF_STATUS_PREDICTIVE_FAILURE: Pool.STATUS_OTHER,
- DMTF_STATUS_ERROR: Pool.STATUS_ERROR,
- DMTF_STATUS_NON_RECOVERABLE_ERROR: Pool.STATUS_ERROR,
- DMTF_STATUS_STARTING: Pool.STATUS_STARTING,
- DMTF_STATUS_STOPPING: Pool.STATUS_STOPPING,
- DMTF_STATUS_STOPPED: Pool.STATUS_STOPPED,
- DMTF_STATUS_IN_SERVICE: Pool.STATUS_OTHER,
- DMTF_STATUS_NO_CONTACT: Pool.STATUS_OTHER,
- DMTF_STATUS_LOST_COMMUNICATION: Pool.STATUS_OTHER,
- DMTF_STATUS_DORMANT: Pool.STATUS_DORMANT,
- DMTF_STATUS_SUPPORTING_ENTITY_IN_ERROR: Pool.STATUS_OTHER,
- DMTF_STATUS_COMPLETED: Pool.STATUS_OTHER,
- DMTF_STATUS_POWER_MODE: Pool.STATUS_OTHER,
- }
-
- _DMTF_STATUS_TO_POOL_STATUS_INFO = {
- # TODO: Use CIM_RelatedElementCausingError
- # to find out the error info.
- DMTF_STATUS_PREDICTIVE_FAILURE: 'Predictive failure',
- DMTF_STATUS_IN_SERVICE: 'In service',
- DMTF_STATUS_NO_CONTACT: 'No contact',
- DMTF_STATUS_LOST_COMMUNICATION: 'Lost communication',
- DMTF_STATUS_SUPPORTING_ENTITY_IN_ERROR: 'Supporting entity in error',
- DMTF_STATUS_COMPLETED: 'Completed',
- DMTF_STATUS_POWER_MODE: 'Power mode',
- }
-
_DMTF_STATUS_TO_DISK_STATUS = {
DMTF_STATUS_UNKNOWN: Disk.STATUS_UNKNOWN,
DMTF_STATUS_OTHER: Disk.STATUS_OTHER,
@@ -1727,8 +1693,8 @@ class Smis(IStorageAreaNetwork):
if 'RemainingManagedSpace' in cim_pool:
free_space = cim_pool['RemainingManagedSpace']
if 'OperationalStatus' in cim_pool:
- status = Smis._pool_status_of(cim_pool)[0]
- status_info = Smis._pool_status_of(cim_pool)[1]
+ (status, status_info) = DMTF.cim_pool_status_of(
+ cim_pool['OperationalStatus'])

element_type = self._pool_element_type(cim_pool)

@@ -3250,30 +3216,6 @@ class Smis(IStorageAreaNetwork):
"CIM_StorageExtent for CIM_DiskDrive %s " %
cim_disk_path)

- @staticmethod
- def _pool_status_of(cim_pool):
- """
- Converting CIM_StoragePool['OperationalStatus'] LSM Pool.status.
- This might change since OperationalStatus does not provide enough
- information.
- Return (status, status_info)
- """
- status = Pool.STATUS_UNKNOWN
- status_info = []
- dmtf_statuses = cim_pool['OperationalStatus']
- for dmtf_status in dmtf_statuses:
- if dmtf_status in Smis._DMTF_STATUS_TO_POOL_STATUS.keys():
-
- lsm_status = Smis._DMTF_STATUS_TO_POOL_STATUS[dmtf_status]
- if status == Pool.STATUS_UNKNOWN:
- status = lsm_status
- else:
- status |= lsm_status
- if dmtf_status in Smis._DMTF_STATUS_TO_POOL_STATUS_INFO.keys():
- status_info.append(
- Smis._DMTF_STATUS_TO_POOL_STATUS_INFO[dmtf_status])
- return (status, ", ".join(status_info))
-
def _cim_disk_of_pri_ext(self, cim_pri_ext_path, pros_list=None):
"""
Follow this procedure to find out CIM_DiskDrive from Primordial
--
2.1.0
Gris Ge
2014-08-22 14:23:16 UTC
Permalink
* Remove Volume.state
Currently, volume status is fully inherited from pool. There is no need
to maintain two status.
For volume individual thin provisioning status, we can discuss that
when plugin need it.
* Add Volume.admin_state
Indicate whether this volume is disabled by administrator or not.
Just two integer:
ADMIN_STATE_DISABLED = 0
ADMIN_STATE_ENABLED = 1

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/lsm/_data.py | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index d435c27..875d773 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -220,7 +220,7 @@ class Disk(IData):
@default_property('vpd83', doc="Vital product page 0x83 identifier")
@default_property('block_size', doc="Volume block size")
@default_property('num_of_blocks', doc="Number of blocks")
-@default_property('status', doc="Enumerated volume status")
+@default_property('admin_state', doc="Enabled or disabled by administrator")
@default_property('system_id', doc="System identifier")
@default_property('pool_id', doc="Pool identifier")
@default_property("plugin_data", doc="Private plugin data")
@@ -229,10 +229,6 @@ class Volume(IData):
Represents a volume.
"""
SUPPORTED_SEARCH_KEYS = ['id', 'system_id', 'pool_id']
- # Volume status Note: Volumes can have multiple status bits set at same
- # time.
- (STATUS_UNKNOWN, STATUS_OK, STATUS_DEGRADED, STATUS_ERR, STATUS_STARTING,
- STATUS_DORMANT) = (0x0, 0x1, 0x2, 0x4, 0x8, 0x10)

#Replication types
(REPLICATE_UNKNOWN, REPLICATE_SNAPSHOT, REPLICATE_CLONE, REPLICATE_COPY,
@@ -243,14 +239,17 @@ class Volume(IData):
(PROVISION_UNKNOWN, PROVISION_THIN, PROVISION_FULL, PROVISION_DEFAULT) = \
(-1, 1, 2, 3)

+ ADMIN_STATE_DISABLED = 0
+ ADMIN_STATE_ENABLED = 1
+
def __init__(self, _id, _name, _vpd83, _block_size, _num_of_blocks,
- _status, _system_id, _pool_id, _plugin_data=None):
+ _admin_state, _system_id, _pool_id, _plugin_data=None):
self._id = _id # Identifier
self._name = _name # Human recognisable name
self._vpd83 = _vpd83 # SCSI page 83 unique ID
self._block_size = _block_size # Block size
self._num_of_blocks = _num_of_blocks # Number of blocks
- self._status = _status # Status
+ self._admin_state = _admin_state # enable or disabled by admin
self._system_id = _system_id # System id this volume belongs
self._pool_id = _pool_id # Pool id this volume belongs
self._plugin_data = _plugin_data
--
2.1.0
Gris Ge
2014-08-22 14:23:18 UTC
Permalink
* Remove Volume.state. Add Volume.admin_state.
The Volume.admin_state will be shown as 'Dsiabled: Yes' or 'Disabled: No'
Example:
lsmcli lv -s
------------------------------------------------
ID | VOL_ID_00000001
Name | Volume 000
SCSI VPD 0x83 | 29D2EBE29486EDA9055AF9234263A664
Block Size | 512
#blocks | 419430400
Size | 214748364800
Disabled | No
Pool ID | POO1
System ID | sim-01
------------------------------------------------
ID | VOL_ID_00000002
Name | Volume 001
SCSI VPD 0x83 | AD1E85E3FA30F423498C5751EC56AB82
Block Size | 512
#blocks | 419430400
Size | 214748364800
Disabled | No
Pool ID | POO1
System ID | sim-01
------------------------------------------------


Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/data_display.py | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index fc8c361..371247d 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -123,16 +123,6 @@ def pool_element_type_to_str(element_type):
return _bit_map_to_str(element_type, _POOL_ELEMENT_TYPE_CONV)


-_VOL_STATUS_CONV = {
- Volume.STATUS_UNKNOWN: 'Unknown',
- Volume.STATUS_OK: 'OK',
- Volume.STATUS_DEGRADED: 'Degraded',
- Volume.STATUS_DORMANT: 'Dormant',
- Volume.STATUS_ERR: 'Error',
- Volume.STATUS_STARTING: 'Starting',
-}
-
-
_VOL_PROVISION_CONV = {
Volume.PROVISION_DEFAULT: 'DEFAULT',
Volume.PROVISION_FULL: 'FULL',
@@ -145,6 +135,16 @@ def vol_provision_str_to_type(vol_provision_str):
return _str_to_enum(vol_provision_str, _VOL_PROVISION_CONV)


+_VOL_ADMIN_STATE_CONV = {
+ Volume.ADMIN_STATE_DISABLED: 'Yes',
+ Volume.ADMIN_STATE_ENABLED: 'No',
+}
+
+
+def vol_admin_state_to_str(vol_admin_state):
+ return _enum_type_to_str(vol_admin_state, _VOL_ADMIN_STATE_CONV)
+
+
_VOL_REP_TYPE_CONV = {
Volume.REPLICATE_SNAPSHOT: 'SNAPSHOT',
Volume.REPLICATE_CLONE: 'CLONE',
@@ -159,10 +159,6 @@ def vol_rep_type_str_to_type(vol_rep_type_str):
return _str_to_enum(vol_rep_type_str, _VOL_REP_TYPE_CONV)


-def vol_status_to_str(vol_status):
- return _bit_map_to_str(vol_status, _VOL_STATUS_CONV)
-
-
_DISK_TYPE_CONV = {
Disk.DISK_TYPE_UNKNOWN: 'UNKNOWN',
Disk.DISK_TYPE_OTHER: 'OTHER',
@@ -330,7 +326,7 @@ class DisplayData(object):
VOL_MAN_HEADER['block_size'] = 'Block Size'
VOL_MAN_HEADER['num_of_blocks'] = '#blocks'
VOL_MAN_HEADER['size_bytes'] = 'Size'
- VOL_MAN_HEADER['status'] = 'Status'
+ VOL_MAN_HEADER['admin_state'] = 'Disabled'
VOL_MAN_HEADER['pool_id'] = 'Pool ID'
VOL_MAN_HEADER['system_id'] = 'System ID'

@@ -341,7 +337,7 @@ class DisplayData(object):
VOL_COLUMN_KEYS.extend([key_name])

VOL_VALUE_CONV_ENUM = {
- 'status': vol_status_to_str,
+ 'admin_state': vol_admin_state_to_str
}

VOL_VALUE_CONV_HUMAN = ['size_bytes', 'block_size']
--
2.1.0
Gris Ge
2014-08-22 14:23:19 UTC
Permalink
* Add volume_enable() and volume_disable() support.
* Add aliases:
ve == volume-enable
vi == volume-disable

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/cmdline.py | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index d520733..287f7f1 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -343,6 +343,22 @@ cmds = (
),

dict(
+ name='volume-enable',
+ help='Enable block access of a volume',
+ args=[
+ dict(vol_id_opt),
+ ],
+ ),
+
+ dict(
+ name='volume-disable',
+ help='Disable block access of a volume',
+ args=[
+ dict(vol_id_opt),
+ ],
+ ),
+
+ dict(
name='access-group-create',
help='Create an access group',
args=[
@@ -592,6 +608,8 @@ aliases = (
['vr', 'volume-resize'],
['vm', 'volume-mask'],
['vu', 'volume-unmask'],
+ ['ve', 'volume-enable'],
+ ['vi', 'volume-disable'],
['ac', 'access-group-create'],
['aa', 'access-group-add'],
['ar', 'access-group-remove'],
@@ -1251,6 +1269,16 @@ class CmdLine:
*self.c.volume_resize(v, size))
self.display_data([vol])

+ ## Enable a volume
+ def volume_enable(self, args):
+ v = _get_item(self.c.volumes(), args.vol, "volume id")
+ self.c.volume_enable(v)
+
+ ## Disable a volume
+ def volume_disable(self, args):
+ v = _get_item(self.c.volumes(), args.vol, "volume id")
+ self.c.volume_disable(v)
+
## Removes a nfs export
def fs_unexport(self, args):
export = _get_item(self.c.exports(), args.export, "nfs export id")
--
2.1.0
Gris Ge
2014-08-22 14:23:20 UTC
Permalink
* Remove Volume.state, add Volume.admin_state

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/nstor/nstor.py | 21 +++------------------
1 file changed, 3 insertions(+), 18 deletions(-)

diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index 3188962..c5e3ef1 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -462,27 +462,12 @@ class NexentaStor(INfs, IStorageAreaNetwork):
block_size = NexentaStor._to_bytes(zvol_props['volblocksize'])
size_bytes = int(zvol_props['size_bytes'])
num_of_blocks = size_bytes / block_size
-
- # Not sure what all the different status are...
- # Api doc shows, but I may be looking at the wrong thing:
- # "ONLINE", "DEGRADED", "FAULTED", "OFFLINE", "REMOVED", "UNAVAIL"
- states_conv = {"ONLINE": Volume.STATUS_OK,
- "DEGRADED": Volume.STATUS_DEGRADED,
- "FAULTED": Volume.STATUS_ERR,
- "OFFLINE": Volume.STATUS_DORMANT,
- "REMOVED": Volume.STATUS_ERR,
- "UNAVAIL": Volume.STATUS_ERR}
-
- vol_state = str(lu_props['state']).upper()
-
- if vol_state in states_conv:
- state = states_conv[vol_state]
- else:
- state = Volume.STATUS_UNKNOWN
+ admin_state = Volume.ADMIN_STATE_ENABLED

vol_list.append(
Volume(lu, lu, lu_props['guid'], block_size, num_of_blocks,
- state, 'N/A', NexentaStor._get_pool_id(lu)))
+ admin_state, self._system.id,
+ NexentaStor._get_pool_id(lu)))

return search_property(vol_list, search_key, search_value)
--
2.1.0
Gris Ge
2014-08-22 14:23:22 UTC
Permalink
* Remove Volume.state, add Volume.admin_state
* Convert num_of_blocks to long.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/targetd/targetd.py | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/plugin/targetd/targetd.py b/plugin/targetd/targetd.py
index d3af6be..989dbf5 100644
--- a/plugin/targetd/targetd.py
+++ b/plugin/targetd/targetd.py
@@ -165,8 +165,9 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
for vol in self._jsonrequest("vol_list", dict(pool=p_name)):
volumes.append(
Volume(vol['uuid'], vol['name'], vol['uuid'], 512,
- vol['size'] / 512, Volume.STATUS_OK, self.system.id,
- p_name))
+ long(vol['size'] / 512),
+ Volume.ADMIN_STATE_ENABLED,
+ self.system.id, p_name))
return search_property(volumes, search_key, search_value)

@handle_errors
@@ -340,16 +341,6 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
return None, self._get_volume(pool_id, name)

@handle_errors
- def volume_online(self, volume, flags=0):
- vol_list = self._jsonrequest("vol_list", dict(pool=volume.pool_id))
-
- return volume.name in [vol['name'] for vol in vol_list]
-
- @handle_errors
- def volume_offline(self, volume, flags=0):
- return not self.volume_online(volume)
-
- @handle_errors
def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
out_password, flags=0):
self._jsonrequest("initiator_set_auth",
--
2.1.0
Gris Ge
2014-08-22 14:23:23 UTC
Permalink
* Data version bump to 2.8.
* Add sim_vol['admin_state'] storing Volume.admin_state.
* Add support of volume_enable() and volume_disable()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/sim/simarray.py | 43 +++++++++++++++++++++++++++----------------
plugin/sim/simulator.py | 8 ++++----
2 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index 143c11e..00c39b2 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -205,7 +205,8 @@ class SimArray(object):
return Volume(sim_vol['vol_id'], sim_vol['name'], sim_vol['vpd83'],
SimData.SIM_DATA_BLK_SIZE,
int(sim_vol['total_space'] / SimData.SIM_DATA_BLK_SIZE),
- Volume.STATUS_OK, sim_vol['sys_id'], sim_vol['pool_id'])
+ sim_vol['admin_state'], sim_vol['sys_id'],
+ sim_vol['pool_id'])

def volumes(self):
sim_vols = self.data.volumes()
@@ -272,11 +273,11 @@ class SimArray(object):
self.data.volume_replicate_range(
rep_type, src_vol_id, dst_vol_id, ranges, flags))[0]

- def volume_online(self, vol_id, flags=0):
- return self.data.volume_online(vol_id, flags)
+ def volume_enable(self, vol_id, flags=0):
+ return self.data.volume_enable(vol_id, flags)

- def volume_offline(self, vol_id, flags=0):
- return self.data.volume_offline(vol_id, flags)
+ def volume_disable(self, vol_id, flags=0):
+ return self.data.volume_disable(vol_id, flags)

def volume_child_dependency(self, vol_id, flags=0):
return self.data.volume_child_dependency(vol_id, flags)
@@ -449,6 +450,7 @@ class SimData(object):
'sys_id': SimData.SIM_DATA_SYS_ID,
'pool_id': owner_pool_id,
'consume_size': size_bytes,
+ 'admin_state': Volume.ADMIN_STATE_ENABLED,
'replicate': {
dst_vol_id = [
{
@@ -540,7 +542,7 @@ class SimData(object):
}
"""
SIM_DATA_BLK_SIZE = 512
- SIM_DATA_VERSION = "2.7"
+ SIM_DATA_VERSION = "2.8"
SIM_DATA_SYS_ID = 'sim-01'
SIM_DATA_INIT_NAME = 'NULL'
SIM_DATA_TMO = 30000 # ms
@@ -930,6 +932,7 @@ class SimData(object):
sim_vol['sys_id'] = SimData.SIM_DATA_SYS_ID
sim_vol['pool_id'] = pool_id
sim_vol['consume_size'] = size_bytes
+ sim_vol['admin_state'] = Volume.ADMIN_STATE_ENABLED
self.vol_dict[sim_vol['vol_id']] = sim_vol
return sim_vol

@@ -1040,22 +1043,30 @@ class SimData(object):

return None

- def volume_online(self, vol_id, flags=0):
- if vol_id not in self.vol_dict.keys():
+ def volume_enable(self, vol_id, flags=0):
+ try:
+ if self.vol_dict[vol_id]['admin_state'] == \
+ Volume.ADMIN_STATE_ENABLED:
+ raise LsmError(ErrorNumber.NO_STATE_CHANGE,
+ "Volume is already enabled")
+ except KeyError:
raise LsmError(ErrorNumber.NOT_FOUND_VOLUME,
"No such Volume: %s" % vol_id)
- # TODO: Volume.STATUS_XXX does have indication about volume offline
- # or online, meanwhile, cmdline does not support volume_online()
- # yet
+
+ self.vol_dict[vol_id]['admin_state'] = Volume.ADMIN_STATE_ENABLED
return None

- def volume_offline(self, vol_id, flags=0):
- if vol_id not in self.vol_dict.keys():
+ def volume_disable(self, vol_id, flags=0):
+ try:
+ if self.vol_dict[vol_id]['admin_state'] == \
+ Volume.ADMIN_STATE_DISABLED:
+ raise LsmError(ErrorNumber.NO_STATE_CHANGE,
+ "Volume is already disabled")
+ except KeyError:
raise LsmError(ErrorNumber.NOT_FOUND_VOLUME,
"No such Volume: %s" % vol_id)
- # TODO: Volume.STATUS_XXX does have indication about volume offline
- # or online, meanwhile, cmdline does not support volume_online()
- # yet
+
+ self.vol_dict[vol_id]['admin_state'] = Volume.ADMIN_STATE_DISABLED
return None

def volume_child_dependency(self, vol_id, flags=0):
diff --git a/plugin/sim/simulator.py b/plugin/sim/simulator.py
index 46fc08b..79b6df5 100644
--- a/plugin/sim/simulator.py
+++ b/plugin/sim/simulator.py
@@ -146,11 +146,11 @@ class SimPlugin(INfs, IStorageAreaNetwork):
return self.sim_array.volume_replicate_range(
rep_type, volume_src.id, volume_dest.id, ranges, flags)

- def volume_online(self, volume, flags=0):
- return self.sim_array.volume_online(volume.id, flags)
+ def volume_enable(self, volume, flags=0):
+ return self.sim_array.volume_enable(volume.id, flags)

- def volume_offline(self, volume, flags=0):
- return self.sim_array.volume_online(volume.id, flags)
+ def volume_disable(self, volume, flags=0):
+ return self.sim_array.volume_disable(volume.id, flags)

def access_groups(self, search_key=None, search_value=None, flags=0):
sim_ags = self.sim_array.ags()
--
2.1.0
Gris Ge
2014-08-22 14:23:24 UTC
Permalink
* Fix bug introduced by changing NetApp volume pool id to path.
* Remove Volume.status and add Volume.admin_status
* Add error handling to volume_disable() and volume_enable().

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/ontap/na.py | 56 +++++++--------------------------------------------
plugin/ontap/ontap.py | 46 +++++++++++++++++++++++++++---------------
2 files changed, 37 insertions(+), 65 deletions(-)

diff --git a/plugin/ontap/na.py b/plugin/ontap/na.py
index fcfb9d4..89d58c1 100644
--- a/plugin/ontap/na.py
+++ b/plugin/ontap/na.py
@@ -137,9 +137,13 @@ class FilerError(Exception):
IGROUP_NOT_CONTAIN_GIVEN_INIT = 9007
IGROUP_ALREADY_HAS_INIT = 9008
NO_SUCH_IGROUP = 9003
+
+ # Using the name from NetApp SDK netapp_errno.h
EVDISK_ERROR_VDISK_EXPORTED = 9013 # LUN is currently mapped
EVDISK_ERROR_INITGROUP_MAPS_EXIST = 9029 # LUN maps for this initiator
# group exist
+ EVDISK_ERROR_VDISK_NOT_ENABLED = 9014 # LUN is not online
+ EVDISK_ERROR_VDISK_NOT_DISABLED = 9015 # LUN is not offline

def __init__(self, errno, reason, *args, **kwargs):
Exception.__init__(self, *args, **kwargs)
@@ -263,17 +267,7 @@ class Filer(object):
else:
luns = self._invoke('lun-list-info')

- tmp = luns['luns']
-
- if tmp is not None:
- rc = to_list(tmp['lun-info'])
-
- if len(rc):
- #Add a key/value for aggr to hash so upper layers have it.
- for i in range(len(rc)):
- rc[i]['aggr'] = aggr
-
- return rc
+ return to_list(luns['luns']['lun-info'])

def _get_aggr_info(self):
aggrs = self._invoke('aggr-list-info')
@@ -282,45 +276,9 @@ class Filer(object):

def luns_get_all(self):
"""
- More efficient approach to retrieving all the luns
-
- Note: A NetApp lun is a file on a NetApp volume (file system)
- so to do this correctly we need to return the NetApp volume
- that a logical unit file resides on, not the base aggregate
- that the file on the fs lies on.
-
-
+ Return all lun-info
"""
- rc = []
- lookup = {}
- na_volume_to_uuid = {}
- aggr_list = self._get_aggr_info()
-
- #Build volume name to uuid lookup
- for p in aggr_list:
- volumes = to_list(p['volumes']['contained-volume-info'])
- for v in volumes:
- lookup[v['name']] = p['uuid']
-
- # Get a list of NetApp volumes
- na_volumes = self.volumes()
- for p in na_volumes:
- vol_name = p['name']
-
- if vol_name.startswith(Filer.LSM_VOL_PREFIX):
- na_volume_to_uuid[vol_name] = lookup[vol_name]
- else:
- na_volume_to_uuid[vol_name] = p['uuid']
-
- luns = self._invoke('lun-list-info')['luns']
-
- if luns is not None:
- rc = to_list(luns['lun-info'])
- if len(rc):
- for i in range(len(rc)):
- volume_name = rc[i]['path'].split('/')[2]
- rc[i]['aggr'] = na_volume_to_uuid[volume_name]
- return rc
+ return to_list(self._invoke('lun-list-info')['luns']['lun-info'])

def lun_create(self, full_path_name, size_bytes):
"""
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index 55599de..bb76a11 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -164,14 +164,19 @@ class Ontap(IStorageAreaNetwork, INfs):
return os.path.basename(path_name)

def _lun(self, l):
- #Info('_lun=' + str(l))
block_size = int(l['block-size'])
num_blocks = int(l['size']) / block_size
+ pool_id = "/".join(l['path'].split('/')[0:3])
+ vol_id = l['path']
+ vol_name = os.path.basename(vol_id)
+ admin_state = Volume.ADMIN_STATE_ENABLED
+ if l['online'] == 'false':
+ admin_state = Volume.ADMIN_STATE_DISABLED
+
#TODO: Need to retrieve actual volume status
- return Volume(l['path'], self._lsm_lun_name(l['path']),
+ return Volume(vol_id, vol_name,
Ontap._create_vpd(l['serial-number']), block_size,
- num_blocks, Volume.STATUS_OK, self.sys_info.id,
- l['aggr'])
+ num_blocks, admin_state, self.sys_info.id, pool_id)

def _vol(self, v, pools=None):
pool_name = v['containing-aggregate']
@@ -386,17 +391,13 @@ class Ontap(IStorageAreaNetwork, INfs):
return ''

@staticmethod
- def _pool_name_of_na_vol(na_vol):
- return "%s/%s" % (Ontap.VOLUME_PREFIX, na_vol['name'])
-
- @staticmethod
- def _na_vol_name_of_pool(pool):
- return pool.name.split('/')[-1]
+ def _pool_id_of_na_vol_name(na_vol_name):
+ return "%s/%s" % (Ontap.VOLUME_PREFIX, na_vol_name)

def _pool_from_na_vol(self, na_vol, na_aggrs, flags):
element_type = Pool.ELEMENT_TYPE_VOLUME
pool_name = na_vol['name']
- pool_id = self._pool_name_of_na_vol(na_vol)
+ pool_id = self._pool_id_of_na_vol_name(na_vol['name'])
total_space = int(na_vol['size-total'])
free_space = int(na_vol['size-available'])
system_id = self.sys_info.id
@@ -409,6 +410,7 @@ class Ontap(IStorageAreaNetwork, INfs):
if not (status & Pool.STATUS_OK):
status_info = "Parrent pool '%s'" \
% na_aggr['name']
+ break

# This volume should be noted that it is reserved for system
# and thus cannot be removed.
@@ -508,7 +510,7 @@ class Ontap(IStorageAreaNetwork, INfs):
raise LsmError(ErrorNumber.INVALID_ARGUMENT,
"Pool not suitable for creating volumes")

- na_vol_name = self._na_vol_name_of_pool(pool)
+ na_vol_name = pool.name
v = self.f.volume_names()
if na_vol_name not in v:
raise LsmError(ErrorNumber.NOT_FOUND_POOL, "Pool not found")
@@ -586,12 +588,24 @@ class Ontap(IStorageAreaNetwork, INfs):
_lsm_vol_to_na_vol_path(volume_dest), None, ranges)

@handle_ontap_errors
- def volume_online(self, volume, flags=0):
- return self.f.lun_online(_lsm_vol_to_na_vol_path(volume))
+ def volume_enable(self, volume, flags=0):
+ try:
+ return self.f.lun_online(_lsm_vol_to_na_vol_path(volume))
+ except na.FilerError as fe:
+ if fe.errno == na.FilerError.EVDISK_ERROR_VDISK_NOT_DISABLED:
+ raise LsmError(ErrorNumber.NO_STATE_CHANGE,
+ "Volume is already enabled")
+ raise

@handle_ontap_errors
- def volume_offline(self, volume, flags=0):
- return self.f.lun_offline(_lsm_vol_to_na_vol_path(volume))
+ def volume_disable(self, volume, flags=0):
+ try:
+ return self.f.lun_offline(_lsm_vol_to_na_vol_path(volume))
+ except na.FilerError as fe:
+ if fe.errno == na.FilerError.EVDISK_ERROR_VDISK_NOT_ENABLED:
+ raise LsmError(ErrorNumber.NO_STATE_CHANGE,
+ "Volume is already disabled")
+ raise

@handle_ontap_errors
def volume_mask(self, access_group, volume, flags=0):
--
2.1.0
Gris Ge
2014-08-22 14:23:17 UTC
Permalink
* Rename volume_online() to volume_enable() and _offline() to _disable().
The word 'online' might mis-leading user to health.
But we actually indicate this method is for volume admin state.

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/lsm/_client.py | 14 +++++++-------
python_binding/lsm/_iplugin.py | 4 ++--
2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/python_binding/lsm/_client.py b/python_binding/lsm/_client.py
index 0a9a75a..6b8e111 100644
--- a/python_binding/lsm/_client.py
+++ b/python_binding/lsm/_client.py
@@ -461,14 +461,14 @@ class Client(INetworkAttachedStorage):
# @param volume The volume to place online
# @param flags Reserved for future use, must be zero.
# @returns None on success, else raises LsmError
- @_return_requires(unicode)
- def volume_online(self, volume, flags=0):
+ @_return_requires(None)
+ def volume_enable(self, volume, flags=0):
"""
Makes a volume available to the host

returns None on success, else raises LsmError on errors.
"""
- return self._tp.rpc('volume_online', _del_self(locals()))
+ return self._tp.rpc('volume_enable', _del_self(locals()))

## Takes a volume offline
# @param self The this pointer
@@ -476,13 +476,13 @@ class Client(INetworkAttachedStorage):
# @param flags Reserved for future use, must be zero.
# @returns None on success, else raises LsmError on errors.
@_return_requires(None)
- def volume_offline(self, volume, flags=0):
+ def volume_disable(self, volume, flags=0):
"""
Makes a volume unavailable to the host

returns None on success, else raises LsmError on errors.
"""
- return self._tp.rpc('volume_offline', _del_self(locals()))
+ return self._tp.rpc('volume_disable', _del_self(locals()))

## Returns an array of disk objects
# @param self The this pointer
@@ -1055,8 +1055,8 @@ class _TestClient(unittest.TestCase):

self.assertTrue(vol.size_bytes == re_sized.size_bytes / 2)

- self.c.volume_offline(re_sized)
- self.c.volume_online(re_sized)
+ self.c.volume_disable(re_sized)
+ self.c.volume_enable(re_sized)

def tearDown(self):
self.c.close()
diff --git a/python_binding/lsm/_iplugin.py b/python_binding/lsm/_iplugin.py
index 3188405..17d99ee 100644
--- a/python_binding/lsm/_iplugin.py
+++ b/python_binding/lsm/_iplugin.py
@@ -200,7 +200,7 @@ class IStorageAreaNetwork(IPlugin):
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")

- def volume_online(self, volume, flags=0):
+ def volume_enable(self, volume, flags=0):
"""
Makes a volume available to the host

@@ -208,7 +208,7 @@ class IStorageAreaNetwork(IPlugin):
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")

- def volume_offline(self, volume, flags=0):
+ def volume_disable(self, volume, flags=0):
"""
Makes a volume unavailable to the host
--
2.1.0
Gris Ge
2014-08-22 14:23:21 UTC
Permalink
* Remove Volume.state, add Volume.admin_state
* Remove volume_online() and volume_offline(). We should let iplugin.py
raise NO_SUPPORT instead of silently return pass.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 31 ++++---------------------------
1 file changed, 4 insertions(+), 27 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 9d8a2d2..8dbf3e4 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -1268,7 +1268,7 @@ class Smis(IStorageAreaNetwork):
"""
Retrun the PropertyList required for creating new LSM Volume.
"""
- props = ['OperationalStatus', 'ElementName', 'NameFormat',
+ props = ['ElementName', 'NameFormat',
'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage']
cim_vol_pros = self._property_list_of_id("Volume", props)
@@ -1279,23 +1279,6 @@ class Smis(IStorageAreaNetwork):
Takes a CIMInstance that represents a volume and returns a lsm Volume
"""

- # Reference page 134 in 1.5 spec.
- status = Volume.STATUS_UNKNOWN
-
- # OperationalStatus is mandatory
- if 'OperationalStatus' in cv:
- for s in cv["OperationalStatus"]:
- if s == Smis.VOL_OP_STATUS_OK:
- status |= Volume.STATUS_OK
- elif s == Smis.VOL_OP_STATUS_DEGRADED:
- status |= Volume.STATUS_DEGRADED
- elif s == Smis.VOL_OP_STATUS_ERR:
- status |= Volume.STATUS_ERR
- elif s == Smis.VOL_OP_STATUS_STARTING:
- status |= Volume.STATUS_STARTING
- elif s == Smis.VOL_OP_STATUS_DORMANT:
- status |= Volume.STATUS_DORMANT
-
# This is optional (User friendly name)
if 'ElementName' in cv:
user_name = cv["ElementName"]
@@ -1322,8 +1305,10 @@ class Smis(IStorageAreaNetwork):
if sys_id is None:
sys_id = cv['SystemName']

+ admin_state = Volume.ADMIN_STATE_ENABLED
+
return Volume(self._vol_id(cv), user_name, vpd_83, cv["BlockSize"],
- cv["NumberOfBlocks"], status, sys_id, pool_id)
+ cv["NumberOfBlocks"], admin_state, sys_id, pool_id)

@staticmethod
def _vpd83_in_cv_name(cv):
@@ -2007,14 +1992,6 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")

- @handle_cim_errors
- def volume_online(self, volume, flags=0):
- return None
-
- @handle_cim_errors
- def volume_offline(self, volume, flags=0):
- return None
-
def _get_cim_service_path(self, cim_sys_path, class_name):
"""
Return None if not supported
--
2.1.0
Loading...