Discussion:
[Libstoragemgmt-devel] [PATCH 00/18] Pending patches
Tony Asleson
2014-10-15 04:46:23 UTC
Permalink
Gris,

Please take a look at this patch set. This is the pending patches I
have. I made changes to one of your patches:
"SMI-S Plugin: Check duplicate name in volume_replicate".
See updated patch for details.

If everything looks OK I want to commit. This patch series is looking
good in testing.

Thanks,
Tony

Gris Ge (12):
SMI-S plugin: Refactor, add smis_common.py, utils.py, dmtf.py files
SMI-S plugin: Refactor, remove eseries.py, smisproxy.py files
SMI-S Plugin: Refactor, add smis_sys.py
SMI-S Plugin: Refactor, add smis_pool.py file
SMI-S Plugin: Refactor, add smis_disk.py file.
SMI-S Plugin: Refactor dmtf.py
SMI-S Plugin: Refactor, remove smis_constants.py
SMI-S Plugin: Workaround for volume name duplication check after job
creation.
SMI-S Plugin: Check duplicate name in volume_replicate()
Plugin test: Fix incorrect NAME_CONFLICT check in
test_volume_replication()
lsmcli: new alias lt = lsmcli list --type target_ports
lsmenv: Integrate with plugin_test.py

Tony Asleson (6):
SMI-S plugin: Refactor, add smis_cap.py, smis_constants.py files
simarray.py: Lock state file
Fix mem leaks in lsm_daemon.c, simc_lsmplugin.c
rpm spec: Use correct tmpfiles.d dir
rpm spec: Move command line python files to python package
rpm spec: udev files to /usr/lib dir instead of /lib

daemon/lsm_daemon.c | 6 +-
doc/man/lsmcli.1.in | 2 +
packaging/libstoragemgmt.spec.in | 39 +-
plugin/Makefile.am | 10 +-
plugin/sim/simarray.py | 22 +-
plugin/simc/simc_lsmplugin.c | 3 +
plugin/smispy/dmtf.py | 403 +++----
plugin/smispy/eseries.py | 164 ---
plugin/smispy/smis.py | 2141 ++++++++------------------------------
plugin/smispy/smis_cap.py | 384 +++++++
plugin/smispy/smis_common.py | 374 +++++++
plugin/smispy/smis_disk.py | 195 ++++
plugin/smispy/smis_pool.py | 285 +++++
plugin/smispy/smis_sys.py | 149 +++
plugin/smispy/smisproxy.py | 51 -
plugin/smispy/smispy_lsmplugin | 4 +-
plugin/smispy/utils.py | 68 ++
test/plugin_test.py | 17 +-
tools/lsmcli/cmdline.py | 1 +
tools/lsmenv | 40 +-
20 files changed, 2195 insertions(+), 2163 deletions(-)
delete mode 100644 plugin/smispy/eseries.py
create mode 100644 plugin/smispy/smis_cap.py
create mode 100644 plugin/smispy/smis_common.py
create mode 100644 plugin/smispy/smis_disk.py
create mode 100644 plugin/smispy/smis_pool.py
create mode 100644 plugin/smispy/smis_sys.py
delete mode 100644 plugin/smispy/smisproxy.py
create mode 100644 plugin/smispy/utils.py
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:28 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Empty smis_pool.py with license only.
* Makefile and RPM spec file updated.
* Replace Smis._cim_pools_of() with smis_pool.cim_pools_of_cim_sys_path()
* Merge the pool filtering(remove spare pool and other unused pool) into
smis_pool.cim_pools_of_cim_sys_path().
With this, it save some WBEM calls[1] in volumes().
Performance changes for volumes()(lsmcli list --type volumes):
EMC VNX with 95 volumes:
Old: 13.37s
New: 8.97s

* Replace Smis._pool_id() with smis_pool.pool_id_of_cim_pool()
* Replace Smis._property_list_of_id(self, 'Pool') with
smis_pool.cim_pool_id_pros()
* Replaced Smis._new_pool_cim_pool_pros(self) with
smis_pool.cim_pool_pros()
* Remove smis_constants.JOB_RETRIEVE_POOL
* Remove Smis._new_pool_from_name() and Smis._new_pool_from_job()
* Move DMTF.cim_pool_status_of() to
smis_pool._pool_status_of_cim_pool().
# This method is for smis_pool internal use only now.
* Move Smis._pool_element_type() to
smis_pool._pool_element_type()
# This method is for smis_pool internal use only now.
* Removed Smis._sys_id_of_cim_pool() as no method require it.
* Add MegaRAID workaround for smis_pool._pool_element_type()
to improve performance by returning (Pool.ELEMENT_TYPE_VOLUME, 0)
directly. Tested on a remote MegaRAID card with two pools:
Old: 10.10s # With all pending patches but this one.
New: 4.61s
* Move Smis._new_pool() to smis_pool.cim_pool_to_lsm_pool()
* Including three changes in patch as _pool_status_of_cim_pool() and
_pool_element_type() are internal methods for
smis_pool.cim_pool_to_lsm_pool() now.
* Using json to save the CIMInstanceName of CIM_StoragePool into
lsm.Pool.plugin_data and convert it back when needed:
* Save:
Pool.plugin_data = json.dumps({
'classname': cim_path.classname,
'keybindings': dict(cim_path.keybindings),
'host': cim_path.host,
'namespace': cim_path.namespace,
})

* Load:
CIMInstanceName(**json.loads(Pool.plugin_data))

* Replace Smis._get_cim_instance_by_id(self, 'Pool', pool.id) with
smis_pool.lsm_pool_to_cim_pool_path(smis_common, pool)
* Replace Smis._get_pool_from_vol() with smis_pool.pool_id_of_cim_vol()

Changes in V2:
* Fix the error message formatter.
* Use json instead of cPickle for security concern[2].

[1] Old codes will try to find volumes on spare pool or other unused pool
which is waster of time.
[2] __reduce__() will be called by cPickle.loads() which might be
use to excute any command remoted.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 3 +-
plugin/smispy/dmtf.py | 17 ---
plugin/smispy/smis.py | 259 ++++-------------------------------
plugin/smispy/smis_constants.py | 3 +-
plugin/smispy/smis_pool.py | 285 +++++++++++++++++++++++++++++++++++++++
6 files changed, 314 insertions(+), 254 deletions(-)
create mode 100644 plugin/smispy/smis_pool.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 6eb1d55..5656548 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -319,6 +319,7 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_common.*
%{python_sitelib}/lsm/plugin/smispy/smis_cap.*
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
+%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
%{_bindir}/smispy_lsmplugin

%files netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index df411f3..793fb0b 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -30,7 +30,8 @@ smispy_PYTHON = \
smispy/smis_common.py \
smispy/dmtf.py \
smispy/smis_cap.py \
- smispy/smis_sys.py
+ smispy/smis_sys.py \
+ smispy/smis_pool.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index d020a9a..c5ea3fe 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -96,23 +96,6 @@ class DMTF(object):
return status, " ".join(status_info_list)


- _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)
-
EMC_DISK_STATUS_REMOVED = 32768

_LSM_DISK_OP_STATUS_CONV = {
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index fc231dd..56b2912 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -31,6 +31,7 @@ from pywbem import CIMError
from smis_constants import *
import smis_cap
import smis_sys
+import smis_pool

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
JobStatus, md5, Volume, AccessGroup,
@@ -181,8 +182,6 @@ class Smis(IStorageAreaNetwork):
if rc == INVOKE_OK:
if retrieve_data == JOB_RETRIEVE_VOLUME:
return None, self._new_vol_from_name(out)
- elif retrieve_data == JOB_RETRIEVE_POOL:
- return None, self._new_pool_from_name(out)
else:
return None, None

@@ -342,8 +341,6 @@ class Smis(IStorageAreaNetwork):
(ignore, retrieve_data) = self._parse_job_id(job_id)
if retrieve_data == JOB_RETRIEVE_VOLUME:
completed_item = self._new_vol_from_job(cim_job)
- elif retrieve_data == JOB_RETRIEVE_POOL:
- completed_item = self._new_pool_from_job(cim_job)
else:
status = JobStatus.ERROR

@@ -395,8 +392,6 @@ class Smis(IStorageAreaNetwork):
rc = []
if class_type == 'Volume':
rc = ['SystemName', 'DeviceID']
- elif class_type == 'Pool':
- rc = ['InstanceID']
elif class_type == 'SystemChild':
rc = ['SystemName']
elif class_type == 'Disk':
@@ -421,12 +416,6 @@ class Smis(IStorageAreaNetwork):
"""
return self._id('SystemChild', cim_xxx)

- def _pool_id(self, cim_pool):
- """
- Return CIM_StoragePool['InstanceID']
- """
- return self._id('Pool', cim_pool)
-
def _vol_id(self, cim_vol):
"""
Return the MD5 hash of CIM_StorageVolume['SystemName'] and
@@ -500,19 +489,6 @@ class Smis(IStorageAreaNetwork):
retrieve_data = int(tmp_list[1])
return (md5_str, retrieve_data)

- def _get_pool_from_vol(self, cim_vol):
- """
- Takes a CIMInstance that represents a volume and returns the pool
- id for that volume.
- """
- property_list = Smis._property_list_of_id('Pool')
- cim_pool = self._c.Associators(
- cim_vol.path,
- AssocClass='CIM_AllocatedFromStoragePool',
- ResultClass='CIM_StoragePool',
- PropertyList=property_list)[0]
- return self._pool_id(cim_pool)
-
@staticmethod
def _get_vol_other_id_info(cv):
other_id = None
@@ -570,7 +546,7 @@ class Smis(IStorageAreaNetwork):
#to not call this very often.
if pool_id is None:
#Go an retrieve the pool id
- pool_id = self._get_pool_from_vol(cv)
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cv.path)

if sys_id is None:
sys_id = cv['SystemName']
@@ -694,23 +670,6 @@ class Smis(IStorageAreaNetwork):

return self._new_vol(instance)

- def _new_pool_from_name(self, out):
- """
- For SYNC CreateOrModifyElementFromStoragePool action.
- The new CIM_StoragePool is stored in out['Pool']
- """
- pool_pros = self._new_pool_cim_pool_pros()
-
- if 'Pool' in out:
- cim_new_pool = self._c.GetInstance(
- out['Pool'],
- PropertyList=pool_pros, LocalOnly=False)
- return self._new_pool(cim_new_pool)
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Got not new Pool from out of InvokeMethod" +
- "when CreateOrModifyElementFromStoragePool")
-
def _cim_spc_pros(self):
"""
Return a list of properties required to build new AccessGroup.
@@ -774,17 +733,6 @@ class Smis(IStorageAreaNetwork):
return self._new_vol(self._c.GetInstance(a.path, LocalOnly=False))
return None

- def _new_pool_from_job(self, cim_job):
- """
- Given a CIMInstance of CIM_ConcreteJob, return a LSM Pool
- """
- pool_pros = self._new_pool_cim_pool_pros()
- cim_pools = self._c.Associators(cim_job.path,
- AssocClass='CIM_AffectedJobElement',
- ResultClass='CIM_StoragePool',
- PropertyList=pool_pros)
- return self._new_pool(cim_pools[0])
-
@handle_cim_errors
def volumes(self, search_key=None, search_value=None, flags=0):
"""
@@ -812,9 +760,11 @@ class Smis(IStorageAreaNetwork):
cim_vol_pros = self._cim_vol_pros()
for cim_sys in cim_syss:
sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
- pool_pros = self._property_list_of_id('Pool')
- for cim_pool in self._cim_pools_of(cim_sys.path, pool_pros):
- pool_id = self._pool_id(cim_pool)
+ pool_pros = smis_pool.cim_pool_id_pros()
+ cim_pools = smis_pool.cim_pools_of_cim_sys_path(
+ self._c, cim_sys.path, pool_pros)
+ for cim_pool in cim_pools:
+ pool_id = smis_pool.pool_id_of_cim_pool(cim_pool)
cim_vols = self._c.Associators(
cim_pool.path,
AssocClass='CIM_AllocatedFromStoragePool',
@@ -831,132 +781,31 @@ class Smis(IStorageAreaNetwork):
rc.extend([vol])
return search_property(rc, search_key, search_value)

- def _cim_pools_of(self, cim_sys_path, property_list=None):
- if property_list is None:
- property_list = ['Primordial']
- else:
- property_list = merge_list(property_list, ['Primordial'])
-
- cim_pools = self._c.Associators(cim_sys_path,
- AssocClass='CIM_HostedStoragePool',
- ResultClass='CIM_StoragePool',
- PropertyList=property_list)
-
- return [p for p in cim_pools if not p["Primordial"]]
-
- def _new_pool_cim_pool_pros(self):
- """
- Return a list of properties for creating new pool.
- """
- pool_pros = self._property_list_of_id('Pool')
- pool_pros.extend(['ElementName', 'TotalManagedSpace',
- 'RemainingManagedSpace', 'Usage',
- 'OperationalStatus'])
- return pool_pros
-
@handle_cim_errors
def pools(self, search_key=None, search_value=None, flags=0):
"""
- We are basing on "Block Services Package" profile version 1.4 or
- later:
- CIM_ComputerSystem
- |
- | (CIM_HostedStoragePool)
- |
- v
- CIM_StoragePool
- As 'Block Services Package' is mandatory for 'Array' profile, we
- don't check support status here as startup() already checked 'Array'
- profile.
+ Convert CIM_StoragePool to lsm.Pool.
+ To list all CIM_StoragePool:
+ 1. List all root CIM_ComputerSystem.
+ 2. List all CIM_StoragePool associated to CIM_ComputerSystem.
"""
rc = []
- cim_pool_pros = self._new_pool_cim_pool_pros()
+ cim_pool_pros = smis_pool.cim_pool_pros()

cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)

for cim_sys in cim_syss:
system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
- for cim_pool in self._cim_pools_of(cim_sys.path, cim_pool_pros):
- # Skip spare storage pool.
- if 'Usage' in cim_pool and \
- cim_pool['Usage'] == DMTF_POOL_USAGE_SPARE:
- continue
- # Skip IBM ArrayPool and ArraySitePool
- # ArrayPool is holding RAID info.
- # ArraySitePool is holding 8 disks. Predefined by array.
- # ArraySite --(1to1 map) --> Array --(1to1 map)--> Rank
-
- # By design when user get a ELEMENT_TYPE_POOL only pool,
- # user can assume he/she can allocate spaces from that pool
- # to create a new pool with ELEMENT_TYPE_VOLUME or
- # ELEMENT_TYPE_FS ability.
-
- # If we expose them out, we will have two kind of pools
- # (ArrayPool and ArraySitePool) having element_type &
- # ELEMENT_TYPE_POOL, but none of them can create a
- # ELEMENT_TYPE_VOLUME pool.
- # Only RankPool can create a ELEMENT_TYPE_VOLUME pool.
-
- # We are trying to hide the detail to provide a simple
- # abstraction.
- if cim_pool.classname == 'IBMTSDS_ArrayPool' or \
- cim_pool.classname == 'IBMTSDS_ArraySitePool':
- continue
+ cim_pools = smis_pool.cim_pools_of_cim_sys_path(
+ self._c, cim_sys.path, cim_pool_pros)
+ for cim_pool in cim_pools:
+ rc.append(
+ smis_pool.cim_pool_to_lsm_pool(
+ self._c, cim_pool, system_id))

- pool = self._new_pool(cim_pool, system_id)
- if pool:
- rc.extend([pool])
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Failed to retrieve pool information " +
- "from CIM_StoragePool: %s" % cim_pool.path)
return search_property(rc, search_key, search_value)

- def _sys_id_of_cim_pool(self, cim_pool):
- """
- Find out the system ID for certain CIM_StoragePool.
- Will return '' if failed.
- """
- sys_pros = smis_sys.cim_sys_id_pros()
- cim_syss = self._c.Associators(cim_pool.path,
- ResultClass='CIM_ComputerSystem',
- PropertyList=sys_pros)
- if len(cim_syss) == 1:
- return smis_sys.sys_id_of_cim_sys(cim_syss[0])
- return ''
-
- @handle_cim_errors
- def _new_pool(self, cim_pool, system_id=''):
- """
- Return a Pool object base on information of cim_pool.
- Assuming cim_pool already holding correct properties.
- """
- if not system_id:
- system_id = self._sys_id_of_cim_pool(cim_pool)
-
- status_info = ''
- pool_id = self._pool_id(cim_pool)
- name = ''
- total_space = Pool.TOTAL_SPACE_NOT_FOUND
- free_space = Pool.FREE_SPACE_NOT_FOUND
- status = Pool.STATUS_OK
- if 'ElementName' in cim_pool:
- name = cim_pool['ElementName']
- if 'TotalManagedSpace' in cim_pool:
- total_space = cim_pool['TotalManagedSpace']
- if 'RemainingManagedSpace' in cim_pool:
- free_space = cim_pool['RemainingManagedSpace']
- if 'OperationalStatus' in cim_pool:
- (status, status_info) = DMTF.cim_pool_status_of(
- cim_pool['OperationalStatus'])
-
- element_type, unsupported = self._pool_element_type(cim_pool)
-
- return Pool(pool_id, name, element_type, unsupported,
- total_space, free_space,
- status, status_info, system_id)
-
@handle_cim_errors
def systems(self, flags=0):
"""
@@ -1016,11 +865,12 @@ class Smis(IStorageAreaNetwork):
# Get the Configuration service for the system we are interested in.
scs = self._c.get_class_instance('CIM_StorageConfigurationService',
'SystemName', pool.system_id)
- sp = self._get_cim_instance_by_id('Pool', pool.id)
+ cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
+ self._c, pool)

in_params = {'ElementName': volume_name,
'ElementType': pywbem.Uint16(2),
- 'InPool': sp.path,
+ 'InPool': cim_pool_path,
'Size': pywbem.Uint64(size_bytes)}

try:
@@ -1293,11 +1143,9 @@ class Smis(IStorageAreaNetwork):
rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
volume_src.system_id,
raise_error=False)
-
+ cim_pool_path = None
if pool is not None:
- cim_pool = self._get_cim_instance_by_id('Pool', pool.id)
- else:
- cim_pool = None
+ cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)

lun = self._get_cim_instance_by_id('Volume', volume_src.id)

@@ -1339,8 +1187,8 @@ class Smis(IStorageAreaNetwork):
'SourceElement': lun.path}
if rs:

- if cim_pool is not None:
- in_params['TargetPool'] = cim_pool.path
+ if cim_pool_path is not None:
+ in_params['TargetPool'] = cim_pool_path

try:

@@ -2455,63 +2303,6 @@ class Smis(IStorageAreaNetwork):
"requested CIM_StorageExtent %s" %
cim_pri_ext_path)

- def _pool_element_type(self, cim_pool):
-
- element_type = 0
- unsupported = 0
-
- # check whether current pool support create volume or not.
- cim_sccs = self._c.Associators(
- cim_pool.path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities',
- PropertyList=['SupportedStorageElementFeatures',
- 'SupportedStorageElementTypes'])
- # Associate StorageConfigurationCapabilities to StoragePool
- # is experimental in SNIA 1.6rev4, Block Book PDF Page 68.
- # Section 5.1.6 StoragePool, StorageVolume and LogicalDisk
- # Manipulation, Figure 9 - Capabilities Specific to a StoragePool
- if len(cim_sccs) == 1:
- cim_scc = cim_sccs[0]
- if 'SupportedStorageElementFeatures' in cim_scc:
- supported_features = cim_scc['SupportedStorageElementFeatures']
-
- if DMTF_SUPPORT_VOL_CREATE in supported_features:
- element_type |= Pool.ELEMENT_TYPE_VOLUME
- if DMTF_SUPPORT_ELEMENT_EXPAND not in supported_features:
- unsupported |= Pool.UNSUPPORTED_VOLUME_GROW
- if DMTF_SUPPORT_ELEMENT_REDUCE not in supported_features:
- unsupported |= Pool.UNSUPPORTED_VOLUME_SHRINK
-
- else:
- # IBM DS 8000 does not support StorageConfigurationCapabilities
- # per pool yet. They has been informed. Before fix, use a quick
- # workaround.
- # TODO: Currently, we don't have a way to detect
- # Pool.ELEMENT_TYPE_POOL
- # but based on knowing definition of each vendor.
- if cim_pool.classname == 'IBMTSDS_VirtualPool' or \
- cim_pool.classname == 'IBMTSDS_ExtentPool':
- element_type = Pool.ELEMENT_TYPE_VOLUME
- elif cim_pool.classname == 'IBMTSDS_RankPool':
- element_type = Pool.ELEMENT_TYPE_POOL
- elif cim_pool.classname == 'LSIESG_StoragePool':
- element_type = Pool.ELEMENT_TYPE_VOLUME
-
- if 'Usage' in cim_pool:
- usage = cim_pool['Usage']
-
- if usage == DMTF_POOL_USAGE_UNRESTRICTED:
- element_type |= Pool.ELEMENT_TYPE_VOLUME
- if usage == DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM or \
- usage > DMTF_POOL_USAGE_DELTA:
- element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
- if usage == DMTF_POOL_USAGE_DELTA:
- # We blitz all the other elements types for this designation
- element_type = Pool.ELEMENT_TYPE_DELTA
-
- return element_type, unsupported
-
@staticmethod
def _is_frontend_fc_tgt(cim_fc_tgt):
"""
diff --git a/plugin/smispy/smis_constants.py b/plugin/smispy/smis_constants.py
index 0536cf5..2df9144 100644
--- a/plugin/smispy/smis_constants.py
+++ b/plugin/smispy/smis_constants.py
@@ -61,7 +61,6 @@ VOL_NAME_SPACE_SNVM = 7

JOB_RETRIEVE_NONE = 0
JOB_RETRIEVE_VOLUME = 1
-JOB_RETRIEVE_POOL = 2

IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989
@@ -129,4 +128,4 @@ class Synchronized(object):
VOL_OP_STATUS_DORMANT) = (2, 3, 6, 8, 15)

# SMI-S ExposePaths device access enumerations
-(EXPOSE_PATHS_DA_READ_WRITE, EXPOSE_PATHS_DA_READ_ONLY) = (2, 3)
\ No newline at end of file
+(EXPOSE_PATHS_DA_READ_WRITE, EXPOSE_PATHS_DA_READ_ONLY) = (2, 3)
diff --git a/plugin/smispy/smis_pool.py b/plugin/smispy/smis_pool.py
new file mode 100644
index 0000000..e97b631
--- /dev/null
+++ b/plugin/smispy/smis_pool.py
@@ -0,0 +1,285 @@
+## 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
+# 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>
+
+from utils import merge_list
+from dmtf import *
+from lsm import LsmError, ErrorNumber, Pool
+import json
+from pywbem import CIMInstanceName
+
+
+def cim_pools_of_cim_sys_path(smis_common, cim_sys_path, property_list=None):
+ """
+ Use this association to get a list of CIM_StoragePool:
+ CIM_ComputerSystem
+ |
+ | (CIM_HostedStoragePool)
+ |
+ v
+ CIM_StoragePool
+ As 'Block Services Package' is mandatory for 'Array' profile which already
+ checked by plugin_register(), we don't do any profile check here.
+ Primordial pool will be eliminated from return list.
+ These pools will be eliminated also:
+ * Spare pool with CIM_StoragePool['Usage'] == DMTF_POOL_USAGE_SPARE
+ * IBM ArrayPool(IBMTSDS_ArrayPool)
+ * IBM ArraySitePool(IBMTSDS_ArraySitePool)
+ """
+ cim_pools = []
+
+ if property_list is None:
+ property_list = ['Primordial', 'Usage']
+ else:
+ property_list = merge_list(property_list, ['Primordial', 'Usage'])
+
+ cim_pools = smis_common.Associators(
+ cim_sys_path,
+ AssocClass='CIM_HostedStoragePool',
+ ResultClass='CIM_StoragePool',
+ PropertyList=property_list)
+
+ rc = []
+ for cim_pool in cim_pools:
+ if 'Primordial' in cim_pool and cim_pool['Primordial']:
+ continue
+ if 'Usage' in cim_pool and cim_pool['Usage'] == DMTF_POOL_USAGE_SPARE:
+ continue
+ # Skip IBM ArrayPool and ArraySitePool
+ # ArrayPool is holding RAID info.
+ # ArraySitePool is holding 8 disks. Predefined by array.
+ # ArraySite --(1to1 map) --> Array --(1to1 map)--> Rank
+
+ # By design when user get a ELEMENT_TYPE_POOL only pool,
+ # user can assume he/she can allocate spaces from that pool
+ # to create a new pool with ELEMENT_TYPE_VOLUME or
+ # ELEMENT_TYPE_FS ability.
+
+ # If we expose them out, we will have two kind of pools
+ # (ArrayPool and ArraySitePool) having element_type &
+ # ELEMENT_TYPE_POOL, but none of them can create a
+ # ELEMENT_TYPE_VOLUME pool.
+ # Only RankPool can create a ELEMENT_TYPE_VOLUME pool.
+
+ # We are trying to hide the detail to provide a simple
+ # abstraction.
+ if cim_pool.classname == 'IBMTSDS_ArrayPool' or \
+ cim_pool.classname == 'IBMTSDS_ArraySitePool':
+ continue
+ rc.append(cim_pool)
+
+ return rc
+
+
+def cim_pool_id_pros():
+ """
+ Return a list of CIM_StoragePool properties required to generate
+ lsm.Pool.id
+ """
+ return ['InstanceID']
+
+
+def pool_id_of_cim_pool(cim_pool):
+ if 'InstanceID' in cim_pool:
+ return cim_pool['InstanceID']
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "pool_id_of_cim_pool(): Got CIM_StoragePool with no 'InstanceID' "
+ "property: %s, %s" % (cim_pool.items(), cim_pool.path))
+
+
+def cim_pool_pros():
+ """
+ Return a list of CIM_StoragePool properties required to generate lsm.Pool.
+ """
+ pool_pros = cim_pool_id_pros()
+ pool_pros.extend(['ElementName', 'TotalManagedSpace',
+ 'RemainingManagedSpace', 'Usage',
+ 'OperationalStatus'])
+ return pool_pros
+
+
+def _pool_element_type(smis_common, cim_pool):
+ """
+ Return a set (Pool.element_type, Pool.unsupported)
+ Using CIM_StorageConfigurationCapabilities
+ 'SupportedStorageElementFeatures' and 'SupportedStorageElementTypes'
+ property.
+ For MegaRAID, just return (Pool.ELEMENT_TYPE_VOLUME, 0)
+ """
+ if smis_common.is_megaraid():
+ return Pool.ELEMENT_TYPE_VOLUME, 0
+
+ element_type = 0
+ unsupported = 0
+
+ # check whether current pool support create volume or not.
+ cim_sccs = smis_common.Associators(
+ cim_pool.path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedStorageElementFeatures',
+ 'SupportedStorageElementTypes'])
+ # Associate StorageConfigurationCapabilities to StoragePool
+ # is experimental in SNIA 1.6rev4, Block Book PDF Page 68.
+ # Section 5.1.6 StoragePool, StorageVolume and LogicalDisk
+ # Manipulation, Figure 9 - Capabilities Specific to a StoragePool
+ if len(cim_sccs) == 1:
+ cim_scc = cim_sccs[0]
+ if 'SupportedStorageElementFeatures' in cim_scc:
+ supported_features = cim_scc['SupportedStorageElementFeatures']
+
+ if DMTF_SUPPORT_VOL_CREATE in supported_features:
+ element_type |= Pool.ELEMENT_TYPE_VOLUME
+ if DMTF_SUPPORT_ELEMENT_EXPAND not in supported_features:
+ unsupported |= Pool.UNSUPPORTED_VOLUME_GROW
+ if DMTF_SUPPORT_ELEMENT_REDUCE not in supported_features:
+ unsupported |= Pool.UNSUPPORTED_VOLUME_SHRINK
+
+ else:
+ # IBM DS 8000 does not support StorageConfigurationCapabilities
+ # per pool yet. They has been informed. Before fix, use a quick
+ # workaround.
+ # TODO: Currently, we don't have a way to detect
+ # Pool.ELEMENT_TYPE_POOL
+ # but based on knowing definition of each vendor.
+ if cim_pool.classname == 'IBMTSDS_VirtualPool' or \
+ cim_pool.classname == 'IBMTSDS_ExtentPool':
+ element_type = Pool.ELEMENT_TYPE_VOLUME
+ elif cim_pool.classname == 'IBMTSDS_RankPool':
+ element_type = Pool.ELEMENT_TYPE_POOL
+ elif cim_pool.classname == 'LSIESG_StoragePool':
+ element_type = Pool.ELEMENT_TYPE_VOLUME
+
+ if 'Usage' in cim_pool:
+ usage = cim_pool['Usage']
+
+ if usage == DMTF_POOL_USAGE_UNRESTRICTED:
+ element_type |= Pool.ELEMENT_TYPE_VOLUME
+ if usage == DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM or \
+ usage > DMTF_POOL_USAGE_DELTA:
+ element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
+ if usage == DMTF_POOL_USAGE_DELTA:
+ # We blitz all the other elements types for this designation
+ element_type = Pool.ELEMENT_TYPE_DELTA
+
+ return element_type, unsupported
+
+
+_LSM_POOL_OP_STATUS_CONV = {
+ DMTF.OP_STATUS_OK: Pool.STATUS_OK,
+ DMTF.OP_STATUS_ERROR: Pool.STATUS_ERROR,
+ DMTF.OP_STATUS_DEGRADED: Pool.STATUS_DEGRADED,
+ DMTF.OP_STATUS_NON_RECOVERABLE_ERROR: Pool.STATUS_ERROR,
+ DMTF.OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: Pool.STATUS_ERROR,
+}
+
+
+def _pool_status_of_cim_pool(dmtf_op_status_list):
+ """
+ Convert CIM_StoragePool['OperationalStatus'] to LSM
+ """
+ return DMTF.dmtf_op_status_list_conv(
+ _LSM_POOL_OP_STATUS_CONV, dmtf_op_status_list,
+ Pool.STATUS_UNKNOWN, Pool.STATUS_OTHER)
+
+
+def cim_pool_to_lsm_pool(smis_common, cim_pool, system_id):
+ """
+ Return a Pool object base on information of cim_pool.
+ Assuming cim_pool already holding correct properties.
+ """
+ status_info = ''
+ pool_id = pool_id_of_cim_pool(cim_pool)
+ name = ''
+ total_space = Pool.TOTAL_SPACE_NOT_FOUND
+ free_space = Pool.FREE_SPACE_NOT_FOUND
+ status = Pool.STATUS_OK
+ if 'ElementName' in cim_pool:
+ name = cim_pool['ElementName']
+ if 'TotalManagedSpace' in cim_pool:
+ total_space = cim_pool['TotalManagedSpace']
+ if 'RemainingManagedSpace' in cim_pool:
+ free_space = cim_pool['RemainingManagedSpace']
+ if 'OperationalStatus' in cim_pool:
+ (status, status_info) = _pool_status_of_cim_pool(
+ cim_pool['OperationalStatus'])
+
+ element_type, unsupported = _pool_element_type(smis_common, cim_pool)
+
+ plugin_data = _cim_path_to_path_str(cim_pool.path)
+
+ return Pool(pool_id, name, element_type, unsupported,
+ total_space, free_space,
+ status, status_info, system_id, plugin_data)
+
+
+def lsm_pool_to_cim_pool_path(smis_common, lsm_pool):
+ """
+ Convert lsm.Pool to CIMInstanceName of CIM_StoragePool using
+ lsm.Pool.plugin_data
+ """
+ if not lsm_pool.plugin_data:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.Pool instance with empty plugin_data")
+ if smis_common.system_list and \
+ lsm_pool.system_id not in smis_common.system_list:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return _path_str_to_cim_path(lsm_pool.plugin_data)
+
+
+def _cim_path_to_path_str(cim_path):
+ """
+ Convert CIMInstanceName to a string which could save in plugin_data
+ """
+ return json.dumps({
+ 'classname': cim_path.classname,
+ 'keybindings': dict(cim_path.keybindings),
+ 'host': cim_path.host,
+ 'namespace': cim_path.namespace,
+ })
+
+
+def _path_str_to_cim_path(path_str):
+ """
+ Convert a string into CIMInstanceName.
+ """
+ path_dict = json.loads(path_str)
+ return CIMInstanceName(**path_dict)
+
+
+def pool_id_of_cim_vol(smis_common, cim_vol_path):
+ """
+ Find out the lsm.Pool.id of CIM_StorageVolume
+ """
+ property_list = cim_pool_id_pros()
+ cim_pools = smis_common.Associators(
+ cim_vol_path,
+ AssocClass='CIM_AllocatedFromStoragePool',
+ ResultClass='CIM_StoragePool',
+ PropertyList=property_list)
+ if len(cim_pools) != 1:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "pool_id_of_cim_vol(): Got unexpected count(%d) of cim_pool " %
+ len(cim_pools) +
+ "assocated to cim_vol: %s, %s" % (cim_vol_path, cim_pools))
+ return pool_id_of_cim_pool(cim_pools[0])
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:25 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Remove fallback mode as no array really need them.
All SMI-S provider I have access support DMTF profile register and support
SMI-S 1.4 'Array' profile[1].
* New method: SmisCommon.is_netappe() for NetApp-E vendor code check.
* Simply move eseries.py codes into smis.py using SmisCommon.is_netappe()
check.
* Remove eseries.py file.
* Makefile and RPM spec file updated.
* SmisProxy is not needed any more after eseries.py got removed.
* Vendor specific code will be stored in smis.py or future sub
module/namespace of smis.py.
* Makefile and RPM spec file updated.

Changes in V2:

* Fixed a NetApp-E bug:
Old:
self._vendor_namespace = SmisCommon._PRODUCT_NETAPP_E

def is_netappe(self):
return self._vendor_product == SmisCommon._PRODUCT_MEGARAID

New:
self._vendor_product = SmisCommon._PRODUCT_NETAPP_E

def is_netappe(self):
return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E

[1] LSI/Avago MegaRAID is using 1.2 and using vendor specific code in this
plugin.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 2 -
plugin/Makefile.am | 2 -
plugin/smispy/eseries.py | 164 --------------------------
plugin/smispy/smis.py | 246 +++++++++++++++++++--------------------
plugin/smispy/smis_common.py | 8 ++
plugin/smispy/smisproxy.py | 51 --------
plugin/smispy/smispy_lsmplugin | 4 +-
7 files changed, 130 insertions(+), 347 deletions(-)
delete mode 100644 plugin/smispy/eseries.py
delete mode 100644 plugin/smispy/smisproxy.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 798d2f4..c9414df 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -312,9 +312,7 @@ fi
%files smis-plugin
%defattr(-,root,root,-)
%{python_sitelib}/lsm/plugin/smispy/__init__.*
-%{python_sitelib}/lsm/plugin/smispy/eseries.*
%{python_sitelib}/lsm/plugin/smispy/smis.*
-%{python_sitelib}/lsm/plugin/smispy/smisproxy.*
%{python_sitelib}/lsm/plugin/smispy/dmtf.*
%{python_sitelib}/lsm/plugin/smispy/utils.*
%{python_sitelib}/lsm/plugin/smispy/smis_common.*
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index a4605ab..424ad93 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -25,8 +25,6 @@ smispydir = $(plugindir)/smispy
smispy_PYTHON = \
smispy/__init__.py \
smispy/smis.py \
- smispy/smisproxy.py \
- smispy/eseries.py \
smispy/utils.py \
smispy/smis_common.py \
smispy/dmtf.py
diff --git a/plugin/smispy/eseries.py b/plugin/smispy/eseries.py
deleted file mode 100644
index c493a47..0000000
--- a/plugin/smispy/eseries.py
+++ /dev/null
@@ -1,164 +0,0 @@
-# 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: tasleson
-
-from smis import Smis
-from string import split
-import pywbem
-import time
-from lsm.plugin.smispy.smis import handle_cim_errors
-from lsm import LsmError, ErrorNumber, uri_parse
-
-
-class ESeries(Smis):
- def plugin_register(self, uri, password, timeout, flags=0):
- """
- The only difference we did here compare to supper method:
- we force to be fallback mode.
- NetApp-E support 'Masking and Mapping' profile but not expose it
- via CIM_RegisteredProfile.
- """
- protocol = 'http'
- port = Smis.IAAN_WBEM_HTTP_PORT
- u = uri_parse(uri, ['scheme', 'netloc', 'host'], None)
-
- if u['scheme'].lower() == 'smispy+ssl':
- protocol = 'https'
- port = Smis.IAAN_WBEM_HTTPS_PORT
-
- if 'port' in u:
- port = u['port']
-
- # smisproxy.py already make sure namespace defined.
- namespace = u['parameters']['namespace']
- self.all_vendor_namespaces = [namespace]
-
- url = "%s://%s:%s" % (protocol, u['host'], port)
- self.system_list = None
- if 'systems' in u['parameters']:
- self.system_list = split(u['parameters']["systems"], ":")
-
- self._c = pywbem.WBEMConnection(url, (u['username'], password),
- namespace)
- if "no_ssl_verify" in u["parameters"] \
- and u["parameters"]["no_ssl_verify"] == 'yes':
- try:
- self._c = pywbem.WBEMConnection(
- url,
- (u['username'], password),
- namespace,
- no_verification=True)
- except TypeError:
- # pywbem is not holding fix from
- # https://bugzilla.redhat.com/show_bug.cgi?id=1039801
- pass
-
- self.tmo = timeout
- self.fallback_mode = True
-
- def _deal_volume_associations(self, vol, lun):
- """
- Check a volume to see if it has any associations with other
- volumes.
- """
- rc = False
- lun_path = lun.path
-
- ss = self._c.References(lun_path,
- ResultClass='CIM_StorageSynchronized')
-
- if len(ss):
- for s in ss:
- if 'SyncedElement' in s:
- item = s['SyncedElement']
-
- if Smis._cim_name_match(item, lun_path):
- self._detach(vol, s)
- rc = True
-
- if 'SystemElement' in s:
- item = s['SystemElement']
-
- if Smis._cim_name_match(item, lun_path):
- self._detach(vol, s)
- rc = True
-
- return rc
-
- def _is_access_group(self, s):
- return True
-
- @handle_cim_errors
- def capabilities(self, system, flags=0):
- cap = self._common_capabilities(system)
-
- #TODO We need to investigate why our interrogation code doesn't work.
- #The array is telling us one thing, but when we try to use it, it
- #doesn't work
- return cap
-
- def _detach(self, vol, sync):
-
- #Get the Configuration service for the system we are interested in.
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', vol.system_id)
-
- in_params = {'Operation': pywbem.Uint16(2),
- 'Synchronization': sync.path}
-
- job_id = self._pi("_detach", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod(
- 'ModifySynchronization', scs.path,
- **in_params)))[0]
-
- self._poll("ModifySynchronization, detach", job_id)
-
- @handle_cim_errors
- def volume_delete(self, volume, flags=0):
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
-
- #If we actually have an association to delete, the volume will be
- #deleted with the association, no need to call ReturnToStoragePool
- if not self._deal_volume_associations(volume, lun):
- in_params = {'TheElement': lun.path}
-
- #Delete returns None or Job number
- return self._pi("volume_delete", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('ReturnToStoragePool',
- scs.path, **in_params)))[0]
-
- #Loop to check to see if volume is actually gone yet!
- try:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
- while lun is not None:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
- time.sleep(0.125)
- except LsmError as e:
- pass
-
- @handle_cim_errors
- def access_group_initiator_delete(self, access_group, init_id, init_type,
- flags=0):
- """
- When using HidePaths to remove initiator, the whole SPC will be
- removed. Before we find a workaround for this, I would like to have
- this method disabled as NO_SUPPORT.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "SMI-S plugin does not support "
- "access_group_initiator_delete() against NetApp-E")
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 3238b86..7ba694b 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -384,7 +384,6 @@ class Smis(IStorageAreaNetwork):
self._c = None
self.tmo = 0
self.system_list = None
- self.fallback_mode = True # Means we cannot use profile register
self.debug_path = None

def _get_cim_instance_by_id(self, class_type, requested_id,
@@ -566,20 +565,6 @@ class Smis(IStorageAreaNetwork):
volume_resize()
volume_delete()
"""
- if self.fallback_mode:
- # pools() is mandatory, we will try pools() related methods first
- try:
- self._cim_pools_of(cim_sys_path)
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Target SMI-S provider does not support "
- "CIM_StoragePool querying which is "
- "mandatory for pools() method")
- else:
- raise
-
# CIM_StorageConfigurationService is optional.
cim_scs_path = self._get_cim_service_path(
cim_sys_path, 'CIM_StorageConfigurationService')
@@ -631,22 +616,10 @@ class Smis(IStorageAreaNetwork):
return

def _disk_cap_set(self, cim_sys_path, cap):
- if self.fallback_mode:
- try:
- # Assuming provider support disk drive when systems under it
- # support it.
- self._c.EnumerateInstanceNames('CIM_DiskDrive')
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- return
- else:
- raise
- else:
- if not self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return
+ if not self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return

cap.set(Capabilities.DISKS)
return
@@ -723,21 +696,10 @@ class Smis(IStorageAreaNetwork):
In SNIA SMI-S 1.4rev6 'Masking and Mapping' profile:
CIM_ControllerConfigurationService is mandatory
and it's ExposePaths() and HidePaths() are mandatory
-
- For fallback mode, once we found CIM_ControllerConfigurationService,
- we assume they are supporting 1.4rev6 'Masking and Mapping' profile.
- Fallback mode means target provider does not support interop, but
- they still need to follow at least SNIA SMI-S 1.4rev6
"""
- if self.fallback_mode:
- cim_ccs_path = self._get_cim_service_path(
- cim_sys_path, 'CIM_ControllerConfigurationService')
- if cim_ccs_path is None:
- return
-
- elif not self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
+ if not self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
return

cap.set(Capabilities.ACCESS_GROUPS)
@@ -771,43 +733,23 @@ class Smis(IStorageAreaNetwork):
if cim_sys_path.classname == 'LSIESG_MegaRAIDHBA':
return

- flag_fc_support = False
- flag_iscsi_support = False
- if self.fallback_mode:
- flag_fc_support = True
- flag_iscsi_support = True
- # CIM_FCPort is the control class of FC Targets profile
- try:
- self._cim_fc_tgt_of(cim_sys_path)
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- flag_fc_support = False
-
- try:
- self._cim_iscsi_pg_of(cim_sys_path)
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- flag_iscsi_support = False
- else:
+ flag_fc_support = self._c.profile_check(
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ # One more check for NetApp Typo:
+ # NetApp: 'FC Target Port'
+ # SMI-S: 'FC Target Ports'
+ # Bug reported.
+ if not flag_fc_support:
flag_fc_support = self._c.profile_check(
- SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- # One more check for NetApp Typo:
- # NetApp: 'FC Target Port'
- # SMI-S: 'FC Target Ports'
- # Bug reported.
- if not flag_fc_support:
- flag_fc_support = self._c.profile_check(
- 'FC Target Port',
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- flag_iscsi_support = self._c.profile_check(
- SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ 'FC Target Port',
SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False)
+ flag_iscsi_support = self._c.profile_check(
+ SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)

if flag_fc_support or flag_iscsi_support:
cap.set(Capabilities.TARGET_PORTS)
@@ -877,6 +819,14 @@ class Smis(IStorageAreaNetwork):

@handle_cim_errors
def capabilities(self, system, flags=0):
+ if self._c.is_netappe():
+ cap = self._common_capabilities(system)
+
+ #TODO We need to investigate why our interrogation code doesn't
+ #work.
+ #The array is telling us one thing, but when we try to use it, it
+ #doesn't work
+ return cap

cim_sys = self._get_cim_instance_by_id(
'System', system.id, raise_error=True)
@@ -1698,7 +1648,25 @@ class Smis(IStorageAreaNetwork):
ErrorNumber.PLUGIN_BUG,
msg + ", job error code= " + str(s))

+ def _detach_netapp_e(self, vol, sync):
+ #Get the Configuration service for the system we are interested in.
+ scs = self._get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', vol.system_id)
+
+ in_params = {'Operation': pywbem.Uint16(2),
+ 'Synchronization': sync.path}
+
+ job_id = self._pi("_detach", Smis.JOB_RETRIEVE_NONE,
+ *(self._c.InvokeMethod(
+ 'ModifySynchronization', scs.path,
+ **in_params)))[0]
+
+ self._poll("ModifySynchronization, detach", job_id)
+
def _detach(self, vol, sync):
+ if self._c.is_netappe():
+ return self._detach_netapp_e(vol, sync)
+
rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
vol.system_id, raise_error=False)

@@ -1723,11 +1691,43 @@ class Smis(IStorageAreaNetwork):
else:
return False

+ def _deal_volume_associations_netappe(self, vol, lun):
+ """
+ Check a volume to see if it has any associations with other
+ volumes.
+ """
+ rc = False
+ lun_path = lun.path
+
+ ss = self._c.References(lun_path,
+ ResultClass='CIM_StorageSynchronized')
+
+ if len(ss):
+ for s in ss:
+ if 'SyncedElement' in s:
+ item = s['SyncedElement']
+
+ if Smis._cim_name_match(item, lun_path):
+ self._detach(vol, s)
+ rc = True
+
+ if 'SystemElement' in s:
+ item = s['SystemElement']
+
+ if Smis._cim_name_match(item, lun_path):
+ self._detach(vol, s)
+ rc = True
+
+ return rc
+
def _deal_volume_associations(self, vol, lun):
"""
Check a volume to see if it has any associations with other
volumes and deal with them.
"""
+ if self._c.is_netappe():
+ return self._deal_volume_associations_netappe(vol, lun)
+
lun_path = lun.path

try:
@@ -1771,6 +1771,30 @@ class Smis(IStorageAreaNetwork):
if Smis._cim_name_match(item, lun_path):
self._detach(vol, s)

+ def _volume_delete_netapp_e(self, volume, flags=0):
+ scs = self._get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', volume.system_id)
+ lun = self._get_cim_instance_by_id('Volume', volume.id)
+
+ #If we actually have an association to delete, the volume will be
+ #deleted with the association, no need to call ReturnToStoragePool
+ if not self._deal_volume_associations(volume, lun):
+ in_params = {'TheElement': lun.path}
+
+ #Delete returns None or Job number
+ return self._pi("volume_delete", Smis.JOB_RETRIEVE_NONE,
+ *(self._c.InvokeMethod('ReturnToStoragePool',
+ scs.path, **in_params)))[0]
+
+ #Loop to check to see if volume is actually gone yet!
+ try:
+ lun = self._get_cim_instance_by_id('Volume', volume.id)
+ while lun is not None:
+ lun = self._get_cim_instance_by_id('Volume', volume.id)
+ time.sleep(0.125)
+ except LsmError as e:
+ pass
+
@handle_cim_errors
def volume_delete(self, volume, flags=0):
"""
@@ -2318,6 +2342,9 @@ class Smis(IStorageAreaNetwork):
return None

def _is_access_group(self, cim_spc):
+ if self._c.is_netappe:
+ return True
+
rc = True
_SMIS_EMC_ADAPTER_ROLE_MASKING = 'MASK_VIEW'

@@ -2441,10 +2468,9 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = []

- if (not self.fallback_mode and
- self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_6,
- raise_error=False)):
+ if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_6,
+ raise_error=False):
return self._c.Associators(
cim_spc_path,
AssocClass='CIM_AssociatedPrivilege',
@@ -2616,15 +2642,12 @@ class Smis(IStorageAreaNetwork):
def _mask_type(self, raise_error=False):
"""
Return Smis.MASK_TYPE_NO_SUPPORT, MASK_TYPE_MASK or MASK_TYPE_GROUP
- For fallback_mode, return MASK_TYPE_MASK
if 'Group Masking and Mapping' profile is supported, return
MASK_TYPE_GROUP

If raise_error == False, just return Smis.MASK_TYPE_NO_SUPPORT
or, raise NO_SUPPORT error.
"""
- if self.fallback_mode:
- return Smis.MASK_TYPE_MASK
if self._c.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
SmisCommon.SMIS_SPEC_VER_1_5,
raise_error=False):
@@ -2867,6 +2890,13 @@ class Smis(IStorageAreaNetwork):
@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, init_type,
flags=0):
+ if self._c.is_netappe():
+ # When using HidePaths to remove initiator, the whole SPC will be
+ # removed. Before we find a workaround for this, I would like to
+ # have this method disabled as NO_SUPPORT.
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S plugin does not support "
+ "access_group_initiator_delete() against NetApp-E")
init_id = _lsm_init_id_to_snia(init_id)
mask_type = self._mask_type(raise_error=True)

@@ -2922,10 +2952,9 @@ class Smis(IStorageAreaNetwork):
by ourselves in case URI contain 'system=xxx'.
"""
rc = []
- if not self.fallback_mode:
- self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=True)
+ self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=True)
cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
cim_disks = self._c.EnumerateInstances(
'CIM_DiskDrive', PropertyList=cim_disk_pros)
@@ -3192,17 +3221,7 @@ class Smis(IStorageAreaNetwork):
def _fc_tgt_is_supported(self, cim_sys_path):
"""
Return True if FC Target Port 1.4+ profile is supported.
- For fallback_mode, we call self._cim_fc_tgt_of() and do try-except
"""
- if self.fallback_mode:
- try:
- self._cim_fc_tgt_of(cim_sys_path)
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- return False
- return True
-
flag_fc_support = self._c.profile_check(
SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
SmisCommon.SMIS_SPEC_VER_1_4,
@@ -3224,22 +3243,9 @@ class Smis(IStorageAreaNetwork):
def _iscsi_tgt_is_supported(self, cim_sys_path):
"""
Return True if FC Target Port 1.4+ profile is supported.
- For fallback_mode, we call self._cim_iscsi_pg_of() and do try-except
- For fallback_mode:
- Even CIM_EthernetPort is the control class of iSCSI Target
- Ports profile, but that class is optional. :(
We use CIM_iSCSIProtocolEndpoint as it's a start point we are
using in our code of target_ports().
"""
- if self.fallback_mode:
- try:
- self._cim_iscsi_pg_of(cim_sys_path)
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- return False
- return True
-
if self._c.profile_check(SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False):
@@ -3249,11 +3255,8 @@ class Smis(IStorageAreaNetwork):
def _multi_sys_is_supported(self):
"""
Return True if Multiple ComputerSystem 1.4+ profile is supported.
- For fallback_mode, always return True.
Return False else.
"""
- if self.fallback_mode:
- return True
flag_multi_sys_support = self._c.profile_check(
SmisCommon.SNIA_MULTI_SYS_PROFILE,
SmisCommon.SMIS_SPEC_VER_1_4,
@@ -3566,7 +3569,7 @@ class Smis(IStorageAreaNetwork):
"these profiles: '%s %s', '%s %s'"
% (SmisCommon.SMIS_SPEC_VER_1_4,
SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SMIS_SPEC_VER_1_4,
SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE))

if flag_fc_support:
@@ -3764,10 +3767,6 @@ class Smis(IStorageAreaNetwork):
"""
org_init_id = init_id
init_id = _lsm_init_id_to_snia(init_id)
- if self.fallback_mode:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "access_group_create() is not supported in "
- "fallback mode")

self._c.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
SmisCommon.SMIS_SPEC_VER_1_5,
@@ -3868,11 +3867,6 @@ class Smis(IStorageAreaNetwork):
return self._cim_init_mg_to_lsm(cim_init_mg, system.id)

def access_group_delete(self, access_group, flags=0):
- if self.fallback_mode:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "access_group_create() is not supported in "
- "fallback mode")
-
self._c.profile_check(
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
raise_error=True)
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 27aa227..cf01b8f 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -153,7 +153,9 @@ class SmisCommon(object):
SMIS_SPEC_VER_1_6 = '1.6'
SNIA_REG_ORG_CODE = Uint16(11)
_MEGARAID_NAMESPACE = 'root/LsiMr13'
+ _NETAPP_E_NAMESPACE = 'root/LsiArray13'
_PRODUCT_MEGARAID = 'LSI MegaRAID'
+ _PRODUCT_NETAPP_E = 'NetApp-E'

def __init__(self, url, username, password,
namespace=DMTF.DEFAULT_NAMESPACE,
@@ -197,6 +199,9 @@ class SmisCommon(object):
(self._profile_dict, self.root_blk_cim_rp) = \
_profile_register_load(self._wbem_conn)

+ if namespace.lower() == SmisCommon._NETAPP_E_NAMESPACE.lower():
+ self._vendor_product = SmisCommon._PRODUCT_NETAPP_E
+
# Check 'Array' 1.4 support status.
_profile_check(
self._profile_dict, SmisCommon.SNIA_BLK_ROOT_PROFILE,
@@ -284,3 +289,6 @@ class SmisCommon(object):

def is_megaraid(self):
return self._vendor_product == SmisCommon._PRODUCT_MEGARAID
+
+ def is_netappe(self):
+ return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E
diff --git a/plugin/smispy/smisproxy.py b/plugin/smispy/smisproxy.py
deleted file mode 100644
index 19a32ce..0000000
--- a/plugin/smispy/smisproxy.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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: tasleson
-
-from smis import Smis
-from lsm import Proxy, VERSION
-import eseries
-
-#The unfortunate truth is that each of the vendors implements functionality
-#slightly differently so we will need to have some special code for these
-#instances.
-
-
-class SmisProxy(Proxy):
- """
- Layer to allow us to swap out different implementations of smi-s clients
- based on provider.
- """
- def plugin_info(self, flags=0):
- return "Generic SMI-S support", VERSION
-
- def plugin_register(self, uri, password, timeout, flags=0):
- """
- We will provide a concrete implementation of this to get the process
- started. All other method will be delegated to implementation.
- """
-
- #TODO Add code to interrogate the provider and then based on the type
- #we will instantiate the most appropriate implementation. At the
- #moment we will drop back to our current mixed implementation.
-
- #TODO We need to do a better job at check for this.
- if 'root/lsiarray13' in uri.lower():
- self.proxied_obj = eseries.ESeries()
- else:
- self.proxied_obj = Smis()
-
- self.proxied_obj.plugin_register(uri, password, timeout, flags)
diff --git a/plugin/smispy/smispy_lsmplugin b/plugin/smispy/smispy_lsmplugin
index de87c7d..b0ea003 100755
--- a/plugin/smispy/smispy_lsmplugin
+++ b/plugin/smispy/smispy_lsmplugin
@@ -23,10 +23,10 @@ import traceback

try:
from lsm import PluginRunner
- from lsm.plugin.smispy.smisproxy import SmisProxy
+ from lsm.plugin.smispy.smis import Smis

if __name__ == '__main__':
- PluginRunner(SmisProxy, sys.argv).run()
+ PluginRunner(Smis, 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
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:24 UTC
Permalink
From: Gris Ge <***@redhat.com>

* The SMI-S provider of HP 3PAR and LSI/Avago MegaRAID is using
'root/PG_Interop' namespace for profile register. Adding
'root/PG_Interop' into check list for profile register namespace.
* Move _merge_list() to separate file utils.py
* Move smis._merge_list() to utils.merge_list().
* Makefile and rpm spec updated.
* Moving SNIA class constants into SmisCommon class.
* SmisCommon class will handle WBEM connection which need __init__(),
so we create a SmisCommon class instead of using smis_common namespace.
* Makefile and RPM spec file updated.
* Move these constants into DMTF as they are defined in DMTF DSP1033:
Smis.DMTF_INTEROP_NAMESPACES => DMTF.INTEROP_NAMESPACES
Smis.SMIS_DEFAULT_NAMESPACE => DMTF.DEFAULT_NAMESPACE
* Move WBEM connection to SmisCommon. This allow use to move to other
WBEM client library in the future(like lmiwbem) with limited changes.
* In Smis class, the 'self._c' was a object of pywbem.WBEMConnection, now
a object of SmisCommon.
* To limit the changes of Smis class, wrap used method of WBEMConnection
in SmisCommon:
EnumerateInstances()
EnumerateInstanceNames()
InvokeMethod()
GetInstance()
References()
DeleteInstance()
Associators()
AssociatorNames()
These method names is defined by DMTF DSP0200, so I keep these CaMel method
name.

* EnumerateInstances() and EnumerateInstanceNames() will enumerate in vendor
name space instead of interop namespace. The vendor namespace was checked
by SmisCommon._vendor_namespace(self) via CIM_ElementConformsToProfile
association.

* New profile register in SmisCommon.__init__():
1. Only store highest version of certain profile.
Support status will be stored as SmisCommon._profile_dict in this
format:
{
SmisCommon.SNIA_DISK_LITE_PROFILE: \
SmisCommon.SMIS_SPEC_VER_1_4,

}
The SmisCommon._profile_dict will be used by
SmisCommon.profile_check().
2. Store root CIM_RegisteredProfile as SmisCommon.root_blk_cim_rp.
It will be used by Smis._root_cim_syss() method. (In other patch)
3. New profile support status check SmisCommon.profile_check().
4. Skip MegaRAID profile register check as they only support 1.2 'Array'
profile.

* Replace Smis._profile_is_supported() with SmisCommon.profile_check().
* Smis.cim_root_profile_dict is not needed anymore as
Smis._profile_is_supported() is replaced.

* Replace Smis._enumerate() with SmisCommon.EnumerateInstances() as
SmisCommon will handle the vendor namespace issue now.

* Replace Smis._enumerate() in disk capability check with
EnumerateInstanceNames() to save some time.[1]

* New method SmisCommon.is_megaraid(). It could be used to determine
the vendor specific code.

* Update Smis._root_cim_syss() to use SmisCommon.root_blk_cim_rp for
CIM_ElementConformsToProfile association.

* LSI/Avago MegaRAID has vendor specific code as it skip the profile
check[2]. It just enumerate all CIM_ComputerSystem as MegaRAID does not
support 'Multiple Computer System' profile.

[1] EnumerateInstanceNames() only return CIMInstanceName which contains
less data than a CIMInstance. For capability check, we just want to
find whether CIM_DiskDrive is supported or not. CIMInstanceName is enough
for this.

[2] If profile check skiped, SmisCommon.root_blk_cim_rp will be None.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 2 +
plugin/smispy/dmtf.py | 4 +
plugin/smispy/smis.py | 418 ++++++++++-----------------------------
plugin/smispy/smis_common.py | 286 +++++++++++++++++++++++++++
plugin/smispy/utils.py | 19 ++
6 files changed, 414 insertions(+), 317 deletions(-)
create mode 100644 plugin/smispy/smis_common.py
create mode 100644 plugin/smispy/utils.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 5e0871e..798d2f4 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -316,6 +316,8 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis.*
%{python_sitelib}/lsm/plugin/smispy/smisproxy.*
%{python_sitelib}/lsm/plugin/smispy/dmtf.*
+%{python_sitelib}/lsm/plugin/smispy/utils.*
+%{python_sitelib}/lsm/plugin/smispy/smis_common.*
%{_bindir}/smispy_lsmplugin

%files netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index 5a4dca2..a4605ab 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -27,6 +27,8 @@ smispy_PYTHON = \
smispy/smis.py \
smispy/smisproxy.py \
smispy/eseries.py \
+ smispy/utils.py \
+ smispy/smis_common.py \
smispy/dmtf.py

nstordir = $(plugindir)/nstor
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 5edbfc1..458e881 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -205,3 +205,7 @@ class DMTF(object):
SCS_CAP_VOLUME_CREATE = Uint16(5)
SCS_CAP_VOLUME_DELETE = Uint16(6)
SCS_CAP_VOLUME_MODIFY = Uint16(7)
+
+ # DSP 1033 Profile Registration
+ INTEROP_NAMESPACES = ['interop', 'root/interop', 'root/PG_Interop']
+ DEFAULT_NAMESPACE = 'interop'
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 870c6c1..3238b86 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -35,6 +35,8 @@ from lsm import (IStorageAreaNetwork, error, uri_parse, LsmError, ErrorNumber,
search_property)

from dmtf import DMTF
+from utils import merge_list
+from smis_common import SmisCommon

## Variable Naming scheme:
# cim_xxx CIMInstance
@@ -132,10 +134,6 @@ def _spec_ver_str_to_num(spec_ver_str):
return None


-def _merge_list(list_a, list_b):
- return list(set(list_a + list_b))
-
-
def _hex_string_format(hex_str, length, every):
hex_str = hex_str.lower()
return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
@@ -187,22 +185,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'
- DISK_LITE_PROFILE = 'Disk Drive Lite'
- MULTI_SYS_PROFILE = 'Multiple Computer System'
- MASK_PROFILE = 'Masking and Mapping'
- GROUP_MASK_PROFILE = 'Group Masking and Mapping'
- FC_TGT_PORT_PROFILE = 'FC Target Ports'
- ISCSI_TGT_PORT_PROFILE = 'iSCSI Target Ports'
- SMIS_SPEC_VER_1_4 = '1.4'
- SMIS_SPEC_VER_1_5 = '1.5'
- SMIS_SPEC_VER_1_6 = '1.6'
- REG_ORG_CODE = pywbem.Uint16(11)
-
-
class Smis(IStorageAreaNetwork):
"""
SMI-S plug-ing which exposes a small subset of the overall provided
@@ -326,9 +308,6 @@ class Smis(IStorageAreaNetwork):
DMTF_STATUS_COMPLETED = 17
DMTF_STATUS_POWER_MODE = 18

- # DSP 1033 Profile Registration
- DMTF_INTEROP_NAMESPACES = ['interop', 'root/interop']
- SMIS_DEFAULT_NAMESPACE = 'interop'

IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989
@@ -405,10 +384,7 @@ class Smis(IStorageAreaNetwork):
self._c = None
self.tmo = 0
self.system_list = None
- self.cim_rps = []
- self.cim_root_profile_dict = dict()
self.fallback_mode = True # Means we cannot use profile register
- self.all_vendor_namespaces = []
self.debug_path = None

def _get_cim_instance_by_id(self, class_type, requested_id,
@@ -424,9 +400,10 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = id_pros
else:
- property_list = _merge_list(property_list, id_pros)
+ property_list = merge_list(property_list, id_pros)

- cim_xxxs = self._enumerate(class_name, property_list)
+ cim_xxxs = self._c.EnumerateInstances(
+ class_name, PropertyList=property_list)
org_requested_id = requested_id
if class_type == 'Job':
(requested_id, ignore) = self._parse_job_id(requested_id)
@@ -450,10 +427,11 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = [prop_name]
else:
- property_list = _merge_list(property_list, [prop_name])
+ property_list = merge_list(property_list, [prop_name])

try:
- cim_xxxs = self._enumerate(class_name, property_list)
+ cim_xxxs = self._c.EnumerateInstances(
+ class_name, PropertyList=property_list)
except CIMError as ce:
error_code = tuple(ce)[0]

@@ -549,82 +527,27 @@ class Smis(IStorageAreaNetwork):
# System filtering
self.system_list = None

- namespace = None
- if 'namespace' in u['parameters']:
- namespace = u['parameters']['namespace']
- self.all_vendor_namespaces = [namespace]
- else:
- namespace = Smis.SMIS_DEFAULT_NAMESPACE
-
if 'systems' in u['parameters']:
self.system_list = split(u['parameters']["systems"], ":")

- if namespace is not None:
- self._c = pywbem.WBEMConnection(url, (u['username'], password),
- namespace)
- if "no_ssl_verify" in u["parameters"] \
- and u["parameters"]["no_ssl_verify"] == 'yes':
- try:
- self._c = pywbem.WBEMConnection(
- url,
- (u['username'], password),
- namespace,
- no_verification=True)
- except TypeError:
- # pywbem is not holding fix from
- # https://bugzilla.redhat.com/show_bug.cgi?id=1039801
- pass
+ namespace = None
+ if 'namespace' in u['parameters']:
+ namespace = u['parameters']['namespace']

- self.tmo = timeout
+ no_ssl_verify = False
+ if "no_ssl_verify" in u["parameters"] \
+ and u["parameters"]["no_ssl_verify"] == 'yes':
+ no_ssl_verify = True

+ debug = False
if 'debug_path' in u['parameters']:
self.debug_path = u['parameters']['debug_path']
- self._c.debug = True
-
- if 'force_fallback_mode' in u['parameters'] and \
- u['parameters']['force_fallback_mode'] == 'yes':
- return
+ debug = True

- # Checking profile registration support status unless
- # force_fallback_mode is enabled in URI.
- namespace_check_list = Smis.DMTF_INTEROP_NAMESPACES
- if 'namespace' in u['parameters'] and \
- u['parameters']['namespace'] not in namespace_check_list:
- namespace_check_list.extend([u['parameters']['namespace']])
+ self._c = SmisCommon(
+ url, u['username'], password, namespace, no_ssl_verify, debug)

- for interop_namespace in Smis.DMTF_INTEROP_NAMESPACES:
- try:
- self.cim_rps = self._c.EnumerateInstances(
- 'CIM_RegisteredProfile',
- namespace=interop_namespace,
- PropertyList=['RegisteredName', 'RegisteredVersion',
- 'RegisteredOrganization'],
- LocalOnly=False)
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_NAMESPACE or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- pass
- else:
- raise
- if len(self.cim_rps) != 0:
- break
-
- if len(self.cim_rps) >= 1:
- self.fallback_mode = False
- self.all_vendor_namespaces = []
- # Support 'Array' profile is step 0 for this whole plugin.
- # We find out all 'Array' CIM_RegisteredProfile and stored
- # them into self.cim_root_profile_dict
- if not self._profile_is_supported(
- SNIA.BLK_ROOT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False):
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Target SMI-S provider does not support "
- "SNIA SMI-S SPEC %s '%s' profile" %
- (SNIA.SMIS_SPEC_VER_1_4,
- SNIA.BLK_ROOT_PROFILE))
+ self.tmo = timeout

def time_out_set(self, ms, flags=0):
self.tmo = ms
@@ -712,7 +635,7 @@ class Smis(IStorageAreaNetwork):
try:
# Assuming provider support disk drive when systems under it
# support it.
- self._enumerate('CIM_DiskDrive')
+ self._c.EnumerateInstanceNames('CIM_DiskDrive')
except CIMError as e:
if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
e[0] == pywbem.CIM_ERR_INVALID_CLASS:
@@ -720,10 +643,9 @@ class Smis(IStorageAreaNetwork):
else:
raise
else:
- if not self._profile_is_supported(SNIA.DISK_LITE_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
- raise_error=False):
+ if not self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
return

cap.set(Capabilities.DISKS)
@@ -813,10 +735,9 @@ class Smis(IStorageAreaNetwork):
if cim_ccs_path is None:
return

- elif not self._profile_is_supported(SNIA.MASK_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
- raise_error=False):
+ elif not self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
return

cap.set(Capabilities.ACCESS_GROUPS)
@@ -870,25 +791,22 @@ class Smis(IStorageAreaNetwork):
e[0] == pywbem.CIM_ERR_INVALID_CLASS:
flag_iscsi_support = False
else:
- flag_fc_support = self._profile_is_supported(
- SNIA.FC_TGT_PORT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
+ flag_fc_support = self._c.profile_check(
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False)
# One more check for NetApp Typo:
# NetApp: 'FC Target Port'
# SMI-S: 'FC Target Ports'
# Bug reported.
if not flag_fc_support:
- flag_fc_support = self._profile_is_supported(
+ flag_fc_support = self._c.profile_check(
'FC Target Port',
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
+ SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False)
- flag_iscsi_support = self._profile_is_supported(
- SNIA.ISCSI_TGT_PORT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
+ flag_iscsi_support = self._c.profile_check(
+ SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False)

if flag_fc_support or flag_iscsi_support:
@@ -1116,7 +1034,7 @@ class Smis(IStorageAreaNetwork):
"class_type %s" % class_type)

if extra_properties:
- rc = _merge_list(rc, extra_properties)
+ rc = merge_list(rc, extra_properties)
return rc

def _sys_id_child(self, cim_xxx):
@@ -1546,7 +1464,7 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = ['Primordial']
else:
- property_list = _merge_list(property_list, ['Primordial'])
+ property_list = merge_list(property_list, ['Primordial'])

cim_pools = self._c.Associators(cim_sys_path,
AssocClass='CIM_HostedStoragePool',
@@ -2423,9 +2341,10 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = ['DeviceID']
else:
- property_list = _merge_list(property_list, ['DeviceID'])
+ property_list = merge_list(property_list, ['DeviceID'])

- cim_spcs = self._enumerate('CIM_SCSIProtocolController', property_list)
+ cim_spcs = self._c.EnumerateInstances(
+ 'CIM_SCSIProtocolController', PropertyList=property_list)

for cim_spc in cim_spcs:
if md5(cim_spc['DeviceID']) == access_group_id:
@@ -2523,10 +2442,9 @@ class Smis(IStorageAreaNetwork):
property_list = []

if (not self.fallback_mode and
- self._profile_is_supported(SNIA.MASK_PROFILE,
- SNIA.SMIS_SPEC_VER_1_6,
- strict=False,
- raise_error=False)):
+ self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_6,
+ raise_error=False)):
return self._c.Associators(
cim_spc_path,
AssocClass='CIM_AssociatedPrivilege',
@@ -2655,10 +2573,10 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = ['InstanceID']
else:
- property_list = _merge_list(property_list, ['InstanceID'])
+ property_list = merge_list(property_list, ['InstanceID'])

- cim_init_mgs = self._enumerate(
- 'CIM_InitiatorMaskingGroup', property_list)
+ cim_init_mgs = self._c.EnumerateInstances(
+ 'CIM_InitiatorMaskingGroup', PropertyList=property_list)

for cim_init_mg in cim_init_mgs:
if md5(cim_init_mg['InstanceID']) == access_group_id:
@@ -2707,22 +2625,20 @@ class Smis(IStorageAreaNetwork):
"""
if self.fallback_mode:
return Smis.MASK_TYPE_MASK
- if self._profile_is_supported(SNIA.GROUP_MASK_PROFILE,
- SNIA.SMIS_SPEC_VER_1_5,
- strict=False,
- raise_error=False):
+ if self._c.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_5,
+ raise_error=False):
return Smis.MASK_TYPE_GROUP
- if self._profile_is_supported(SNIA.MASK_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
- raise_error=False):
+ if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
return Smis.MASK_TYPE_MASK
if raise_error:
raise LsmError(ErrorNumber.NO_SUPPORT,
"Target SMI-S provider does not support "
"%s version %s or %s version %s" %
- (SNIA.MASK_PROFILE, SNIA.SMIS_SPEC_VER_1_4,
- SNIA.GROUP_MASK_PROFILE, SNIA.SMIS_SPEC_VER_1_5))
+ (SmisCommon.SNIA_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5))
return Smis.MASK_TYPE_NO_SUPPORT

@handle_cim_errors
@@ -2991,29 +2907,6 @@ class Smis(IStorageAreaNetwork):
except CIMError:
pass

- def _enumerate(self, class_name, property_list=None):
- """
- Please do the filter of "systems=" in URI by yourself.
- """
- if len(self.all_vendor_namespaces) == 0:
- # We need to find out the vendor spaces.
- # We do it here to save plugin_register() time.
- # Only non-fallback mode can goes there.
- cim_syss = self._root_cim_syss()
- all_vendor_namespaces = []
- for cim_sys in cim_syss:
- if cim_sys.path.namespace not in all_vendor_namespaces:
- all_vendor_namespaces.extend([cim_sys.path.namespace])
- self.all_vendor_namespaces = all_vendor_namespaces
- rc = []
- e_args = dict(LocalOnly=False)
- if property_list is not None:
- e_args['PropertyList'] = property_list
- for vendor_namespace in self.all_vendor_namespaces:
- rc.extend(self._c.EnumerateInstances(class_name, vendor_namespace,
- **e_args))
- return rc
-
@handle_cim_errors
def disks(self, search_key=None, search_value=None, flags=0):
"""
@@ -3030,12 +2923,12 @@ class Smis(IStorageAreaNetwork):
"""
rc = []
if not self.fallback_mode:
- self._profile_is_supported(SNIA.DISK_LITE_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
- raise_error=True)
+ self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=True)
cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
- cim_disks = self._enumerate('CIM_DiskDrive', cim_disk_pros)
+ cim_disks = self._c.EnumerateInstances(
+ 'CIM_DiskDrive', PropertyList=cim_disk_pros)
for cim_disk in cim_disks:
if self.system_list:
if self._sys_id_child(cim_disk) not in self.system_list:
@@ -3147,7 +3040,7 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = ['Primordial']
else:
- property_list = _merge_list(property_list, ['Primordial'])
+ property_list = merge_list(property_list, ['Primordial'])

cim_exts = self._c.Associators(
cim_disk_path,
@@ -3251,143 +3144,40 @@ class Smis(IStorageAreaNetwork):

return element_type, unsupported

- def _profile_is_supported(self, profile_name, spec_ver, strict=False,
- raise_error=False):
- """
- Usage:
- Check whether we support certain profile at certain SNIA
- specification version.
- When strict == False(default), profile spec version later or equal
- than require spec_ver will also be consider as found.
- When strict == True, only defined spec_version is allowed.
- Require self.cim_rps containing all CIM_RegisteredProfile
- Will raise LsmError(ErrorNumber.NO_SUPPORT, 'xxx') if raise_error
- is True when nothing found.
- Parameter:
- profile_name # SNIA.XXXX_PROFILE
- spec_ver # SNIA.SMIS_SPEC_VER_XXX
- strict # False or True. If True, only defined
- # spec_version is consider as supported
- # If false, will return the maximum version of
- # spec.
- raise_error # Raise LsmError if not found
- Returns:
- None # Not supported.
- or
- spec_int # Integer. Converted by _spec_ver_str_to_num()
- """
- req_ver = _spec_ver_str_to_num(spec_ver)
-
- max_spec_ver_str = None
- max_spec_ver = None
- for cim_rp in self.cim_rps:
- if 'RegisteredName' not in cim_rp or \
- 'RegisteredVersion' not in cim_rp:
- continue
- if cim_rp['RegisteredName'] == profile_name:
- # check spec version
- cur_ver = _spec_ver_str_to_num(cim_rp['RegisteredVersion'])
-
- if strict and cur_ver == req_ver:
- return cur_ver
- elif cur_ver >= req_ver:
- if max_spec_ver is None or \
- cur_ver > max_spec_ver:
- max_spec_ver = cur_ver
- max_spec_ver_str = cim_rp['RegisteredVersion']
- if (strict or max_spec_ver is None) and raise_error:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "SNIA SMI-S %s '%s' profile is not supported" %
- (spec_ver, profile_name))
-
- return max_spec_ver
-
def _root_cim_syss(self, property_list=None):
"""
- For fallback mode, this just enumerate CIM_ComputerSystem.
- We require vendor to implement profile registration when using
- "Multiple System Profile".
- For normal mode, this just find out the root CIM_ComputerSystem
- via:
+ Use this association to find out the root CIM_ComputerSystem

CIM_RegisteredProfile # Root Profile('Array') in interop
|
| CIM_ElementConformsToProfile
v
CIM_ComputerSystem # vendor namespace
-
- We also assume no matter which version of root profile can lead to
- the same CIM_ComputerSystem instance.
- As CIM_ComputerSystem has no property indicate SNIA SMI-S version,
- this is assumption should work. Tested on EMC SMI-S provider which
- provide 1.4, 1.5, 1.6 root profile.
+ For LSI MegaRAID, we just EnumerateInstances CIM_ComputerSystem.
"""
cim_scss_path = []
id_pros = self._property_list_of_id('System', property_list)
if property_list is None:
property_list = id_pros
else:
- property_list = _merge_list(property_list, id_pros)
+ property_list = merge_list(property_list, id_pros)

cim_syss = []
- if self.fallback_mode:
- # Fallback mode:
- # Find out the root CIM_ComputerSystem using the fallback method:
- # CIM_StorageConfigurationService # Enumerate
- # |
- # | CIM_HostedService
- # v
- # CIM_ComputerSystem
- # If CIM_StorageConfigurationService is not support neither,
- # we enumerate CIM_ComputerSystem.
- try:
- cim_scss_path = self._c.EnumerateInstanceNames(
- 'CIM_StorageConfigurationService')
- except CIMError as e:
- # If array does not support CIM_StorageConfigurationService
- # we use CIM_ComputerSystem which is mandatory.
- # We might get some non-storage array listed as system.
- # but we would like to take that risk instead of
- # skipping basic support of old SMIS provider.
- if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- cim_syss = self._c.EnumerateInstances(
- 'CIM_ComputerSystem',
- PropertyList=property_list,
- LocalOnly=False)
- else:
- raise
+ if self._c.is_megaraid():
+ cim_syss = self._c.EnumerateInstances(
+ 'CIM_ComputerSystem', PropertyList=property_list)

- if not cim_syss:
- for cim_scs_path in cim_scss_path:
- cim_tmp = None
- # CIM_ComputerSystem is one-one map to
- # CIM_StorageConfigurationService
- cim_tmp = self._c.Associators(
- cim_scs_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ComputerSystem',
- PropertyList=property_list)
- if cim_tmp and cim_tmp[0]:
- cim_syss.extend([cim_tmp[0]])
else:
- for cim_rp in self.cim_rps:
- if cim_rp['RegisteredName'] == SNIA.BLK_ROOT_PROFILE and\
- cim_rp['RegisteredOrganization'] == SNIA.REG_ORG_CODE:
- cim_syss = self._c.Associators(
- cim_rp.path,
- ResultClass='CIM_ComputerSystem',
- AssocClass='CIM_ElementConformsToProfile',
- PropertyList=property_list)
- # Any version of 'Array' profile can get us to root
- # CIM_ComputerSystem. startup() already has checked the
- # 1.4 version
- break
+ cim_syss = self._c.Associators(
+ self._c.root_blk_cim_rp.path,
+ ResultClass='CIM_ComputerSystem',
+ AssocClass='CIM_ElementConformsToProfile',
+ PropertyList=property_list)
if len(cim_syss) == 0:
raise LsmError(ErrorNumber.NO_SUPPORT,
"Current SMI-S provider does not provide "
"the root CIM_ComputerSystem associated "
- "to 'Array' CIM_RegisteredProfile. Try "
- "add 'force_fallback_mode=yes' into URI")
+ "to 'Array' CIM_RegisteredProfile.")

# System URI Filtering
if self.system_list:
@@ -3413,20 +3203,18 @@ class Smis(IStorageAreaNetwork):
return False
return True

- flag_fc_support = self._profile_is_supported(
- SNIA.FC_TGT_PORT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
+ flag_fc_support = self._c.profile_check(
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False)
# One more check for NetApp Typo:
# NetApp: 'FC Target Port'
# SMI-S: 'FC Target Ports'
# Bug reported.
if not flag_fc_support:
- flag_fc_support = self._profile_is_supported(
+ flag_fc_support = self._c.profile_check(
'FC Target Port',
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
+ SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False)
if flag_fc_support:
return True
@@ -3452,10 +3240,9 @@ class Smis(IStorageAreaNetwork):
return False
return True

- if self._profile_is_supported(SNIA.ISCSI_TGT_PORT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
- raise_error=False):
+ if self._c.profile_check(SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
return True
return False

@@ -3467,10 +3254,9 @@ class Smis(IStorageAreaNetwork):
"""
if self.fallback_mode:
return True
- flag_multi_sys_support = self._profile_is_supported(
- SNIA.MULTI_SYS_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
+ flag_multi_sys_support = self._c.profile_check(
+ SmisCommon.SNIA_MULTI_SYS_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=False)
if flag_multi_sys_support:
return True
@@ -3497,7 +3283,7 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = ['UsageRestriction']
else:
- property_list = _merge_list(property_list, ['UsageRestriction'])
+ property_list = merge_list(property_list, ['UsageRestriction'])
all_cim_syss_path = [cim_sys_path]
if self._multi_sys_is_supported():
all_cim_syss_path.extend(
@@ -3576,7 +3362,7 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = ['Role']
else:
- property_list = _merge_list(property_list, ['Role'])
+ property_list = merge_list(property_list, ['Role'])
all_cim_syss_path = [cim_sys_path]
if self._multi_sys_is_supported():
all_cim_syss_path.extend(
@@ -3778,10 +3564,10 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.NO_SUPPORT,
"Target SMI-S provider does not support any of"
"these profiles: '%s %s', '%s %s'"
- % (SNIA.SMIS_SPEC_VER_1_4,
- SNIA.FC_TGT_PORT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- SNIA.ISCSI_TGT_PORT_PROFILE))
+ % (SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE))

if flag_fc_support:
# CIM_FCPort might be not belong to root cim_sys
@@ -3916,9 +3702,9 @@ class Smis(IStorageAreaNetwork):
[1] At least check whether CIM_TargetMaskingGroup is already used
by other SPC.
"""
- cim_tgt_mgs = self._enumerate(
- class_name='CIM_TargetMaskingGroup',
- property_list=['ElementName'])
+ cim_tgt_mgs = self._c.EnumerateInstances(
+ 'CIM_TargetMaskingGroup',
+ PropertyList=['ElementName'])
for cim_tgt_mg in cim_tgt_mgs:
if cim_tgt_mg['ElementName'] == name:
return cim_tgt_mg.path
@@ -3932,9 +3718,9 @@ class Smis(IStorageAreaNetwork):
platform of Group Masking and Mapping.
When found CIM_DeviceMaskingGroup, make sure cim_vol is included.
"""
- cim_dev_mgs = self._enumerate(
- class_name='CIM_DeviceMaskingGroup',
- property_list=['ElementName'])
+ cim_dev_mgs = self._c.EnumerateInstances(
+ 'CIM_DeviceMaskingGroup',
+ PropertyList=['ElementName'])
cim_dev_mg = None
for tmp_cim_dev_mg in cim_dev_mgs:
if tmp_cim_dev_mg['ElementName'] == name:
@@ -3983,10 +3769,9 @@ class Smis(IStorageAreaNetwork):
"access_group_create() is not supported in "
"fallback mode")

- self._profile_is_supported(SNIA.GROUP_MASK_PROFILE,
- SNIA.SMIS_SPEC_VER_1_5,
- strict=False,
- raise_error=True)
+ self._c.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_5,
+ raise_error=True)

if init_type != AccessGroup.INIT_TYPE_WWPN and \
init_type != AccessGroup.INIT_TYPE_ISCSI_IQN:
@@ -4088,10 +3873,9 @@ class Smis(IStorageAreaNetwork):
"access_group_create() is not supported in "
"fallback mode")

- self._profile_is_supported(SNIA.GROUP_MASK_PROFILE,
- SNIA.SMIS_SPEC_VER_1_5,
- strict=False,
- raise_error=True)
+ self._c.profile_check(
+ SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
+ raise_error=True)

cim_init_mg = self._cim_init_mg_of_id(
access_group.id, raise_error=True)
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
new file mode 100644
index 0000000..27aa227
--- /dev/null
+++ b/plugin/smispy/smis_common.py
@@ -0,0 +1,286 @@
+# 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
+# version 2.1 of the License, or (at your option) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Author: Gris Ge <***@redhat.com>
+
+# This file stores:
+# 1. Constants of SNIA SMI-S.
+# 2. Methods shared by smis_sys.py and etc:
+# * Job control
+# * Profile register
+# * WBEM actions: enumerate, associations, getinstance and etc.
+
+from pywbem import Uint16, CIMError
+import pywbem
+
+from dmtf import DMTF
+from lsm import LsmError, ErrorNumber
+
+
+def _profile_register_load(wbem_conn):
+ """
+ Check CIM_RegisteredProfile in interop namespace.
+ Return (profile_dict, root_blk_cim_rp)
+ The 'profile_dict' is a dictionary like this:
+ {
+ # profile_name: max_version
+ 'Array': 1.4,
+ 'Block Service Profile': 1.4,
+ }
+ The 'root_blk_cim_rp' is the 'Array' profile of CIM_RegisteredProfile
+ with hightest version number.
+ """
+ profile_dict = {}
+ root_blk_cim_rp = None
+ namespace_check_list = DMTF.INTEROP_NAMESPACES
+
+ cim_rps = []
+ for namespace in namespace_check_list:
+ try:
+ cim_rps = wbem_conn.EnumerateInstances(
+ 'CIM_RegisteredProfile',
+ namespace=namespace,
+ PropertyList=['RegisteredName', 'RegisteredVersion',
+ 'RegisteredOrganization'],
+ LocalOnly=False)
+ except CIMError as e:
+ if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
+ e[0] == pywbem.CIM_ERR_INVALID_NAMESPACE or \
+ e[0] == pywbem.CIM_ERR_INVALID_CLASS:
+ pass
+ else:
+ raise
+ if len(cim_rps) != 0:
+ break
+
+ if len(cim_rps) >= 1:
+ for cim_rp in cim_rps:
+ if cim_rp['RegisteredOrganization'] != \
+ SmisCommon.SNIA_REG_ORG_CODE:
+ continue
+ profile_name = cim_rp['RegisteredName']
+ profile_ver = cim_rp['RegisteredVersion']
+ profile_ver_num = _profile_spec_ver_to_num(profile_ver)
+ if profile_name in profile_dict.keys():
+ exist_ver_num = _profile_spec_ver_to_num(
+ profile_dict[profile_name])
+ if exist_ver_num >= profile_ver_num:
+ continue
+ if profile_name == SmisCommon.SNIA_BLK_ROOT_PROFILE:
+ root_blk_cim_rp = cim_rp
+ profile_dict[profile_name] = profile_ver
+ else:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support DMTF DSP1033 profile "
+ "register which is mandatory for LSM")
+
+ return profile_dict, root_blk_cim_rp
+
+
+def _profile_check(profile_dict, profile_name, spec_ver,
+ raise_error=False):
+ """
+ Check whether we support certain profile at certain SNIA
+ specification version.
+ Profile spec version later or equal than require spec_ver will also be
+ consider as found.
+ Require profile_dict provided by SmisCommon.profile_register_load()
+ Will raise LsmError(ErrorNumber.NO_SUPPORT, 'xxx') if raise_error
+ is True when nothing found.
+ """
+ request_ver_num = _profile_spec_ver_to_num(spec_ver)
+ if profile_name not in profile_dict.keys():
+ if raise_error:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "SNIA SMI-S %s '%s' profile is not supported by " %
+ (profile_name, spec_ver) +
+ "target SMI-S provider")
+ return False
+
+ support_ver_num = _profile_spec_ver_to_num(profile_dict[profile_name])
+ if support_ver_num < request_ver_num:
+ if raise_error:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "SNIA SMI-S %s '%s' profile is not supported by " %
+ (profile_name, spec_ver) +
+ "target SMI-S provider. Only version %s is supported" %
+ profile_dict[profile_name])
+ return True
+
+
+def _profile_spec_ver_to_num(spec_ver_str):
+ """
+ Convert version string stored in CIM_RegisteredProfile to a integer.
+ Example:
+ "1.5.1" -> 1,005,001
+ """
+ tmp_list = [0, 0, 0]
+ tmp_list = spec_ver_str.split(".")
+ if len(tmp_list) == 2:
+ tmp_list.extend([0])
+ if len(tmp_list) == 3:
+ return (int(tmp_list[0]) * 10 ** 6 +
+ int(tmp_list[1]) * 10 ** 3 +
+ int(tmp_list[2]))
+ return None
+
+class SmisCommon(object):
+ SNIA_BLK_ROOT_PROFILE = 'Array'
+ SNIA_BLK_SRVS_PROFILE = 'Block Services'
+ SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite'
+ SNIA_MULTI_SYS_PROFILE = 'Multiple Computer System'
+ SNIA_MASK_PROFILE = 'Masking and Mapping'
+ SNIA_GROUP_MASK_PROFILE = 'Group Masking and Mapping'
+ SNIA_FC_TGT_PORT_PROFILE = 'FC Target Ports'
+ SNIA_ISCSI_TGT_PORT_PROFILE = 'iSCSI Target Ports'
+ SMIS_SPEC_VER_1_4 = '1.4'
+ SMIS_SPEC_VER_1_5 = '1.5'
+ SMIS_SPEC_VER_1_6 = '1.6'
+ SNIA_REG_ORG_CODE = Uint16(11)
+ _MEGARAID_NAMESPACE = 'root/LsiMr13'
+ _PRODUCT_MEGARAID = 'LSI MegaRAID'
+
+ def __init__(self, url, username, password,
+ namespace=DMTF.DEFAULT_NAMESPACE,
+ no_ssl_verify=False, debug=False):
+ self._wbem_conn = None
+ self._profile_dict = {}
+ self.root_blk_cim_rp = None # For root_cim_
+ self._vendor_product = None # For vendor workaround codes.
+
+ if namespace is None:
+ namespace = DMTF.DEFAULT_NAMESPACE
+
+ self._wbem_conn = pywbem.WBEMConnection(
+ url, (username, password), namespace)
+ if no_ssl_verify:
+ try:
+ self._wbem_conn = pywbem.WBEMConnection(
+ url, (username, password), namespace,
+ no_verification=True)
+ except TypeError:
+ # pywbem is not holding fix from
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1039801
+ pass
+
+ self._wbem_conn.debug = debug
+
+ if namespace.lower() == SmisCommon._MEGARAID_NAMESPACE.lower():
+ # Skip profile register check on MegaRAID for better performance.
+ # MegaRAID SMI-S profile support status will not change for a while.
+ self._profile_dict = {
+ # Provide a fake profile support status to pass the check.
+ SmisCommon.SNIA_BLK_ROOT_PROFILE: \
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SNIA_BLK_SRVS_PROFILE: \
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SNIA_DISK_LITE_PROFILE: \
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ }
+ self._vendor_product = SmisCommon._PRODUCT_MEGARAID
+ else:
+ (self._profile_dict, self.root_blk_cim_rp) = \
+ _profile_register_load(self._wbem_conn)
+
+ # Check 'Array' 1.4 support status.
+ _profile_check(
+ self._profile_dict, SmisCommon.SNIA_BLK_ROOT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4, raise_error=True)
+
+ def profile_check(self, profile_name, spec_ver, raise_error=False):
+ """
+ Usage:
+ Check whether we support certain profile at certain SNIA
+ specification version or later version.
+ Will raise LsmError(ErrorNumber.NO_SUPPORT, 'xxx') if raise_error
+ is True when nothing found.
+ Parameter:
+ profile_name # SmisCommon.SNIA_XXXX_PROFILE
+ spec_ver # SmisCommon.SMIS_SPEC_VER_XXX
+ raise_error # Raise LsmError if not found
+ Returns:
+ True
+ or
+ False
+ """
+ return _profile_check(
+ self._profile_dict, profile_name, spec_ver, raise_error)
+
+ def _vendor_namespace(self):
+ if self.root_blk_cim_rp:
+ cim_syss_path = self._wbem_conn.AssociatorNames(
+ self.root_blk_cim_rp.path,
+ ResultClass='CIM_ComputerSystem',
+ AssocClass='CIM_ElementConformsToProfile')
+ if len(cim_syss_path) == 0:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support any "
+ "CIM_ComputerSystem for SNIA SMI-S '%s' profile" %
+ SmisCommon.SNIA_BLK_ROOT_PROFILE)
+ return cim_syss_path[0].namespace
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "_vendor_namespace(): self.root_blk_cim_rp not set yet")
+
+ def EnumerateInstances(self, ClassName, namespace=None, **params):
+ if self._wbem_conn.default_namespace in DMTF.INTEROP_NAMESPACES:
+ # We have to enumerate in vendor namespace
+ self._wbem_conn.default_namespace = self._vendor_namespace()
+ params['LocalOnly']=False
+ return self._wbem_conn.EnumerateInstances(
+ ClassName, namespace, **params)
+
+ def EnumerateInstanceNames(self, ClassName, namespace=None, **params):
+ if self._wbem_conn.default_namespace in DMTF.INTEROP_NAMESPACES:
+ # We have to enumerate in vendor namespace
+ self._wbem_conn.default_namespace = self._vendor_namespace()
+ params['LocalOnly']=False
+ return self._wbem_conn.EnumerateInstanceNames(
+ ClassName, namespace, **params)
+
+ def Associators(self, ObjectName, **params):
+ return self._wbem_conn.Associators(ObjectName, **params)
+
+ def AssociatorNames(self, ObjectName, **params):
+ return self._wbem_conn.AssociatorNames(ObjectName, **params)
+
+ def GetInstance(self, InstanceName, **params):
+ params['LocalOnly']=False
+ return self._wbem_conn.GetInstance(InstanceName, **params)
+
+ def InvokeMethod(self, MethodName, ObjectName, **params):
+ return self._wbem_conn.InvokeMethod(MethodName, ObjectName, **params)
+
+ def DeleteInstance(self, InstanceName, **params):
+ return self._wbem_conn.DeleteInstance(InstanceName, **params)
+
+ def References(self, ObjectName, **params):
+ return self._wbem_conn.References(ObjectName, **params)
+
+ @property
+ def last_request(self):
+ return self._wbem_conn.last_request
+
+ @property
+ def last_reply(self):
+ return self._wbem_conn.last_reply
+
+ def is_megaraid(self):
+ return self._vendor_product == SmisCommon._PRODUCT_MEGARAID
diff --git a/plugin/smispy/utils.py b/plugin/smispy/utils.py
new file mode 100644
index 0000000..9b0bbbc
--- /dev/null
+++ b/plugin/smispy/utils.py
@@ -0,0 +1,19 @@
+# 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
+# version 2.1 of the License, or (at your option) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Author: Gris Ge <***@redhat.com>
+
+def merge_list(list_a, list_b):
+ return list(set(list_a + list_b))
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:27 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Just empty smis_sys.py file with license only.
* Makefile and RPM spec file updated.
* Replace Smis._property_list_of_id(self, "System") with
smis_sys.cim_sys_id_pros()
* Replace Smis._sys_id(self, cim_sys) with
smis_sys.sys_id_of_cim_sys(cim_sys)
* Move Smis.system_list to SmisCommon.system_list to allow
other smis_sys.py to do system filtering.
* Replaced Smis._root_cim_syss(self) with smis_sys.root_cim_sys(smis_common)
* Replace Smis._cim_sys_pros(self) with smis_sys.cim_sys_pros()
* Make DMTF._dmtf_op_status_list_conv() public as
DMTF.dmtf_op_status_list_conv().
* Move DMTF.cim_sys_status_of() to smis_sys._sys_status_of_cim_sys().
# Only used in smis_sys internally, hence hide from public.
* Move Smis._cim_sys_to_lsm() to smis_sys.cim_sys_to_lsm_sys()
* Add DMTF.OP_STATUS_UNKNOWN -> System.STATUS_UNKNOWN map.
Found EMC SMI-S provider will use 0(Unknown) for outdated system.
* Including smis_sys._sys_status_of_cim_sys() and
smis_sys.cim_sys_to_lsm_sys() changes in one patch as
_sys_status_of_cim_sys() is only used by smis_sys.cim_sys_to_lsm_sys().
* Replace Smis._get_cim_instance_by_id("System") with
smis_sys.cim_sys_of_sys_id()
* Fix the bug when query filtered system.
Example:

URI: smispy://***@emc-smi?systems=CLARiiON+APM00041704073
CMD: lsmcli capabilities --sys CLARiiON+FCN00122500421

Expected result:
lsmcli should report system not found as URI already filter that
requested system out.

Actual result:
lsmcli got capabilities of filtered system.

Fix:
Replace EnumerateInstances("CIM_ComputerSystem") with
smis_sys.root_cim_sys() which implemented the system filter.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 3 +-
plugin/smispy/dmtf.py | 25 +-----
plugin/smispy/smis.py | 170 +++++++++------------------------------
plugin/smispy/smis_common.py | 3 +-
plugin/smispy/smis_sys.py | 149 ++++++++++++++++++++++++++++++++++
6 files changed, 197 insertions(+), 154 deletions(-)
create mode 100644 plugin/smispy/smis_sys.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index ef39361..6eb1d55 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -318,6 +318,7 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_constants.*
%{python_sitelib}/lsm/plugin/smispy/smis_common.*
%{python_sitelib}/lsm/plugin/smispy/smis_cap.*
+%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
%{_bindir}/smispy_lsmplugin

%files netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index 30b4ea5..df411f3 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -29,7 +29,8 @@ smispy_PYTHON = \
smispy/smis_constants.py \
smispy/smis_common.py \
smispy/dmtf.py \
- smispy/smis_cap.py
+ smispy/smis_cap.py \
+ smispy/smis_sys.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 2bea0fe..d020a9a 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -77,17 +77,8 @@ class DMTF(object):
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,
+ def dmtf_op_status_list_conv(conv_dict, dmtf_op_status_list,
unknown_value, other_value):
status = 0
status_info_list = []
@@ -104,14 +95,6 @@ class DMTF(object):
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,
@@ -126,7 +109,7 @@ class DMTF(object):
"""
Convert CIM_StoragePool['OperationalStatus'] to LSM
"""
- return DMTF._dmtf_op_status_list_conv(
+ return DMTF.dmtf_op_status_list_conv(
DMTF._LSM_POOL_OP_STATUS_CONV, dmtf_op_status_list,
Pool.STATUS_UNKNOWN, Pool.STATUS_OTHER)

@@ -149,7 +132,7 @@ class DMTF(object):
Convert CIM_DiskDrive['OperationalStatus'] to LSM
Only return status, no status_info
"""
- return DMTF._dmtf_op_status_list_conv(
+ return DMTF.dmtf_op_status_list_conv(
DMTF._LSM_DISK_OP_STATUS_CONV, dmtf_op_status_list,
Disk.STATUS_UNKNOWN, Disk.STATUS_OTHER)[0]

@@ -278,4 +261,4 @@ DMTF_STATUS_ABORTED = 14
DMTF_STATUS_DORMANT = 15
DMTF_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16
DMTF_STATUS_COMPLETED = 17
-DMTF_STATUS_POWER_MODE = 18
\ No newline at end of file
+DMTF_STATUS_POWER_MODE = 18
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 84537bc..fc231dd 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -30,6 +30,7 @@ import pywbem
from pywbem import CIMError
from smis_constants import *
import smis_cap
+import smis_sys

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
JobStatus, md5, Volume, AccessGroup,
@@ -140,7 +141,6 @@ class Smis(IStorageAreaNetwork):
def __init__(self):
self._c = None
self.tmo = 0
- self.system_list = None
self.debug_path = None

def _get_cim_instance_by_id(self, class_type, requested_id,
@@ -246,10 +246,10 @@ class Smis(IStorageAreaNetwork):
url = "%s://%s:%s" % (protocol, u['host'], port)

# System filtering
- self.system_list = None
+ system_list = None

if 'systems' in u['parameters']:
- self.system_list = split(u['parameters']["systems"], ":")
+ system_list = split(u['parameters']["systems"], ":")

namespace = None
if 'namespace' in u['parameters']:
@@ -266,7 +266,8 @@ class Smis(IStorageAreaNetwork):
debug = True

self._c = SmisCommon(
- url, u['username'], password, namespace, no_ssl_verify, debug)
+ url, u['username'], password, namespace, no_ssl_verify, debug,
+ system_list)

self.tmo = timeout

@@ -284,8 +285,7 @@ class Smis(IStorageAreaNetwork):

@handle_cim_errors
def capabilities(self, system, flags=0):
- cim_sys = self._get_cim_instance_by_id(
- 'System', system.id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, system.id)
return smis_cap.get(self._c, cim_sys, system)

@handle_cim_errors
@@ -357,8 +357,6 @@ class Smis(IStorageAreaNetwork):
def _cim_class_name_of(class_type):
if class_type == 'Volume':
return 'CIM_StorageVolume'
- if class_type == 'System':
- return 'CIM_ComputerSystem'
if class_type == 'Pool':
return 'CIM_StoragePool'
if class_type == 'Disk':
@@ -377,8 +375,6 @@ class Smis(IStorageAreaNetwork):
def _not_found_error_of_class(class_type):
if class_type == 'Volume':
return ErrorNumber.NOT_FOUND_VOLUME
- if class_type == 'System':
- return ErrorNumber.NOT_FOUND_SYSTEM
if class_type == 'Pool':
return ErrorNumber.NOT_FOUND_POOL
if class_type == 'Job':
@@ -399,8 +395,6 @@ class Smis(IStorageAreaNetwork):
rc = []
if class_type == 'Volume':
rc = ['SystemName', 'DeviceID']
- elif class_type == 'System':
- rc = ['Name']
elif class_type == 'Pool':
rc = ['InstanceID']
elif class_type == 'SystemChild':
@@ -427,12 +421,6 @@ class Smis(IStorageAreaNetwork):
"""
return self._id('SystemChild', cim_xxx)

- def _sys_id(self, cim_sys):
- """
- Return CIM_ComputerSystem['Name']
- """
- return self._id('System', cim_sys)
-
def _pool_id(self, cim_pool):
"""
Return CIM_StoragePool['InstanceID']
@@ -819,11 +807,11 @@ class Smis(IStorageAreaNetwork):
profile.
"""
rc = []
- cim_sys_pros = self._property_list_of_id("System")
- cim_syss = self._root_cim_syss(cim_sys_pros)
+ cim_sys_pros = smis_sys.cim_sys_id_pros()
+ cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
cim_vol_pros = self._cim_vol_pros()
for cim_sys in cim_syss:
- sys_id = self._sys_id(cim_sys)
+ sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
pool_pros = self._property_list_of_id('Pool')
for cim_pool in self._cim_pools_of(cim_sys.path, pool_pros):
pool_id = self._pool_id(cim_pool)
@@ -884,11 +872,11 @@ class Smis(IStorageAreaNetwork):
rc = []
cim_pool_pros = self._new_pool_cim_pool_pros()

- cim_sys_pros = self._property_list_of_id("System")
- cim_syss = self._root_cim_syss(cim_sys_pros)
+ cim_sys_pros = smis_sys.cim_sys_id_pros()
+ cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)

for cim_sys in cim_syss:
- system_id = self._sys_id(cim_sys)
+ system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
for cim_pool in self._cim_pools_of(cim_sys.path, cim_pool_pros):
# Skip spare storage pool.
if 'Usage' in cim_pool and \
@@ -930,12 +918,12 @@ class Smis(IStorageAreaNetwork):
Find out the system ID for certain CIM_StoragePool.
Will return '' if failed.
"""
- sys_pros = self._property_list_of_id('System')
+ sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = self._c.Associators(cim_pool.path,
ResultClass='CIM_ComputerSystem',
PropertyList=sys_pros)
if len(cim_syss) == 1:
- return self._sys_id(cim_syss[0])
+ return smis_sys.sys_id_of_cim_sys(cim_syss[0])
return ''

@handle_cim_errors
@@ -969,29 +957,6 @@ class Smis(IStorageAreaNetwork):
total_space, free_space,
status, status_info, system_id)

- @staticmethod
- 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:
- (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):
- """
- Return a list of properties required to create a LSM System
- """
- cim_sys_pros = self._property_list_of_id('System',
- ['ElementName',
- 'OperationalStatus'])
- return cim_sys_pros
-
@handle_cim_errors
def systems(self, flags=0):
"""
@@ -1001,10 +966,10 @@ class Smis(IStorageAreaNetwork):
don't check support status here as startup() already checked 'Array'
profile.
"""
- cim_sys_pros = self._cim_sys_pros()
- cim_syss = self._root_cim_syss(cim_sys_pros)
+ cim_sys_pros = smis_sys.cim_sys_pros()
+ cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)

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

def _check_for_dupe_vol(self, volume_name, original_exception):
"""
@@ -1494,8 +1459,7 @@ class Smis(IStorageAreaNetwork):
target ports(all FC and FCoE port for access_group.init_type == WWPN,
and the same to iSCSI)
"""
- cim_sys = self._get_cim_instance_by_id(
- 'System', access_group.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

cim_init_mg = self._cim_init_mg_of_id(access_group.id,
raise_error=True)
@@ -1577,8 +1541,7 @@ class Smis(IStorageAreaNetwork):
mask_type = smis_cap.mask_type(self._c, raise_error=True)
# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_sys = self._get_cim_instance_by_id(
- 'System', volume.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
if cim_sys.path.classname == 'Clar_StorageSystem':
mask_type = smis_cap.MASK_TYPE_MASK

@@ -1597,8 +1560,7 @@ class Smis(IStorageAreaNetwork):
access_group.id +
"will not do volume_mask()")

- cim_sys = self._get_cim_instance_by_id(
- 'System', volume.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
cim_css_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

@@ -1626,8 +1588,7 @@ class Smis(IStorageAreaNetwork):
"""
cim_vol = self._get_cim_instance_by_id(
'Volume', volume.id, raise_error=True)
- cim_sys = self._get_cim_instance_by_id(
- 'System', volume.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)

cim_gmm_cap = self._c.Associators(
cim_sys.path,
@@ -1721,8 +1682,7 @@ class Smis(IStorageAreaNetwork):
mask_type = smis_cap.mask_type(self._c, raise_error=True)
# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_sys = self._get_cim_instance_by_id(
- 'System', volume.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
if cim_sys.path.classname == 'Clar_StorageSystem':
mask_type = smis_cap.MASK_TYPE_MASK

@@ -1731,8 +1691,7 @@ class Smis(IStorageAreaNetwork):
return self._volume_unmask_old(access_group, volume)

def _volume_unmask_old(self, access_group, volume):
- cim_sys = self._get_cim_instance_by_id(
- 'System', access_group.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

@@ -1924,8 +1883,8 @@ class Smis(IStorageAreaNetwork):

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_sys = self._get_cim_instance_by_id(
- 'System', access_group.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(
+ self._c, access_group.system_id)
if cim_sys.path.classname == 'Clar_StorageSystem':
mask_type = smis_cap.MASK_TYPE_MASK

@@ -1964,8 +1923,7 @@ class Smis(IStorageAreaNetwork):

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_sys = self._get_cim_instance_by_id(
- 'System', volume.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
if cim_sys.path.classname == 'Clar_StorageSystem':
mask_type = smis_cap.MASK_TYPE_MASK

@@ -2054,8 +2012,8 @@ class Smis(IStorageAreaNetwork):
rc = []
mask_type = smis_cap.mask_type(self._c, raise_error=True)

- cim_sys_pros = self._property_list_of_id('System')
- cim_syss = self._root_cim_syss(cim_sys_pros)
+ cim_sys_pros = smis_sys.cim_sys_id_pros()
+ cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)

cim_spc_pros = self._cim_spc_pros()
for cim_sys in cim_syss:
@@ -2065,7 +2023,7 @@ class Smis(IStorageAreaNetwork):
# CIM_RegisteredProfile, but actually they don't support it.
mask_type = smis_cap.MASK_TYPE_MASK

- system_id = self._sys_id(cim_sys)
+ system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg_pros = self._cim_init_mg_pros()
cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
@@ -2124,8 +2082,7 @@ class Smis(IStorageAreaNetwork):
expect_class='CIM_StorageHardwareID')

def _ag_init_add_group(self, access_group, init_id, init_type):
- cim_sys = self._get_cim_instance_by_id(
- 'System', access_group.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

if cim_sys.path.classname == 'Clar_StorageSystem':
raise LsmError(ErrorNumber.NO_SUPPORT,
@@ -2182,8 +2139,7 @@ class Smis(IStorageAreaNetwork):
def _ag_init_add_old(self, access_group, init_id, init_type):
# CIM_StorageHardwareIDManagementService.CreateStorageHardwareID()
# is mandatory since 1.4rev6
- cim_sys = self._get_cim_instance_by_id(
- 'System', access_group.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

if cim_sys.path.classname == 'Clar_StorageSystem':
raise LsmError(ErrorNumber.NO_SUPPORT,
@@ -2229,8 +2185,7 @@ class Smis(IStorageAreaNetwork):
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_sys = self._get_cim_instance_by_id(
- 'System', access_group.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

cim_init_mg_pros = self._cim_init_mg_pros()
cim_init_mg = self._cim_init_mg_of_id(
@@ -2291,8 +2246,7 @@ class Smis(IStorageAreaNetwork):
return self._ag_init_del_old(access_group, init_id)

def _ag_init_del_old(self, access_group, init_id):
- cim_sys = self._get_cim_instance_by_id(
- 'System', access_group.system_id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)

@@ -2344,8 +2298,8 @@ class Smis(IStorageAreaNetwork):
cim_disks = self._c.EnumerateInstances(
'CIM_DiskDrive', PropertyList=cim_disk_pros)
for cim_disk in cim_disks:
- if self.system_list:
- if self._sys_id_child(cim_disk) not in self.system_list:
+ if self._c.system_list:
+ if self._sys_id_child(cim_disk) not in self._c.system_list:
continue
cim_ext_pros = Smis._new_disk_cim_ext_pros(flags)
cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path,
@@ -2558,51 +2512,6 @@ class Smis(IStorageAreaNetwork):

return element_type, unsupported

- def _root_cim_syss(self, property_list=None):
- """
- Use this association to find out the root CIM_ComputerSystem
-
- CIM_RegisteredProfile # Root Profile('Array') in interop
- |
- | CIM_ElementConformsToProfile
- v
- CIM_ComputerSystem # vendor namespace
- For LSI MegaRAID, we just EnumerateInstances CIM_ComputerSystem.
- """
- cim_scss_path = []
- id_pros = self._property_list_of_id('System', property_list)
- if property_list is None:
- property_list = id_pros
- else:
- property_list = merge_list(property_list, id_pros)
-
- cim_syss = []
- if self._c.is_megaraid():
- cim_syss = self._c.EnumerateInstances(
- 'CIM_ComputerSystem', PropertyList=property_list)
-
- else:
- cim_syss = self._c.Associators(
- self._c.root_blk_cim_rp.path,
- ResultClass='CIM_ComputerSystem',
- AssocClass='CIM_ElementConformsToProfile',
- PropertyList=property_list)
- if len(cim_syss) == 0:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Current SMI-S provider does not provide "
- "the root CIM_ComputerSystem associated "
- "to 'Array' CIM_RegisteredProfile.")
-
- # System URI Filtering
- if self.system_list:
- needed_cim_syss = []
- for cim_sys in cim_syss:
- if self._sys_id(cim_sys) in self.system_list:
- needed_cim_syss.extend([cim_sys])
- return needed_cim_syss
- else:
- return cim_syss
-
@staticmethod
def _is_frontend_fc_tgt(cim_fc_tgt):
"""
@@ -2890,10 +2799,10 @@ class Smis(IStorageAreaNetwork):
'PermanentAddress', 'PortDiscriminator',
'LinkTechnology', 'DeviceID']

- cim_syss = self._root_cim_syss(
- property_list=self._property_list_of_id('System'))
+ cim_syss = smis_sys.root_cim_sys(
+ self._c, property_list=smis_sys.cim_sys_id_pros())
for cim_sys in cim_syss:
- system_id = self._sys_id(cim_sys)
+ system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
flag_fc_support = smis_cap.fc_tgt_is_supported(self._c)
flag_iscsi_support = smis_cap.iscsi_tgt_is_supported(self._c)

@@ -3115,8 +3024,7 @@ class Smis(IStorageAreaNetwork):
"SMI-S plugin only support creating FC/FCoE WWPN "
"and iSCSI AccessGroup")

- cim_sys = self._get_cim_instance_by_id(
- 'System', system.id, raise_error=True)
+ cim_sys = smis_sys.cim_sys_of_sys_id(self._c, system.id)
if cim_sys.path.classname == 'Clar_StorageSystem':
# EMC VNX/CX does not support Group M&M, which incorrectly exposed
# in CIM_RegisteredProfile
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 6f91b20..d66286c 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -161,11 +161,12 @@ class SmisCommon(object):

def __init__(self, url, username, password,
namespace=DMTF.DEFAULT_NAMESPACE,
- no_ssl_verify=False, debug=False):
+ no_ssl_verify=False, debug=False, system_list=None):
self._wbem_conn = None
self._profile_dict = {}
self.root_blk_cim_rp = None # For root_cim_
self._vendor_product = None # For vendor workaround codes.
+ self.system_list = system_list

if namespace is None:
namespace = DMTF.DEFAULT_NAMESPACE
diff --git a/plugin/smispy/smis_sys.py b/plugin/smispy/smis_sys.py
new file mode 100644
index 0000000..683ae2b
--- /dev/null
+++ b/plugin/smispy/smis_sys.py
@@ -0,0 +1,149 @@
+## 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
+# 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>
+
+from utils import merge_list
+from dmtf import DMTF
+from lsm import System, LsmError, ErrorNumber
+
+
+def cim_sys_id_pros():
+ """
+ Return the property of CIM_ComputerSystem required to gernarate
+ lsm.System.id
+ """
+ return ['Name']
+
+
+def sys_id_of_cim_sys(cim_sys):
+ if 'Name' in cim_sys:
+ return cim_sys['Name']
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_id_of_cim_sys(): Got a CIM_ComputerSystem does not have "
+ "'Name' property: %s, %s" % (cim_sys.items(), cim_sys.path))
+
+
+def root_cim_sys(smis_common, property_list=None):
+ """
+ Use this association to find out the root CIM_ComputerSystem:
+ CIM_RegisteredProfile # Root Profile('Array') in interop
+ |
+ | CIM_ElementConformsToProfile
+ v
+ CIM_ComputerSystem # vendor namespace
+ """
+ id_pros = cim_sys_id_pros()
+ if property_list is None:
+ property_list = id_pros
+ else:
+ property_list = merge_list(property_list, id_pros)
+
+ cim_syss = []
+ if smis_common.is_megaraid():
+ cim_syss = smis_common.EnumerateInstances(
+ 'CIM_ComputerSystem', PropertyList=property_list)
+ else:
+ cim_syss = smis_common.Associators(
+ smis_common.root_blk_cim_rp.path,
+ ResultClass='CIM_ComputerSystem',
+ AssocClass='CIM_ElementConformsToProfile',
+ PropertyList=property_list)
+
+ if len(cim_syss) == 0:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Current SMI-S provider does not provide "
+ "the root CIM_ComputerSystem associated "
+ "to 'Array' CIM_RegisteredProfile.")
+
+ # System URI Filtering
+ if smis_common.system_list:
+ needed_cim_syss = []
+ for cim_sys in cim_syss:
+ if sys_id_of_cim_sys(cim_sys) in smis_common.system_list:
+ needed_cim_syss.extend([cim_sys])
+ return needed_cim_syss
+ else:
+ return cim_syss
+
+
+def cim_sys_pros():
+ """
+ Return a list of properties required to create a LSM System
+ """
+ cim_sys_pros = cim_sys_id_pros()
+ cim_sys_pros.extend(['ElementName', 'OperationalStatus'])
+ return cim_sys_pros
+
+
+_LSM_SYS_OP_STATUS_CONV = {
+ DMTF.OP_STATUS_UNKNOWN: System.STATUS_UNKNOWN,
+ DMTF.OP_STATUS_OK: System.STATUS_OK,
+ DMTF.OP_STATUS_ERROR: System.STATUS_ERROR,
+ DMTF.OP_STATUS_DEGRADED: System.STATUS_DEGRADED,
+ DMTF.OP_STATUS_NON_RECOVERABLE_ERROR: System.STATUS_ERROR,
+ DMTF.OP_STATUS_PREDICTIVE_FAILURE: System.STATUS_PREDICTIVE_FAILURE,
+ DMTF.OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: System.STATUS_ERROR,
+}
+
+
+def _sys_status_of_cim_sys(cim_sys):
+ """
+ Convert CIM_ComputerSystem['OperationalStatus']
+ """
+ if 'OperationalStatus' not in cim_sys:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_status_of_cim_sys(): Got a CIM_ComputerSystem with no "
+ "OperationalStatus: %s, %s" % (cim_sys.items(), cim_sys.path))
+
+ return DMTF.dmtf_op_status_list_conv(
+ _LSM_SYS_OP_STATUS_CONV, cim_sys['OperationalStatus'],
+ System.STATUS_UNKNOWN, System.STATUS_OTHER)
+
+
+def cim_sys_to_lsm_sys(cim_sys):
+ status = System.STATUS_UNKNOWN
+ status_info = ''
+
+ if 'OperationalStatus' in cim_sys:
+ (status, status_info) = _sys_status_of_cim_sys(cim_sys)
+
+ sys_id = sys_id_of_cim_sys(cim_sys)
+ sys_name = cim_sys['ElementName']
+
+ return System(sys_id, sys_name, status, status_info)
+
+
+def cim_sys_of_sys_id(smis_common, sys_id, property_list=None):
+ """
+ Find out the CIM_ComputerSystem for given lsm.System.id using
+ root_cim_sys()
+ """
+ id_pros = cim_sys_id_pros()
+ if property_list is None:
+ property_list = id_pros
+ else:
+ property_list = merge_list(property_list, id_pros)
+
+ cim_syss = root_cim_sys(smis_common, property_list)
+ for cim_sys in cim_syss:
+ if sys_id_of_cim_sys(cim_sys) == sys_id:
+ return cim_sys
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "Not found System")
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:29 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Empty smis_disk.py with license file only.
* Makefile and RPM spec file updated.
* Remove as no method is using EMC_DISK_STATUS_REMOVED constants.
* Replace DMTF.cim_disk_status_of() with smis_disk.disk_status_of_cim_disk()
* Replace dmtf.dmtf_disk_type_2_lsm_disk_type() with
smis_disk.dmtf_disk_type_2_lsm_disk_type()
* Remove unused method Smis._cim_disk_of_pri_ext()
* Replace Smis._disk_id() with smis_disk.disk_id_of_cim_disk()
* Replace Smis._new_disk_cim_disk_pros() with
smis_disk.cim_disk_pros()
* Replace Smis._sys_id_child(cim_disk) with
smis_disk.sys_id_of_cim_disk(cim_disk)
* Replace Smis._new_disk() with smis_disk.cim_disk_to_lsm_disk()
* Moved Smis._pri_cim_ext_of_cim_disk() into smis_disk.
* Merged Smis._new_disk_cim_ext_pros() into smis_disk.cim_disk_to_lsm_disk()
as no need to has a method for storing a non-shared list.
* Combining these changes in one patch as they are internal actions for
smis_disk.cim_disk_to_lsm_disk().
* Hide these internal methods of smis_disk:
smis_disk.disk_id_of_cim_disk()
-> smis_disk._disk_id_of_cim_disk()
smis_disk.dmtf_disk_type_2_lsm_disk_type()
-> smis_disk._dmtf_disk_type_2_lsm_disk_type()
smis_disk.disk_status_of_cim_disk()
-> smis_disk._disk_status_of_cim_disk()

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 3 +-
plugin/smispy/dmtf.py | 39 --------
plugin/smispy/smis.py | 169 ++-------------------------------
plugin/smispy/smis_disk.py | 197 +++++++++++++++++++++++++++++++++++++++
5 files changed, 207 insertions(+), 202 deletions(-)
create mode 100644 plugin/smispy/smis_disk.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 5656548..32125ee 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -320,6 +320,7 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_cap.*
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
+%{python_sitelib}/lsm/plugin/smispy/smis_disk.*
%{_bindir}/smispy_lsmplugin

%files netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index 793fb0b..df8907d 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -31,7 +31,8 @@ smispy_PYTHON = \
smispy/dmtf.py \
smispy/smis_cap.py \
smispy/smis_sys.py \
- smispy/smis_pool.py
+ smispy/smis_pool.py \
+ smispy/smis_disk.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index c5ea3fe..8ebf06a 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -96,29 +96,6 @@ class DMTF(object):
return status, " ".join(status_info_list)


- EMC_DISK_STATUS_REMOVED = 32768
-
- _LSM_DISK_OP_STATUS_CONV = {
- OP_STATUS_UNKNOWN: Disk.STATUS_UNKNOWN,
- OP_STATUS_OK: Disk.STATUS_OK,
- OP_STATUS_PREDICTIVE_FAILURE: Disk.STATUS_PREDICTIVE_FAILURE,
- OP_STATUS_ERROR: Disk.STATUS_ERROR,
- OP_STATUS_NON_RECOVERABLE_ERROR: Disk.STATUS_ERROR,
- OP_STATUS_STARTING: Disk.STATUS_STARTING,
- OP_STATUS_STOPPING: Disk.STATUS_STOPPING,
- OP_STATUS_STOPPED: Disk.STATUS_STOPPED,
- }
-
- @staticmethod
- def cim_disk_status_of(dmtf_op_status_list):
- """
- Convert CIM_DiskDrive['OperationalStatus'] to LSM
- Only return status, no status_info
- """
- return DMTF.dmtf_op_status_list_conv(
- DMTF._LSM_DISK_OP_STATUS_CONV, dmtf_op_status_list,
- Disk.STATUS_UNKNOWN, Disk.STATUS_OTHER)[0]
-
# CIM_StorageHardwareID['IDType']
ID_TYPE_OTHER = Uint16(1)
ID_TYPE_WWPN = Uint16(2)
@@ -210,22 +187,6 @@ DMTF_DISK_TYPE_HDD = 2
DMTF_DISK_TYPE_SSD = 3
DMTF_DISK_TYPE_HYBRID = 4

-_DMTF_DISK_TYPE_2_LSM = {
- DMTF_DISK_TYPE_UNKNOWN: Disk.TYPE_UNKNOWN,
- DMTF_DISK_TYPE_OTHER: Disk.TYPE_OTHER,
- DMTF_DISK_TYPE_HDD: Disk.TYPE_HDD,
- DMTF_DISK_TYPE_SSD: Disk.TYPE_SSD,
- DMTF_DISK_TYPE_HYBRID: Disk.TYPE_HYBRID,
-}
-
-
-def dmtf_disk_type_2_lsm_disk_type(dmtf_disk_type):
- if dmtf_disk_type in _DMTF_DISK_TYPE_2_LSM.keys():
- return _DMTF_DISK_TYPE_2_LSM[dmtf_disk_type]
- else:
- return Disk.TYPE_UNKNOWN
-
-
DMTF_STATUS_UNKNOWN = 0
DMTF_STATUS_OTHER = 1
DMTF_STATUS_OK = 2
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 56b2912..351de57 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -32,6 +32,7 @@ from smis_constants import *
import smis_cap
import smis_sys
import smis_pool
+import smis_disk

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
JobStatus, md5, Volume, AccessGroup,
@@ -423,12 +424,6 @@ class Smis(IStorageAreaNetwork):
"""
return self._id('Volume', cim_vol)

- def _disk_id(self, cim_disk):
- """
- Return the MD5 hash of CIM_DiskDrive['SystemName'] and ['DeviceID']
- """
- return self._id('Disk', cim_disk)
-
def _job_id(self, cim_job, retrieve_data):
"""
Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
@@ -2130,7 +2125,6 @@ class Smis(IStorageAreaNetwork):
return all object of data.Disk.
We are using "Disk Drive Lite Subprofile" v1.4 of SNIA SMI-S for these
classes to create LSM Disk:
- CIM_PhysicalPackage
CIM_DiskDrive
CIM_StorageExtent (Primordial)
Due to 'Multiple Computer System' profile, disks might associated to
@@ -2142,168 +2136,19 @@ class Smis(IStorageAreaNetwork):
self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
SmisCommon.SMIS_SPEC_VER_1_4,
raise_error=True)
- cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
+ cim_disk_pros = smis_disk.cim_disk_pros()
cim_disks = self._c.EnumerateInstances(
'CIM_DiskDrive', PropertyList=cim_disk_pros)
for cim_disk in cim_disks:
- if self._c.system_list:
- if self._sys_id_child(cim_disk) not in self._c.system_list:
- continue
- cim_ext_pros = Smis._new_disk_cim_ext_pros(flags)
- cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path,
- cim_ext_pros)
+ if self._c.system_list and \
+ smis_disk.sys_id_of_cim_disk(cim_disk) not in \
+ self._c.system_list:
+ continue

- rc.extend([self._new_disk(cim_disk, cim_ext)])
+ rc.extend([smis_disk.cim_disk_to_lsm_disk(self._c, cim_disk)])
return search_property(rc, search_key, search_value)

@staticmethod
- def _new_disk_cim_disk_pros(flag=0):
- """
- Return all CIM_DiskDrive Properties needed to create a Disk object.
- """
- pros = ['OperationalStatus', 'Name', 'SystemName',
- 'Caption', 'InterconnectType', 'DiskType']
- return pros
-
- @staticmethod
- def _new_disk_cim_ext_pros(flag=0):
- """
- Return all CIM_StorageExtent Properties needed to create a Disk
- object.
- """
- return ['BlockSize', 'NumberOfBlocks']
-
- def _new_disk(self, cim_disk, cim_ext):
- """
- Takes a CIM_DiskDrive and CIM_StorageExtent, returns a lsm Disk
- Assuming cim_disk and cim_ext already contained the correct
- properties.
- """
- status = Disk.STATUS_UNKNOWN
- name = ''
- block_size = Disk.BLOCK_SIZE_NOT_FOUND
- num_of_block = Disk.BLOCK_COUNT_NOT_FOUND
- disk_type = Disk.TYPE_UNKNOWN
- status_info = ''
- sys_id = self._sys_id_child(cim_disk)
-
- # These are mandatory
- # we do not check whether they follow the SNIA standard.
- if 'OperationalStatus' in cim_disk:
- status = DMTF.cim_disk_status_of(cim_disk['OperationalStatus'])
- if 'Name' in cim_disk:
- name = cim_disk["Name"]
- if 'BlockSize' in cim_ext:
- block_size = cim_ext['BlockSize']
- if 'NumberOfBlocks' in cim_ext:
- num_of_block = cim_ext['NumberOfBlocks']
-
- # SNIA SMI-S 1.4 or even 1.6 does not define anyway to find out disk
- # type.
- # Currently, EMC is following DMTF define to do so.
- if 'InterconnectType' in cim_disk: # DMTF 2.31 CIM_DiskDrive
- disk_type = cim_disk['InterconnectType']
- if 'Caption' in cim_disk:
- # EMC VNX introduced NL_SAS disk.
- if cim_disk['Caption'] == 'NL_SAS':
- disk_type = Disk.TYPE_NL_SAS
-
- if disk_type == Disk.TYPE_UNKNOWN and 'DiskType' in cim_disk:
- disk_type = \
- dmtf_disk_type_2_lsm_disk_type(cim_disk['DiskType'])
-
- # LSI way for checking disk type
- if not disk_type and cim_disk.classname == 'LSIESG_DiskDrive':
- cim_pes = self._c.Associators(
- cim_disk.path,
- AssocClass='CIM_SAPAvailableForElement',
- ResultClass='CIM_ProtocolEndpoint',
- PropertyList=['CreationClassName'])
- if cim_pes and cim_pes[0]:
- if 'CreationClassName' in cim_pes[0]:
- ccn = cim_pes[0]['CreationClassName']
- if ccn == 'LSIESG_TargetSATAProtocolEndpoint':
- disk_type = Disk.TYPE_SATA
- if ccn == 'LSIESG_TargetSASProtocolEndpoint':
- disk_type = Disk.TYPE_SAS
-
- new_disk = Disk(self._disk_id(cim_disk), name, disk_type, block_size,
- num_of_block, status, sys_id)
-
- return new_disk
-
- def _pri_cim_ext_of_cim_disk(self, cim_disk_path, property_list=None):
- """
- Usage:
- Find out the Primordial CIM_StorageExtent of CIM_DiskDrive
- In SNIA SMI-S 1.4 rev.6 Block book, section 11.1.1 'Base Model'
- quote:
- A disk drive is modeled as a single MediaAccessDevice (DiskDrive)
- That shall be linked to a single StorageExtent (representing the
- storage in the drive) by a MediaPresent association. The
- StorageExtent class represents the storage of the drive and
- contains its size.
- Parameter:
- cim_disk_path # CIM_InstanceName of CIM_DiskDrive
- property_list # a List of properties needed on returned
- # CIM_StorageExtent
- Returns:
- cim_pri_ext # The CIM_Instance of Primordial CIM_StorageExtent
- Exceptions:
- LsmError
- ErrorNumber.LSM_PLUGIN_BUG # Failed to find out pri cim_ext
- """
- if property_list is None:
- property_list = ['Primordial']
- else:
- property_list = merge_list(property_list, ['Primordial'])
-
- cim_exts = self._c.Associators(
- cim_disk_path,
- AssocClass='CIM_MediaPresent',
- ResultClass='CIM_StorageExtent',
- PropertyList=property_list)
- cim_exts = [p for p in cim_exts if p["Primordial"]]
- if cim_exts and cim_exts[0]:
- # As SNIA commanded, only _ONE_ Primordial CIM_StorageExtent for
- # each CIM_DiskDrive
- return cim_exts[0]
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Failed to find out Primordial " +
- "CIM_StorageExtent for CIM_DiskDrive %s " %
- cim_disk_path)
-
- def _cim_disk_of_pri_ext(self, cim_pri_ext_path, pros_list=None):
- """
- Follow this procedure to find out CIM_DiskDrive from Primordial
- CIM_StorageExtent:
- CIM_StorageExtent (Primordial)
- ^
- |
- | CIM_MediaPresent
- |
- v
- CIM_DiskDrive
- """
- if pros_list is None:
- pros_list = []
- cim_disks = self._c.Associators(
- cim_pri_ext_path,
- AssocClass='CIM_MediaPresent',
- ResultClass='CIM_DiskDrive',
- PropertyList=pros_list)
- if len(cim_disks) == 1:
- return cim_disks[0]
- elif len(cim_disks) == 2:
- return None
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Found two or more CIM_DiskDrive associated to " +
- "requested CIM_StorageExtent %s" %
- cim_pri_ext_path)
-
- @staticmethod
def _is_frontend_fc_tgt(cim_fc_tgt):
"""
Check CIM_FCPort['UsageRestriction'] for frontend port.
diff --git a/plugin/smispy/smis_disk.py b/plugin/smispy/smis_disk.py
new file mode 100644
index 0000000..01de3db
--- /dev/null
+++ b/plugin/smispy/smis_disk.py
@@ -0,0 +1,197 @@
+## 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
+# 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>
+
+from lsm import Disk, md5, LsmError, ErrorNumber
+from dmtf import (
+ DMTF, DMTF_DISK_TYPE_UNKNOWN, DMTF_DISK_TYPE_OTHER,
+ DMTF_DISK_TYPE_HDD, DMTF_DISK_TYPE_SSD, DMTF_DISK_TYPE_HYBRID)
+from utils import merge_list
+
+
+_LSM_DISK_OP_STATUS_CONV = {
+ DMTF.OP_STATUS_UNKNOWN: Disk.STATUS_UNKNOWN,
+ DMTF.OP_STATUS_OK: Disk.STATUS_OK,
+ DMTF.OP_STATUS_PREDICTIVE_FAILURE: Disk.STATUS_PREDICTIVE_FAILURE,
+ DMTF.OP_STATUS_ERROR: Disk.STATUS_ERROR,
+ DMTF.OP_STATUS_NON_RECOVERABLE_ERROR: Disk.STATUS_ERROR,
+ DMTF.OP_STATUS_STARTING: Disk.STATUS_STARTING,
+ DMTF.OP_STATUS_STOPPING: Disk.STATUS_STOPPING,
+ DMTF.OP_STATUS_STOPPED: Disk.STATUS_STOPPED,
+}
+
+
+def _disk_status_of_cim_disk(cim_disk):
+ """
+ Convert CIM_DiskDrive['OperationalStatus'] to LSM
+ Only return status, no status_info
+ """
+ if 'OperationalStatus' not in cim_disk:
+ return Disk.STATUS_UNKNOWN
+
+ return DMTF.dmtf_op_status_list_conv(
+ _LSM_DISK_OP_STATUS_CONV, cim_disk['OperationalStatus'],
+ Disk.STATUS_UNKNOWN, Disk.STATUS_OTHER)[0]
+
+
+_DMTF_DISK_TYPE_2_LSM = {
+ DMTF_DISK_TYPE_UNKNOWN: Disk.TYPE_UNKNOWN,
+ DMTF_DISK_TYPE_OTHER: Disk.TYPE_OTHER,
+ DMTF_DISK_TYPE_HDD: Disk.TYPE_HDD,
+ DMTF_DISK_TYPE_SSD: Disk.TYPE_SSD,
+ DMTF_DISK_TYPE_HYBRID: Disk.TYPE_HYBRID,
+}
+
+
+def _dmtf_disk_type_2_lsm_disk_type(dmtf_disk_type):
+ if dmtf_disk_type in _DMTF_DISK_TYPE_2_LSM.keys():
+ return _DMTF_DISK_TYPE_2_LSM[dmtf_disk_type]
+ else:
+ return Disk.TYPE_UNKNOWN
+
+
+def _disk_id_of_cim_disk(cim_disk):
+ if 'SystemName' not in cim_disk or \
+ 'DeviceID' not in cim_disk:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "_disk_id_of_cim_disk(): Got cim_disk with no "
+ "SystemName or DeviceID property: %s, %s" %
+ (cim_disk.path, cim_disk.items()))
+
+ return md5("%s%s" % (cim_disk['SystemName'], cim_disk['DeviceID']))
+
+
+def cim_disk_pros():
+ """
+ Return all CIM_DiskDrive Properties needed to create a Disk object.
+ """
+ return ['OperationalStatus', 'Name', 'SystemName',
+ 'Caption', 'InterconnectType', 'DiskType', 'DeviceID']
+
+
+def sys_id_of_cim_disk(cim_disk):
+ if 'SystemName' not in cim_disk:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_id_of_cim_disk(): Got cim_disk with no "
+ "SystemName property: %s, %s" %
+ (cim_disk.path, cim_disk.items()))
+ return cim_disk['SystemName']
+
+
+def _pri_cim_ext_of_cim_disk(smis_common, cim_disk_path, property_list=None):
+ """
+ Usage:
+ Find out the Primordial CIM_StorageExtent of CIM_DiskDrive
+ In SNIA SMI-S 1.4 rev.6 Block book, section 11.1.1 'Base Model'
+ quote:
+ A disk drive is modeled as a single MediaAccessDevice (DiskDrive)
+ That shall be linked to a single StorageExtent (representing the
+ storage in the drive) by a MediaPresent association. The
+ StorageExtent class represents the storage of the drive and
+ contains its size.
+ Parameter:
+ cim_disk_path # CIM_InstanceName of CIM_DiskDrive
+ property_list # a List of properties needed on returned
+ # CIM_StorageExtent
+ Returns:
+ cim_pri_ext # The CIM_Instance of Primordial CIM_StorageExtent
+ Exceptions:
+ LsmError
+ ErrorNumber.LSM_PLUGIN_BUG # Failed to find out pri cim_ext
+ """
+ if property_list is None:
+ property_list = ['Primordial']
+ else:
+ property_list = merge_list(property_list, ['Primordial'])
+
+ cim_exts = smis_common.Associators(
+ cim_disk_path,
+ AssocClass='CIM_MediaPresent',
+ ResultClass='CIM_StorageExtent',
+ PropertyList=property_list)
+ cim_exts = [p for p in cim_exts if p["Primordial"]]
+ if len(cim_exts) == 1:
+ # As SNIA commanded, only _ONE_ Primordial CIM_StorageExtent for
+ # each CIM_DiskDrive
+ return cim_exts[0]
+ else:
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "_pri_cim_ext_of_cim_disk(): "
+ "Got unexpected count of Primordial " +
+ "CIM_StorageExtent for CIM_DiskDrive: %s, %s " %
+ (cim_disk_path, cim_exts))
+
+
+def cim_disk_to_lsm_disk(smis_common, cim_disk):
+ """
+ Convert CIM_DiskDrive to lsm.Disk.
+ """
+ # CIM_DiskDrive does not have disk size information.
+ # We have to find out the Primodial CIM_StorageExtent for that.
+ cim_ext = _pri_cim_ext_of_cim_disk(
+ smis_common, cim_disk.path,
+ property_list=['BlockSize', 'NumberOfBlocks'])
+
+ status = _disk_status_of_cim_disk(cim_disk)
+ name = ''
+ block_size = Disk.BLOCK_SIZE_NOT_FOUND
+ num_of_block = Disk.BLOCK_COUNT_NOT_FOUND
+ disk_type = Disk.TYPE_UNKNOWN
+ sys_id = sys_id_of_cim_disk(cim_disk)
+
+ # These are mandatory
+ # we do not check whether they follow the SNIA standard.
+ if 'Name' in cim_disk:
+ name = cim_disk["Name"]
+ if 'BlockSize' in cim_ext:
+ block_size = cim_ext['BlockSize']
+ if 'NumberOfBlocks' in cim_ext:
+ num_of_block = cim_ext['NumberOfBlocks']
+
+ # SNIA SMI-S 1.4 or even 1.6 does not define anyway to find out disk
+ # type.
+ # Currently, EMC is following DMTF define to do so.
+ if 'InterconnectType' in cim_disk: # DMTF 2.31 CIM_DiskDrive
+ disk_type = cim_disk['InterconnectType']
+ if 'Caption' in cim_disk:
+ # EMC VNX introduced NL_SAS disk.
+ if cim_disk['Caption'] == 'NL_SAS':
+ disk_type = Disk.TYPE_NL_SAS
+
+ if disk_type == Disk.TYPE_UNKNOWN and 'DiskType' in cim_disk:
+ disk_type = _dmtf_disk_type_2_lsm_disk_type(cim_disk['DiskType'])
+
+ # LSI way for checking disk type
+ if not disk_type and cim_disk.classname == 'LSIESG_DiskDrive':
+ cim_pes = smis_common.Associators(
+ cim_disk.path,
+ AssocClass='CIM_SAPAvailableForElement',
+ ResultClass='CIM_ProtocolEndpoint',
+ PropertyList=['CreationClassName'])
+ if cim_pes and cim_pes[0]:
+ if 'CreationClassName' in cim_pes[0]:
+ ccn = cim_pes[0]['CreationClassName']
+ if ccn == 'LSIESG_TargetSATAProtocolEndpoint':
+ disk_type = Disk.TYPE_SATA
+ if ccn == 'LSIESG_TargetSASProtocolEndpoint':
+ disk_type = Disk.TYPE_SAS
+
+ disk_id = _disk_id_of_cim_disk(cim_disk)
+
+ return Disk(disk_id, name, disk_type, block_size, num_of_block, status,
+ sys_id)
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:35 UTC
Permalink
There is a possiblity of an older exiting simulator plugin writing
its state out while a new client is reading state from the file.
Ensure this cannot happen with a lock on the state file to ensure
that only one plugin can be mucking with the state file at one time.

This is only a theory as I'm unable to reproduce a failure I was
seeing while building packages, but it would be good to prevent
concurrent access to the state file regardless.

The file is opened and locked and kept open until the plugin is
closed.

Signed-off-by: Tony Asleson <***@redhat.com>
---
plugin/sim/simarray.py | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index 6e039c5..d733e50 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -24,6 +24,7 @@ import pickle
import tempfile
import os
import time
+import fcntl

from lsm import (size_human_2_size_bytes, size_bytes_2_size_human)
from lsm import (System, Volume, Disk, Pool, FileSystem, AccessGroup,
@@ -162,10 +163,15 @@ class SimArray(object):
else:
self.dump_file = dump_file

- if os.path.exists(self.dump_file):
+ self.state_fd = os.open(self.dump_file, os.O_RDWR | os.O_CREAT)
+ fcntl.lockf(self.state_fd, fcntl.LOCK_EX)
+ self.state_fo = os.fdopen(self.state_fd, "r+b")
+
+ current = self.state_fo.read()
+
+ if current:
try:
- with open(self.dump_file, 'rb') as f:
- self.data = pickle.load(f)
+ self.data = pickle.loads(current)

# Going forward we could get smarter about handling this for
# changes that aren't invasive, but we at least need to check
@@ -176,14 +182,16 @@ class SimArray(object):
SimArray._version_error(self.dump_file)
except AttributeError:
SimArray._version_error(self.dump_file)
-
else:
self.data = SimData()

def save_state(self):
- fh_dump_file = open(self.dump_file, 'wb')
- pickle.dump(self.data, fh_dump_file)
- fh_dump_file.close()
+ # Make sure we are at the beginning of the stream
+ self.state_fo.seek(0)
+ pickle.dump(self.data, self.state_fo)
+ self.state_fo.flush()
+ self.state_fo.close()
+ self.state_fo = None

def job_status(self, job_id, flags=0):
return self.data.job_status(job_id, flags=0)
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:37 UTC
Permalink
Signed-off-by: Tony Asleson <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 14fa4be..ec86887 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -148,7 +148,6 @@ the %{name}-rest package contains the http daemon for %{name} rest api.
%build
./autogen.sh

-#Tell the install program to preserve file date/timestamps
%configure \
%if 0%{?with_rest_api} != 1
--without-rest-api \
@@ -168,9 +167,9 @@ install -m644 packaging/daemon/libstoragemgmt.service \
%{buildroot}/%{_unitdir}/libstoragemgmt.service

#tempfiles.d configuration for /var/run
-mkdir -p %{buildroot}%{_sysconfdir}/tmpfiles.d
+mkdir -p %{buildroot}/%{_tmpfilesdir}
install -m 0644 packaging/daemon/lsm-tmpfiles.conf \
- %{buildroot}%{_sysconfdir}/tmpfiles.d/%{name}.conf
+ %{buildroot}/%{_tmpfilesdir}/%{name}.conf
%else
#Need these to exist at install so we can start the daemon
mkdir -p %{buildroot}/etc/rc.d/init.d
@@ -280,7 +279,7 @@ fi
%dir %attr(0755, libstoragemgmt, libstoragemgmt) %{_localstatedir}/run/lsm/ipc

%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7
-%attr(0644, root, root) %{_sysconfdir}/tmpfiles.d/%{name}.conf
+%attr(0644, root, root) %{_tmpfilesdir}/%{name}.conf
%else
%attr(0755, root, root) /etc/rc.d/init.d/libstoragemgmtd
%endif
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:38 UTC
Permalink
We cannot have files that have a py extension in packages that are
not in noarch rpm. This is to prevent a user from installing both
32bit and 64bit packages on the same system from having signature
conflicts for the compiled python files (pyc).

Signed-off-by: Tony Asleson <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index ec86887..4dd5b88 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -267,9 +267,6 @@ fi
%{_bindir}/lsmcli
%{_bindir}/lsmd
%{_bindir}/simc_lsmplugin
-%{python_sitelib}/lsm/lsmcli/__init__.*
-%{python_sitelib}/lsm/lsmcli/data_display.*
-%{python_sitelib}/lsm/lsmcli/cmdline.*

%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7
%{_unitdir}/*
@@ -306,6 +303,9 @@ fi
%{python_sitelib}/lsm/plugin/sim/__init__.*
%{python_sitelib}/lsm/plugin/sim/simulator.*
%{python_sitelib}/lsm/plugin/sim/simarray.*
+%{python_sitelib}/lsm/lsmcli/__init__.*
+%{python_sitelib}/lsm/lsmcli/data_display.*
+%{python_sitelib}/lsm/lsmcli/cmdline.*
%{_bindir}/sim_lsmplugin

%files smis-plugin
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:36 UTC
Permalink
Not likely to happen in normal operation.

Signed-off-by: Tony Asleson <***@redhat.com>
---
daemon/lsm_daemon.c | 6 +++++-
plugin/simc/simc_lsmplugin.c | 3 +++
2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/daemon/lsm_daemon.c b/daemon/lsm_daemon.c
index 80e0064..ef958f1 100644
--- a/daemon/lsm_daemon.c
+++ b/daemon/lsm_daemon.c
@@ -367,7 +367,7 @@ int setup_socket(char *full_name)

} else {
err = errno;
- loud("Error on unlinking file %s: %s\n",
+ loud("Error on socket create %s: %s\n",
socket_file, strerror(err));
}

@@ -425,6 +425,10 @@ int process_plugin(void *p, char *full_name)
LIST_INSERT_HEAD((struct plugin_list*)p, item, pointers);
info("Plugin %s added\n", full_name);
} else {
+ /* The only real way to get here is failed strdup as
+ setup_socket will exit on error. */
+ free(item);
+ item = NULL;
loud("strdup failed %s\n", full_name);
}
} else {
diff --git a/plugin/simc/simc_lsmplugin.c b/plugin/simc/simc_lsmplugin.c
index 5ef2afd..8e08be6 100644
--- a/plugin/simc/simc_lsmplugin.c
+++ b/plugin/simc/simc_lsmplugin.c
@@ -2184,6 +2184,9 @@ int load( lsm_plugin_ptr c, const char *uri, const char *password,
lsm_disk_record_free(d);
d = NULL;

+ free(key);
+ key = NULL;
+
break;
}
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:34 UTC
Permalink
From: Gris Ge <***@redhat.com>

* If certain plugin didn't raise LsmError on NAME_CONFLICT for
volume_create(), plugin_test.py will incorrectly treat it as PASS.
This patch fixed it by using a error_num variable to checking
NAME_CONFLICT.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/plugin_test.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/test/plugin_test.py b/test/plugin_test.py
index 77f4b29..1464a55 100755
--- a/test/plugin_test.py
+++ b/test/plugin_test.py
@@ -486,14 +486,17 @@ class TestPlugin(unittest.TestCase):
if volume_clone is not None:
# Lets test for creating a clone with an
# existing name
+ error_num = None
try:
volume_clone_dupe_name = \
self.c.volume_replicate(
None, replication_type, vol,
volume_clone.name)[1]
except LsmError as le:
- self.assertTrue(le.code ==
- ErrorNumber.NAME_CONFLICT)
+ error_num = le.code
+
+ self.assertTrue(error_num ==
+ ErrorNumber.NAME_CONFLICT)

self._volume_delete(volume_clone)
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:31 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Move smis_constants.JS_XXX to dmtf.py:
smis_constants.JS_NEW -> dmtf.JOB_STATE_NEW
smis_constants.JS_STARTING -> dmtf.JOB_STATE_STARTING
smis_constants.JS_RUNNING -> dmtf.JOB_STATE_RUNNING
smis_constants.JS_COMPLETED -> dmtf.JOB_STATE_COMPLETED
* Removed unused smis_constants.JS_XXX constatns:
smis_constants.JS_SUSPENDED
smis_constants.JS_SHUTTING_DOWN
smis_constants.JS_TERMINATED
smis_constants.JS_KILLED
smis_constants.JS_EXCEPTION
* Replace these constants:
smis_constants.JOB_OK => dmtf.OP_STATUS_OK
smis_constants.JOB_COMPLETE => dmtf.OP_STATUS_COMPLETED
* Removed Unused constants:
smis_constants.JOB_ERROR
smis_constants.JOB_STOPPED
* Move these InvokeMethod() return code to SmisCommon:
smis_constants.INVOKE_OK => SmisCommon.SNIA_INVOKE_OK
smis_constants.INVOKE_ASYNC => SmisCommon.SNIA_INVOKE_ASYNC
smis_constants.INVOKE_NOT_SUPPORTED =>
SmisCommon.SNIA_INVOKE_NOT_SUPPORTED
smis_constants.INVOKE_FAILED => SmisCommon.SNIA_INVOKE_FAILED
* Removed these InvokeMethod() return code as unused:
smis_constants.INVOKE_TIMEOUT
smis_constants.INVOKE_FAILED
smis_constants.INVOKE_INVALID_PARAMETER
smis_constants.INVOKE_IN_USE
smis_constants.INVOKE_SIZE_NOT_SUPPORTED
* Replaced these constants used by CreateElementReplica():
smis_constants.SYNC_TYPE_MIRROR
-> dmtf.SYNC_TYPE_MIRROR
smis_constants.SYNC_TYPE_SNAPSHOT
-> dmtf.SYNC_TYPE_SNAPSHOT
smis_constants.SYNC_TYPE_CLONE
-> dmtf.SYNC_TYPE_CLONE
smis_constants.CREATE_ELEMENT_REPLICA_MODE_SYNC
-> dmtf.REPLICA_MODE_SYNC
smis_constants.CREATE_ELEMENT_REPLICA_MODE_ASYNC
-> dmtf.REPLICA_MODE_ASYNC
* Move these constants into dmtf.
VOL_NAME_FORMAT_OTHER
VOL_NAME_FORMAT_NNA
VOL_NAME_FORMAT_EUI64
VOL_NAME_FORMAT_T10VID

VOL_NAME_SPACE_OTHER
VOL_NAME_SPACE_VPD83_TYPE3
VOL_NAME_SPACE_VPD83_TYPE2
VOL_NAME_SPACE_VPD83_TYPE1
* Removed these unused constants:
VOL_NAME_FORMAT_VPD83_NNA6
VOL_NAME_FORMAT_VPD83_NNA5
VOL_NAME_FORMAT_VPD83_TYPE2
VOL_NAME_FORMAT_VPD83_TYPE1
VOL_NAME_FORMAT_VPD83_TYPE0
VOL_NAME_FORMAT_SNVM
VOL_NAME_FORMAT_NODE_WWN

VOL_NAME_SPACE_OTHER
VOL_NAME_SPACE_VPD80
VOL_NAME_SPACE_NODE_WWN
VOL_NAME_SPACE_SNVM
* Move these constants to SmisCommon:
smis_constants.JOB_RETRIEVE_NONE => SmisCommon.JOB_RETRIEVE_NONE
smis_constants.JOB_RETRIEVE_VOLUME => SmisCommon.JOB_RETRIEVE_VOLUME
# These two constants is just for plugin internal use, not a SNIA or DMTF
# constant.
* Move these constants into SmisCommon:
smis_constants.IAAN_WBEM_HTTP_PORT => SmisCommon.IAAN_WBEM_HTTP_PORT
smis_constants.IAAN_WBEM_HTTPS_PORT => SmisCommon.IAAN_WBEM_HTTPS_PORT
# These two constant is defined by IETF IAAN. Store in SmisCommon class
# which was supposed to hold non-dmtf constants.
* Previously:
incorrect use
CIM_ReplicationServiceCapabilities['SupportedReplicationTypes'] --
2(Synchronous Mirror Local) for Capabilities.VOLUME_REPLICATE
capability.
Now:
Use CIM_ReplicationServiceCapabilities['SupportedSynchronousActions'] and
['SupportedAsynchronousActions'] -- 2(CreateElementReplica) for
Capabilities.VOLUME_REPLICATE capability.
* Remove smis_constants.RepSvc.Action class.
* Add dmtf.REPLICA_CAP_ACTION_CREATE_ELEMENT for 2(CreateElementReplica)
in CIM_ReplicationServiceCapabilities['SupportedSynchronousActions'] and
['SupportedAsynchronousActions'].
* Replace smis_constants.RepSvc with these constants in dmtf.py:
RepSvc.RepTypes.SYNC_SNAPSHOT_LOCAL
-> dmtf.REPLICA_CAP_TYPE_SYNC_SNAPSHOT_LOCAL
RepSvc.RepTypes.ASYNC_SNAPSHOT_LOCAL
-> dmtf.REPLICA_CAP_TYPE_ASYNC_SNAPSHOT_LOCAL
RepSvc.RepTypes.SYNC_CLONE_LOCAL
-> dmtf.REPLICA_CAP_TYPE_SYNC_CLONE_LOCAL
RepSvc.RepTypes.ASYNC_CLONE_LOCAL
-> dmtf.REPLICA_CAP_TYPE_ASYNC_CLONE_LOCAL
RepSvc.RepTypes.SYNC_MIRROR_LOCAL
-> dmtf.REPLICA_CAP_TYPE_SYNC_MIRROR_LOCAL
RepSvc.RepTypes.ASYNC_MIRROR_LOCAL
-> dmtf.REPLICA_CAP_TYPE_ASYNC_MIRROR_LOCAL
* Removed these unused constants:
RepSvc.RepTypes.SYNC_MIRROR_REMOTE
RepSvc.RepTypes.ASYNC_MIRROR_REMOTE
RepSvc.RepTypes.SYNC_CLONE_REMOTE
RepSvc.RepTypes.ASYNC_CLONE_REMOTE
* Replace smis_constants.CopyStates with dmtf.py constants:
smis_constants.CopyStates.SYNCHRONIZED
-> dmtf.COPY_STATE_SYNC
* Removed smis_constants.CopyStates unused constants:
smis_constants.CopyStates.INITIALIZED
smis_constants.CopyStates.UNSYNCHRONIZED
smis_constants.CopyStates.INACTIVE
* Remove smis_constants.CopyStates class.
* Replaced smis_constants.CopyTypes by dmtf constants:
smis_constants.CopyTypes.ASYNC
-> dmtf.ST_CONF_CAP_COPY_TYPE_ASYNC
smis_constants.CopyTypes.SYNC
-> dmtf.ST_CONF_CAP_COPY_TYPE_SYNC
smis_constants.CopyTypes.UNSYNCASSOC
-> dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_ASSOC
smis_constants.CopyTypes.UNSYNCUNASSOC
-> dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_UNASSOC
* Removed smis_constants.CopyTypes as all its constants moved out.
* Replaced this constants by dmtf one:
smis_constants.Synchronized.SyncState.SYNCHRONIZED
-> dmtf.ST_SYNC_STATE_SYNCHRONIZED
* Removed unused constants in smis_constants.py:
smis_constants.Synchronized.SyncState.INITIALIZED
smis_constants.Synchronized.SyncState.PREPAREINPROGRESS
smis_constants.Synchronized.SyncState.PREPARED
smis_constants.Synchronized.SyncState.RESYNCINPROGRESS
smis_constants.Synchronized.SyncState.FRACTURE_IN_PROGRESS
smis_constants.Synchronized.SyncState.QUIESCEINPROGRESS
smis_constants.Synchronized.SyncState.QUIESCED
smis_constants.Synchronized.SyncState.RESTORE_IN_PROGRESSS
smis_constants.Synchronized.SyncState.IDLE
smis_constants.Synchronized.SyncState.BROKEN
smis_constants.Synchronized.SyncState.FRACTURED
smis_constants.Synchronized.SyncState.FROZEN
smis_constants.Synchronized.SyncState.COPY_IN_PROGRESS
* Remove smis_constants.Synchronized class as all its constants moved out.
* Removed these unused constants of smis_constants.py:
CREATE_ELEMENT_REPLICA_MODE_SYNC
CREATE_ELEMENT_REPLICA_MODE_ASYNC
VOL_OP_STATUS_OK
VOL_OP_STATUS_DEGRADED
VOL_OP_STATUS_ERR
VOL_OP_STATUS_STARTING
VOL_OP_STATUS_DORMANT
EXPOSE_PATHS_DA_READ_ONLY
* Replace smis_constants.EXPOSE_PATHS_DA_READ_WRITE with
dmtf.CTRL_CONF_SRV_DA_RW
* Remove empty smis_constants.py file.
* Makefile and rpm SPEC file updated

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 -
plugin/Makefile.am | 1 -
plugin/smispy/dmtf.py | 60 ++++++++++++++++
plugin/smispy/smis.py | 150 ++++++++++++++++++++-------------------
plugin/smispy/smis_cap.py | 38 ++++------
plugin/smispy/smis_common.py | 17 +++++
plugin/smispy/smis_constants.py | 131 ----------------------------------
7 files changed, 166 insertions(+), 232 deletions(-)
delete mode 100644 plugin/smispy/smis_constants.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 32125ee..14fa4be 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -315,7 +315,6 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis.*
%{python_sitelib}/lsm/plugin/smispy/dmtf.*
%{python_sitelib}/lsm/plugin/smispy/utils.*
-%{python_sitelib}/lsm/plugin/smispy/smis_constants.*
%{python_sitelib}/lsm/plugin/smispy/smis_common.*
%{python_sitelib}/lsm/plugin/smispy/smis_cap.*
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index df8907d..c3084c9 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -26,7 +26,6 @@ smispy_PYTHON = \
smispy/__init__.py \
smispy/smis.py \
smispy/utils.py \
- smispy/smis_constants.py \
smispy/smis_common.py \
smispy/dmtf.py \
smispy/smis_cap.py \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 18a8a8f..5e30bac 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -155,6 +155,7 @@ _OP_STATUS_STR_CONV = {
OP_STATUS_POWER_MODE: "POWER_MODE",
}

+
def _op_status_to_str(dmtf_op_status):
"""
Just convert integer to string. NOT ALLOWING provide a list.
@@ -165,6 +166,7 @@ def _op_status_to_str(dmtf_op_status):
except KeyError:
return ''

+
def op_status_list_conv(conv_dict, dmtf_op_status_list,
unknown_value, other_value):
status = 0
@@ -180,3 +182,61 @@ def op_status_list_conv(conv_dict, dmtf_op_status_list,
if status == 0:
status = unknown_value
return status, " ".join(status_info_list)
+
+# CIM_ConcreteJob['JobState']
+JOB_STATE_NEW = 2
+JOB_STATE_STARTING = 3
+JOB_STATE_RUNNING = 4
+JOB_STATE_COMPLETED = 7
+
+# CIM_Synchronized['SyncType'] also used by
+# CIM_ReplicationService.CreateElementReplica() 'SyncType' parameter.
+SYNC_TYPE_MIRROR = Uint16(6)
+SYNC_TYPE_SNAPSHOT = Uint16(7)
+SYNC_TYPE_CLONE = Uint16(8)
+
+# CIM_Synchronized['Mode'] also used by
+# CIM_ReplicationService.CreateElementReplica() 'Mode' parameter.
+REPLICA_MODE_SYNC = Uint16(2)
+REPLICA_MODE_ASYNC = Uint16(3)
+
+# CIM_StorageVolume['NameFormat']
+VOL_NAME_FORMAT_OTHER = 1
+VOL_NAME_FORMAT_NNA = 9
+VOL_NAME_FORMAT_EUI64 = 10
+VOL_NAME_FORMAT_T10VID = 11
+
+# CIM_StorageVolume['NameNamespace']
+VOL_NAME_SPACE_OTHER = 1
+VOL_NAME_SPACE_VPD83_TYPE3 = 2
+VOL_NAME_SPACE_VPD83_TYPE2 = 3
+VOL_NAME_SPACE_VPD83_TYPE1 = 4
+
+# CIM_ReplicationServiceCapabilities['SupportedAsynchronousActions']
+# or CIM_ReplicationServiceCapabilities['SupportedSynchronousActions']
+REPLICA_CAP_ACTION_CREATE_ELEMENT = 2
+
+# CIM_ReplicationServiceCapabilities['SupportedReplicationTypes']
+REPLICA_CAP_TYPE_SYNC_MIRROR_LOCAL = 2
+REPLICA_CAP_TYPE_ASYNC_MIRROR_LOCAL = 3
+
+REPLICA_CAP_TYPE_SYNC_SNAPSHOT_LOCAL = 6
+REPLICA_CAP_TYPE_ASYNC_SNAPSHOT_LOCAL = 7
+
+REPLICA_CAP_TYPE_SYNC_CLONE_LOCAL = 10
+REPLICA_CAP_TYPE_ASYNC_CLONE_LOCAL = 11
+
+# CIM_Synchronized['CopyState']
+COPY_STATE_SYNC = Uint16(4)
+
+# CIM_StorageConfigurationCapabilities['SupportedCopyTypes']
+ST_CONF_CAP_COPY_TYPE_ASYNC = Uint16(2)
+ST_CONF_CAP_COPY_TYPE_SYNC = Uint16(3)
+ST_CONF_CAP_COPY_TYPE_UNSYNC_ASSOC = Uint16(4)
+ST_CONF_CAP_COPY_TYPE_UNSYNC_UNASSOC = Uint16(5)
+
+# CIM_StorageSynchronized['SyncState']
+ST_SYNC_STATE_SYNCHRONIZED = 6
+
+# CIM_ControllerConfigurationService.ExposePaths(DeviceAccesses)
+CTRL_CONF_SRV_DA_RW = Uint16(2)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 2cee221..4b78a74 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -28,7 +28,6 @@ import re

import pywbem
from pywbem import CIMError
-from smis_constants import *
import smis_cap
import smis_sys
import smis_pool
@@ -180,17 +179,17 @@ class Smis(IStorageAreaNetwork):
Handle the the process of invoking an operation.
"""
# Check to see if operation is done
- if rc == INVOKE_OK:
- if retrieve_data == JOB_RETRIEVE_VOLUME:
+ if rc == SmisCommon.SNIA_INVOKE_OK:
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME:
return None, self._new_vol_from_name(out)
else:
return None, None

- elif rc == INVOKE_ASYNC:
+ elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
# We have an async operation
job_id = self._job_id(out['Job'], retrieve_data)
return job_id, None
- elif rc == INVOKE_NOT_SUPPORTED:
+ elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
raise LsmError(
ErrorNumber.NO_SUPPORT,
'SMI-S error code indicates operation not supported')
@@ -233,12 +232,12 @@ class Smis(IStorageAreaNetwork):
Enumerate CIM_RegisteredProfile in userdefined namespace.
"""
protocol = 'http'
- port = IAAN_WBEM_HTTP_PORT
+ port = SmisCommon.IAAN_WBEM_HTTP_PORT
u = uri_parse(uri, ['scheme', 'netloc', 'host'], None)

if u['scheme'].lower() == 'smispy+ssl':
protocol = 'https'
- port = IAAN_WBEM_HTTPS_PORT
+ port = SmisCommon.IAAN_WBEM_HTTPS_PORT

if 'port' in u:
port = u['port']
@@ -303,8 +302,10 @@ class Smis(IStorageAreaNetwork):
op = status['OperationalStatus']

if (len(op) > 1 and
- ((op[0] == JOB_OK and op[1] == JOB_COMPLETE) or
- (op[0] == JOB_COMPLETE and op[1] == JOB_OK))):
+ ((op[0] == dmtf.OP_STATUS_OK and
+ op[1] == dmtf.OP_STATUS_COMPLETED) or
+ (op[0] == dmtf.OP_STATUS_COMPLETED and
+ op[1] == dmtf.OP_STATUS_OK))):
rc = True

return rc
@@ -325,7 +326,8 @@ class Smis(IStorageAreaNetwork):

job_state = cim_job['JobState']

- if job_state in (JS_NEW, JS_STARTING, JS_RUNNING):
+ if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
+ dmtf.JOB_STATE_RUNNING):
status = JobStatus.INPROGRESS

pc = cim_job['PercentComplete']
@@ -334,13 +336,13 @@ class Smis(IStorageAreaNetwork):
else:
percent_complete = pc

- elif job_state == JS_COMPLETED:
+ elif job_state == dmtf.JOB_STATE_COMPLETED:
status = JobStatus.COMPLETE
percent_complete = 100

if Smis._job_completed_ok(cim_job):
(ignore, retrieve_data) = self._parse_job_id(job_id)
- if retrieve_data == JOB_RETRIEVE_VOLUME:
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME:
completed_item = self._new_vol_from_job(cim_job)
else:
status = JobStatus.ERROR
@@ -428,7 +430,8 @@ class Smis(IStorageAreaNetwork):
"""
Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
with '@%s' % retrieve_data
- retrieve_data should be JOB_RETRIEVE_NONE or JOB_RETRIEVE_VOLUME or etc
+ retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
+ SmisCommon.JOB_RETRIEVE_VOLUME or etc
"""
return "%s@%d" % (self._id('Job', cim_job), int(retrieve_data))

@@ -479,7 +482,7 @@ class Smis(IStorageAreaNetwork):
"""
tmp_list = job_id.split('@', 2)
md5_str = tmp_list[0]
- retrieve_data = JOB_RETRIEVE_NONE
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
if len(tmp_list) == 2:
retrieve_data = int(tmp_list[1])
return (md5_str, retrieve_data)
@@ -584,17 +587,17 @@ class Smis(IStorageAreaNetwork):
if not (nf and nn and name):
return None
# SNIA might have miss documented VPD83Type3(1), it should be
- # VOL_NAME_FORMAT_OTHER(1) based on dmtf.
- # Will remove the Smis.VOL_NAME_FORMAT_OTHER condition if confirmed as
+ # dmtf.VOL_NAME_FORMAT_OTHER(1) based on dmtf.
+ # Will remove the Smis.dmtf.VOL_NAME_FORMAT_OTHER condition if confirmed as
# SNIA document fault.
- if (nf == VOL_NAME_FORMAT_NNA and
- nn == VOL_NAME_FORMAT_OTHER) or \
- (nf == VOL_NAME_FORMAT_NNA and
- nn == VOL_NAME_SPACE_VPD83_TYPE3) or \
- (nf == VOL_NAME_FORMAT_EUI64 and
- nn == VOL_NAME_SPACE_VPD83_TYPE2) or \
- (nf == VOL_NAME_FORMAT_T10VID and
- nn == VOL_NAME_SPACE_VPD83_TYPE1):
+ if (nf == dmtf.VOL_NAME_FORMAT_NNA and
+ nn == dmtf.VOL_NAME_FORMAT_OTHER) or \
+ (nf == dmtf.VOL_NAME_FORMAT_NNA and
+ nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE3) or \
+ (nf == dmtf.VOL_NAME_FORMAT_EUI64 and
+ nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE2) or \
+ (nf == dmtf.VOL_NAME_FORMAT_T10VID and
+ nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE1):
return name

@staticmethod
@@ -869,7 +872,8 @@ class Smis(IStorageAreaNetwork):
'Size': pywbem.Uint64(size_bytes)}

try:
- return self._pi("volume_create", JOB_RETRIEVE_VOLUME,
+ return self._pi("volume_create",
+ SmisCommon.JOB_RETRIEVE_VOLUME,
*(self._c.InvokeMethod(
'CreateOrModifyElementFromStoragePool',
scs.path, **in_params)))
@@ -899,7 +903,8 @@ class Smis(IStorageAreaNetwork):
in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}

- job_id = self._pi("_detach", JOB_RETRIEVE_NONE,
+ job_id = self._pi("_detach",
+ SmisCommon.JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod(
'ModifySynchronization', scs.path,
**in_params)))[0]
@@ -917,7 +922,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}

- job_id = self._pi("_detach", JOB_RETRIEVE_NONE,
+ job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod(
'ModifyReplicaSynchronization', rs.path,
**in_params)))[0]
@@ -999,9 +1004,9 @@ class Smis(IStorageAreaNetwork):
# range of array vendors.

if 'SyncState' in s and 'CopyType' in s:
- if s['SyncState'] == \
- Synchronized.SyncState.SYNCHRONIZED and \
- (s['CopyType'] != CopyTypes.UNSYNCASSOC):
+ if s['SyncState'] == dmtf.ST_SYNC_STATE_SYNCHRONIZED and \
+ s['CopyType'] != \
+ dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_ASSOC:
if 'SyncedElement' in s:
item = s['SyncedElement']

@@ -1025,7 +1030,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'TheElement': lun.path}

#Delete returns None or Job number
- return self._pi("volume_delete", JOB_RETRIEVE_NONE,
+ return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod('ReturnToStoragePool',
scs.path, **in_params)))[0]

@@ -1052,7 +1057,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'TheElement': lun.path}

# Delete returns None or Job number
- return self._pi("volume_delete", JOB_RETRIEVE_NONE,
+ return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod('ReturnToStoragePool',
scs.path,
**in_params)))[0]
@@ -1070,7 +1075,7 @@ class Smis(IStorageAreaNetwork):
'TheElement': lun.path,
'Size': pywbem.Uint64(new_size_bytes)}

- return self._pi("volume_resize", JOB_RETRIEVE_VOLUME,
+ return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME,
*(self._c.InvokeMethod(
'CreateOrModifyElementFromStoragePool',
scs.path, **in_params)))
@@ -1095,30 +1100,30 @@ class Smis(IStorageAreaNetwork):
s_rt = rs_cap['SupportedReplicationTypes']

if rep_type == Volume.REPLICATE_COPY:
- if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt:
- rc[0] = SYNC_TYPE_CLONE
- rc[1] = CREATE_ELEMENT_REPLICA_MODE_SYNC
- elif RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
- rc[0] = SYNC_TYPE_CLONE
- rc[1] = CREATE_ELEMENT_REPLICA_MODE_ASYNC
+ if dmtf.REPLICA_CAP_TYPE_SYNC_CLONE_LOCAL in s_rt:
+ rc[0] = dmtf.SYNC_TYPE_CLONE
+ rc[1] = dmtf.REPLICA_MODE_SYNC
+ elif dmtf.REPLICA_CAP_TYPE_ASYNC_CLONE_LOCAL in s_rt:
+ rc[0] = dmtf.SYNC_TYPE_CLONE
+ rc[1] = dmtf.REPLICA_MODE_ASYNC

elif rep_type == Volume.REPLICATE_MIRROR_ASYNC:
- if RepSvc.RepTypes.ASYNC_MIRROR_LOCAL in s_rt:
- rc[0] = SYNC_TYPE_MIRROR
- rc[1] = CREATE_ELEMENT_REPLICA_MODE_ASYNC
+ if dmtf.REPLICA_CAP_TYPE_ASYNC_MIRROR_LOCAL in s_rt:
+ rc[0] = dmtf.SYNC_TYPE_MIRROR
+ rc[1] = dmtf.REPLICA_MODE_ASYNC

elif rep_type == Volume.REPLICATE_MIRROR_SYNC:
- if RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
- rc[0] = SYNC_TYPE_MIRROR
- rc[1] = CREATE_ELEMENT_REPLICA_MODE_SYNC
+ if dmtf.REPLICA_CAP_TYPE_SYNC_MIRROR_LOCAL in s_rt:
+ rc[0] = dmtf.SYNC_TYPE_MIRROR
+ rc[1] = dmtf.REPLICA_MODE_SYNC

elif rep_type == Volume.REPLICATE_CLONE:
- if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt:
- rc[0] = SYNC_TYPE_SNAPSHOT
- rc[1] = CREATE_ELEMENT_REPLICA_MODE_SYNC
- elif RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
- rc[0] = SYNC_TYPE_SNAPSHOT
- rc[1] = CREATE_ELEMENT_REPLICA_MODE_ASYNC
+ if dmtf.REPLICA_CAP_TYPE_SYNC_CLONE_LOCAL in s_rt:
+ rc[0] = dmtf.SYNC_TYPE_SNAPSHOT
+ rc[1] = dmtf.REPLICA_MODE_SYNC
+ elif dmtf.REPLICA_CAP_TYPE_ASYNC_CLONE_LOCAL in s_rt:
+ rc[0] = dmtf.SYNC_TYPE_SNAPSHOT
+ rc[1] = dmtf.REPLICA_MODE_ASYNC

if rc[0] is None:
raise LsmError(ErrorNumber.NO_SUPPORT,
@@ -1151,11 +1156,10 @@ class Smis(IStorageAreaNetwork):
volume_src.system_id, rep_type)

in_params = {'ElementName': name,
- 'SyncType': pywbem.Uint16(sync),
- #'Mode': pywbem.Uint16(mode),
+ 'SyncType': sync,
+ #'Mode': mode,
'SourceElement': lun.path,
- 'WaitForCopyState':
- pywbem.Uint16(CopyStates.SYNCHRONIZED)}
+ 'WaitForCopyState': dmtf.COPY_STATE_SYNC}

else:
# Check for older support via storage configuration service
@@ -1169,16 +1173,16 @@ class Smis(IStorageAreaNetwork):

ct = Volume.REPLICATE_CLONE
if rep_type == Volume.REPLICATE_CLONE:
- ct = CopyTypes.UNSYNCASSOC
+ ct = dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_ASSOC
elif rep_type == Volume.REPLICATE_COPY:
- ct = CopyTypes.UNSYNCUNASSOC
+ ct = dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_UNASSOC
elif rep_type == Volume.REPLICATE_MIRROR_ASYNC:
- ct = CopyTypes.ASYNC
+ ct = dmtf.ST_CONF_CAP_COPY_TYPE_ASYNC
elif rep_type == Volume.REPLICATE_MIRROR_SYNC:
- ct = CopyTypes.SYNC
+ ct = dmtf.ST_CONF_CAP_COPY_TYPE_SYNC

in_params = {'ElementName': name,
- 'CopyType': pywbem.Uint16(ct),
+ 'CopyType': ct,
'SourceElement': lun.path}
if rs:

@@ -1187,7 +1191,8 @@ class Smis(IStorageAreaNetwork):

try:

- return self._pi("volume_replicate", JOB_RETRIEVE_VOLUME,
+ return self._pi("volume_replicate",
+ SmisCommon.JOB_RETRIEVE_VOLUME,
*(self._c.InvokeMethod(method,
rs.path, **in_params)))
except CIMError:
@@ -1198,7 +1203,7 @@ class Smis(IStorageAreaNetwork):

def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
vol_id):
- rc = INVOKE_FAILED
+ rc = SmisCommon.SNIA_INVOKE_FAILED
out = None

in_params = {
@@ -1233,7 +1238,7 @@ class Smis(IStorageAreaNetwork):
we will mask to all target ports.
Return CIMInstanceName of CIM_TargetMaskingGroup
"""
- rc = INVOKE_FAILED
+ rc = SmisCommon.SNIA_INVOKE_FAILED
out = None

in_params = {
@@ -1410,11 +1415,9 @@ class Smis(IStorageAreaNetwork):
cim_vol = self._get_cim_instance_by_id(
'Volume', volume.id, ['Name'], raise_error=True)

- da = EXPOSE_PATHS_DA_READ_WRITE
-
in_params = {'LUNames': [cim_vol['Name']],
'ProtocolControllers': [cim_spc.path],
- 'DeviceAccesses': [pywbem.Uint16(da)]}
+ 'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}

(rc, out) = self._c.InvokeMethod(
'ExposePaths',
@@ -2506,13 +2509,14 @@ class Smis(IStorageAreaNetwork):
def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
flag_out_array=False,):
"""
- Return out[out_key] if found rc == INVOKE_OK.
- For rc == INVOKE_ASYNC, we check every Smis.INVOKE_CHECK_INTERVAL
+ Return out[out_key] if found rc == SmisCommon.SNIA_INVOKE_OK.
+ For rc == SmisCommon.SNIA_INVOKE_ASYNC, we check every
+ Smis._INVOKE_CHECK_INTERVAL
seconds until done. Then return association via CIM_AffectedJobElement
Return CIM_InstanceName
Assuming only one CIM_InstanceName will get.
"""
- if rc == INVOKE_OK:
+ if rc == SmisCommon.SNIA_INVOKE_OK:
if out_key is None:
return None
if out_key in out:
@@ -2527,7 +2531,7 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.PLUGIN_BUG,
"_wait_invoke(), %s not exist in out %s" %
(out_key, out.items()))
- elif rc == INVOKE_ASYNC:
+ elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
cim_job_path = out['Job']
loop_counter = 0
job_pros = ['JobState', 'PercentComplete', 'ErrorDescription',
@@ -2538,12 +2542,12 @@ class Smis(IStorageAreaNetwork):
PropertyList=job_pros,
LocalOnly=False)
job_state = cim_job['JobState']
- if job_state in (JS_NEW, JS_STARTING,
- JS_RUNNING):
+ if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
+ dmtf.JOB_STATE_RUNNING):
loop_counter += 1
time.sleep(Smis._INVOKE_CHECK_INTERVAL)
continue
- elif job_state == JS_COMPLETED:
+ elif job_state == dmtf.JOB_STATE_COMPLETED:
if expect_class is None:
return None
cim_xxxs_path = self._c.AssociatorNames(
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
index 0c9751d..1309056 100644
--- a/plugin/smispy/smis_cap.py
+++ b/plugin/smispy/smis_cap.py
@@ -15,7 +15,6 @@
# USA

from lsm import Capabilities, LsmError, ErrorNumber
-from smis_constants import *
import dmtf
from smis_common import SmisCommon

@@ -37,25 +36,21 @@ def _rs_supported_capabilities(smis_common, system, cap):
ResultClass='CIM_ReplicationServiceCapabilities')[0]

s_rt = rs_cap['SupportedReplicationTypes']
+ async_actions = rs_cap['SupportedAsynchronousActions']
+ sync_actions = rs_cap['SupportedSynchronousActions']

- if RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt or \
- RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt:
+ if dmtf.REPLICA_CAP_ACTION_CREATE_ELEMENT in async_actions or \
+ dmtf.REPLICA_CAP_ACTION_CREATE_ELEMENT in sync_actions :
cap.set(Capabilities.VOLUME_REPLICATE)
+ else:
+ return

- # Mirror support is not working and is not supported at this time.
- # if RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
- # cap.set(Capabilities.DeviceID)
-
- # if RepSvc.RepTypes.ASYNC_MIRROR_LOCAL \
- # in s_rt:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
-
- if RepSvc.RepTypes.SYNC_SNAPSHOT_LOCAL in s_rt or \
- RepSvc.RepTypes.ASYNC_SNAPSHOT_LOCAL in s_rt:
+ if dmtf.REPLICA_CAP_TYPE_SYNC_SNAPSHOT_LOCAL in s_rt or \
+ dmtf.REPLICA_CAP_TYPE_ASYNC_SNAPSHOT_LOCAL in s_rt:
cap.set(Capabilities.VOLUME_REPLICATE_CLONE)

- if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt or \
- RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
+ if dmtf.REPLICA_CAP_TYPE_SYNC_CLONE_LOCAL in s_rt or \
+ dmtf.REPLICA_CAP_TYPE_ASYNC_CLONE_LOCAL in s_rt:
cap.set(Capabilities.VOLUME_REPLICATE_COPY)
else:
# Try older storage configuration service
@@ -76,19 +71,10 @@ def _rs_supported_capabilities(smis_common, system, cap):
if sct and len(sct):
cap.set(Capabilities.VOLUME_REPLICATE)

- # Mirror support is not working and is not supported at
- # this time.
-
- # if CopyTypes.ASYNC in sct:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
-
- # if CopyTypes.SYNC in sct:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_SYNC)
-
- if CopyTypes.UNSYNCASSOC in sct:
+ if dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_ASSOC in sct:
cap.set(Capabilities.VOLUME_REPLICATE_CLONE)

- if CopyTypes.UNSYNCUNASSOC in sct:
+ if dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_UNASSOC in sct:
cap.set(Capabilities.VOLUME_REPLICATE_COPY)


diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index e497b29..decbb51 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -142,6 +142,17 @@ def _profile_spec_ver_to_num(spec_ver_str):


class SmisCommon(object):
+ # Even many CIM_XXX_Service in DMTF shared the same return value
+ # defination as SNIA do, but there is no DMTF standard metioned
+ # InvokeMethod() should follow that list of return value.
+ # We use SNIA defination here.
+ # SNIA 1.6 rev4 Block book, BSP 5.5.3.12 Return Values section.
+ SNIA_INVOKE_OK = 0
+ SNIA_INVOKE_NOT_SUPPORTED = 1
+ SNIA_INVOKE_FAILED = 4
+ SNIA_INVOKE_ASYNC = 4096
+
+
SNIA_BLK_ROOT_PROFILE = 'Array'
SNIA_BLK_SRVS_PROFILE = 'Block Services'
SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite'
@@ -159,6 +170,12 @@ class SmisCommon(object):
_PRODUCT_MEGARAID = 'LSI MegaRAID'
_PRODUCT_NETAPP_E = 'NetApp-E'

+ JOB_RETRIEVE_NONE = 0
+ JOB_RETRIEVE_VOLUME = 1
+
+ IAAN_WBEM_HTTP_PORT = 5988
+ IAAN_WBEM_HTTPS_PORT = 5989
+
def __init__(self, url, username, password,
namespace=dmtf.DEFAULT_NAMESPACE,
no_ssl_verify=False, debug=False, system_list=None):
diff --git a/plugin/smispy/smis_constants.py b/plugin/smispy/smis_constants.py
deleted file mode 100644
index 2df9144..0000000
--- a/plugin/smispy/smis_constants.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# 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
-# 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
-
- # SMI-S job 'JobState' enumerations
-(JS_NEW, JS_STARTING, JS_RUNNING, JS_SUSPENDED, JS_SHUTTING_DOWN,
- JS_COMPLETED,
- JS_TERMINATED, JS_KILLED, JS_EXCEPTION) = (2, 3, 4, 5, 6, 7, 8, 9, 10)
-
-# SMI-S job 'OperationalStatus' enumerations
-(JOB_OK, JOB_ERROR, JOB_STOPPED, JOB_COMPLETE) = (2, 6, 10, 17)
-
-# SMI-S invoke return values we are interested in
-# Reference: Page 54 in 1.5 SMI-S block specification
-(INVOKE_OK,
- INVOKE_NOT_SUPPORTED,
- INVOKE_TIMEOUT,
- INVOKE_FAILED,
- INVOKE_INVALID_PARAMETER,
- INVOKE_IN_USE,
- INVOKE_ASYNC,
- INVOKE_SIZE_NOT_SUPPORTED) = (0, 1, 3, 4, 5, 6, 4096, 4097)
-
-# SMI-S replication enumerations
-(SYNC_TYPE_MIRROR, SYNC_TYPE_SNAPSHOT, SYNC_TYPE_CLONE) = (6, 7, 8)
-
-# DMTF 2.29.1 (which SNIA SMI-S 1.6 based on)
-# CIM_StorageVolume['NameFormat']
-VOL_NAME_FORMAT_OTHER = 1
-VOL_NAME_FORMAT_VPD83_NNA6 = 2
-VOL_NAME_FORMAT_VPD83_NNA5 = 3
-VOL_NAME_FORMAT_VPD83_TYPE2 = 4
-VOL_NAME_FORMAT_VPD83_TYPE1 = 5
-VOL_NAME_FORMAT_VPD83_TYPE0 = 6
-VOL_NAME_FORMAT_SNVM = 7
-VOL_NAME_FORMAT_NODE_WWN = 8
-VOL_NAME_FORMAT_NNA = 9
-VOL_NAME_FORMAT_EUI64 = 10
-VOL_NAME_FORMAT_T10VID = 11
-
-# CIM_StorageVolume['NameNamespace']
-VOL_NAME_SPACE_OTHER = 1
-VOL_NAME_SPACE_VPD83_TYPE3 = 2
-VOL_NAME_SPACE_VPD83_TYPE2 = 3
-VOL_NAME_SPACE_VPD83_TYPE1 = 4
-VOL_NAME_SPACE_VPD80 = 5
-VOL_NAME_SPACE_NODE_WWN = 6
-VOL_NAME_SPACE_SNVM = 7
-
-JOB_RETRIEVE_NONE = 0
-JOB_RETRIEVE_VOLUME = 1
-
-IAAN_WBEM_HTTP_PORT = 5988
-IAAN_WBEM_HTTPS_PORT = 5989
-
-
-class RepSvc(object):
-
- class Action(object):
- CREATE_ELEMENT_REPLICA = 2
-
- class RepTypes(object):
- # SMI-S replication service capabilities
- SYNC_MIRROR_LOCAL = 2
- ASYNC_MIRROR_LOCAL = 3
- SYNC_MIRROR_REMOTE = 4
- ASYNC_MIRROR_REMOTE = 5
- SYNC_SNAPSHOT_LOCAL = 6
- ASYNC_SNAPSHOT_LOCAL = 7
- SYNC_SNAPSHOT_REMOTE = 8
- ASYNC_SNAPSHOT_REMOTE = 9
- SYNC_CLONE_LOCAL = 10
- ASYNC_CLONE_LOCAL = 11
- SYNC_CLONE_REMOTE = 12
- ASYNC_CLONE_REMOTE = 13
-
-
-class CopyStates(object):
- INITIALIZED = 2
- UNSYNCHRONIZED = 3
- SYNCHRONIZED = 4
- INACTIVE = 8
-
-
-class CopyTypes(object):
- ASYNC = 2 # Async. mirror
- SYNC = 3 # Sync. mirror
- UNSYNCASSOC = 4 # lsm Clone
- UNSYNCUNASSOC = 5 # lsm Copy
-
-
-class Synchronized(object):
- class SyncState(object):
- INITIALIZED = 2
- PREPAREINPROGRESS = 3
- PREPARED = 4
- RESYNCINPROGRESS = 5
- SYNCHRONIZED = 6
- FRACTURE_IN_PROGRESS = 7
- QUIESCEINPROGRESS = 8
- QUIESCED = 9
- RESTORE_IN_PROGRESSS = 10
- IDLE = 11
- BROKEN = 12
- FRACTURED = 13
- FROZEN = 14
- COPY_IN_PROGRESS = 15
-
-# SMI-S mode for mirror updates
-(CREATE_ELEMENT_REPLICA_MODE_SYNC,
- CREATE_ELEMENT_REPLICA_MODE_ASYNC) = (2, 3)
-
-# SMI-S volume 'OperationalStatus' enumerations
-(VOL_OP_STATUS_OK, VOL_OP_STATUS_DEGRADED, VOL_OP_STATUS_ERR,
- VOL_OP_STATUS_STARTING,
- VOL_OP_STATUS_DORMANT) = (2, 3, 6, 8, 15)
-
-# SMI-S ExposePaths device access enumerations
-(EXPOSE_PATHS_DA_READ_WRITE, EXPOSE_PATHS_DA_READ_ONLY) = (2, 3)
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:39 UTC
Permalink
Later versions of Fedora and EL linux moved /lib to /usr/lib.

Signed-off-by: Tony Asleson <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 4dd5b88..f84266c 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -40,6 +40,13 @@ Requires(preun): systemd-units
Requires(postun): systemd-units
%endif

+# Later versions moved /lib to /usr/lib
+%if 0%{?fedora} >= 18 || 0%{?rhel} >= 7
+%define udev_dir /usr/lib
+%else
+%define udev_dir /lib
+%endif
+
%description
The libStorageMgmt library will provide a vendor agnostic open source storage
application programming interface (API) that will allow management of storage
@@ -180,11 +187,12 @@ install packaging/daemon/libstoragemgmtd \
#Need these to exist at install so we can start the daemon
mkdir -p %{buildroot}%{_localstatedir}/run/lsm/ipc

-mkdir -p %{buildroot}/lib/udev/rules.d
+#Files for udev handling
+mkdir -p %{buildroot}/%{udev_dir}/udev/rules.d
install -m 644 tools/udev/90-scsi-ua.rules \
- %{buildroot}/lib/udev/rules.d/90-scsi-ua.rules
+ %{buildroot}/%{udev_dir}/udev/rules.d/90-scsi-ua.rules
install -m 755 tools/udev/scan-scsi-target \
- %{buildroot}/lib/udev/scan-scsi-target
+ %{buildroot}/%{udev_dir}/udev/scan-scsi-target

%clean
rm -rf %{buildroot}
@@ -342,8 +350,8 @@ fi

%files udev
%defattr(-,root,root,-)
-/lib/udev/scan-scsi-target
-/lib/udev/rules.d/90-scsi-ua.rules
+%{udev_dir}/udev/scan-scsi-target
+%{udev_dir}/udev/rules.d/90-scsi-ua.rules

%if 0%{?with_rest_api}
%files rest
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:33 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Some (EMC VMAX, Dot hill) SMI-S Providers allow duplicated
ElementName when creating replication, we have to do a pre-check by
enumerating all CIM_StroageVolume with 'ElementName' property only.

* EMC VMAX passed the 'TestPlugin.test_volume_replication' test of
plugin_test.py.

V2:
- We don't need to check for duplicate volume name in the exception
handler if we already checked before trying to replicate
- Move quicker search code into method so it can be shared.
- rebased

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

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index e57cb19..80c503c 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -598,8 +598,8 @@ class Smis(IStorageAreaNetwork):
return None
# SNIA might have miss documented VPD83Type3(1), it should be
# dmtf.VOL_NAME_FORMAT_OTHER(1) based on dmtf.
- # Will remove the Smis.dmtf.VOL_NAME_FORMAT_OTHER condition if confirmed as
- # SNIA document fault.
+ # Will remove the Smis.dmtf.VOL_NAME_FORMAT_OTHER condition if
+ # confirmed as SNIA document fault.
if (nf == dmtf.VOL_NAME_FORMAT_NNA and
nn == dmtf.VOL_NAME_FORMAT_OTHER) or \
(nf == dmtf.VOL_NAME_FORMAT_NNA and
@@ -828,6 +828,19 @@ class Smis(IStorageAreaNetwork):

return [smis_sys.cim_sys_to_lsm_sys(s) for s in cim_syss]

+ def _volume_exists(self, name):
+ """
+ Try to minimize time to search.
+ :param name: Volume ElementName
+ :return: True if volume exists with 'name', else False
+ """
+ all_cim_vols = self._c.EnumerateInstances(
+ 'CIM_StorageVolume', PropertyList=['ElementName'])
+ for exist_cim_vol in all_cim_vols:
+ if name == exist_cim_vol['ElementName']:
+ return True
+ return False
+
def _check_for_dupe_vol(self, volume_name, original_exception):
"""
Throw original exception or NAME_CONFLICT if volume name found
@@ -846,11 +859,7 @@ class Smis(IStorageAreaNetwork):
# name.

try:
- # TODO: Add ability to search by volume name to 'volumes'
- volumes = self.volumes()
- for v in volumes:
- if v.name == volume_name:
- report_original = False
+ report_original = not self._volume_exists(volume_name)
except Exception:
# Don't report anything here on a failing
pass
@@ -1160,6 +1169,13 @@ class Smis(IStorageAreaNetwork):
rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
volume_src.system_id,
raise_error=False)
+
+ # Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
+ # ElementName, we have to do pre-check here.
+ if self._volume_exists(name):
+ raise LsmError(ErrorNumber.NAME_CONFLICT,
+ "Volume with name '%s' already exists!" % name)
+
cim_pool_path = None
if pool is not None:
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)
@@ -1206,14 +1222,10 @@ class Smis(IStorageAreaNetwork):
if cim_pool_path is not None:
in_params['TargetPool'] = cim_pool_path

- try:
-
- return self._pi("volume_replicate",
- SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(method,
- rs.path, **in_params)))
- except CIMError:
- self._check_for_dupe_vol(name, sys.exc_info())
+ return self._pi("volume_replicate",
+ SmisCommon.JOB_RETRIEVE_VOLUME, None,
+ *(self._c.InvokeMethod(method,
+ rs.path, **in_params)))

raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:40 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Create new alias 'lsmcli lt' for this command:
lsmcli list --type target_ports

Signed-off-by: Gris Ge <***@redhat.com>
---
doc/man/lsmcli.1.in | 2 ++
tools/lsmcli/cmdline.py | 1 +
2 files changed, 3 insertions(+)

diff --git a/doc/man/lsmcli.1.in b/doc/man/lsmcli.1.in
index 93b2b88..ec4e3eb 100644
--- a/doc/man/lsmcli.1.in
+++ b/doc/man/lsmcli.1.in
@@ -564,6 +564,8 @@ Alias of 'list --type disks'
Alias of 'list --type access_groups'
.SS lf
Alias of 'list --type fs'
+.SS lt
+Alias of 'list --type target_ports'
.SS c
Alias of 'capabilities'
.SS p
diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index 0a4e656..66163b3 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -601,6 +601,7 @@ aliases = (
['ld', 'list --type disks'],
['la', 'list --type access_groups'],
['lf', 'list --type fs'],
+ ['lt', 'list --type target_ports'],
['c', 'capabilities'],
['p', 'plugin-info'],
['vc', 'volume-create'],
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:26 UTC
Permalink
Moving handle_cim_error, hex_string_format to utils.py

Move smis class constants to smis_constants.py, move remaining
DMTF constants to dmtf.py file.

There is quite a bit of code which is used to determine
what capabilities an array supports. Move this into
a separate file of related functionality.

To make this work we needed to move:

- get_class_instance
- get_cim_service_path

To smis_common.py

I also moved the MASK_* constants to the new file too.

Updated:
- Rename file to smis_cap.py
- Change from class to functions instead

Signed-off-by: Tony Asleson <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 4 +-
plugin/smispy/dmtf.py | 70 +++
plugin/smispy/smis.py | 962 ++++++---------------------------------
plugin/smispy/smis_cap.py | 398 ++++++++++++++++
plugin/smispy/smis_common.py | 61 +++
plugin/smispy/smis_constants.py | 132 ++++++
plugin/smispy/utils.py | 49 ++
8 files changed, 865 insertions(+), 813 deletions(-)
create mode 100644 plugin/smispy/smis_cap.py
create mode 100644 plugin/smispy/smis_constants.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index c9414df..ef39361 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -315,7 +315,9 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis.*
%{python_sitelib}/lsm/plugin/smispy/dmtf.*
%{python_sitelib}/lsm/plugin/smispy/utils.*
+%{python_sitelib}/lsm/plugin/smispy/smis_constants.*
%{python_sitelib}/lsm/plugin/smispy/smis_common.*
+%{python_sitelib}/lsm/plugin/smispy/smis_cap.*
%{_bindir}/smispy_lsmplugin

%files netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index 424ad93..30b4ea5 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -26,8 +26,10 @@ smispy_PYTHON = \
smispy/__init__.py \
smispy/smis.py \
smispy/utils.py \
+ smispy/smis_constants.py \
smispy/smis_common.py \
- smispy/dmtf.py
+ smispy/dmtf.py \
+ smispy/smis_cap.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 458e881..2bea0fe 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -209,3 +209,73 @@ class DMTF(object):
# DSP 1033 Profile Registration
INTEROP_NAMESPACES = ['interop', 'root/interop', 'root/PG_Interop']
DEFAULT_NAMESPACE = 'interop'
+
+
+# DMTF CIM 2.37.0 experimental CIM_StoragePool['Usage']
+DMTF_POOL_USAGE_UNRESTRICTED = 2
+DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM = 3
+DMTF_POOL_USAGE_DELTA = 4
+DMTF_POOL_USAGE_SPARE = 8
+
+# DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
+# ['SupportedStorageElementFeatures']
+DMTF_SUPPORT_VOL_CREATE = 3
+DMTF_SUPPORT_ELEMENT_EXPAND = 12
+DMTF_SUPPORT_ELEMENT_REDUCE = 13
+
+# DMTF CIM 2.37.0 experimental CIM_StorageConfigurationCapabilities
+# ['SupportedStorageElementTypes']
+DMTF_ELEMENT_THICK_VOLUME = 2
+DMTF_ELEMENT_THIN_VOLUME = 5
+
+# DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
+# ['SupportedStoragePoolFeatures']
+DMTF_ST_POOL_FEATURE_INEXTS = 2
+DMTF_ST_POOL_FEATURE_SINGLE_INPOOL = 3
+DMTF_ST_POOL_FEATURE_MULTI_INPOOL = 4
+
+# DMTF CIM 2.38.0+ CIM_StorageSetting['ThinProvisionedPoolType']
+DMTF_THINP_POOL_TYPE_ALLOCATED = Uint16(7)
+
+# DMTF Disk Type
+DMTF_DISK_TYPE_UNKNOWN = 0
+DMTF_DISK_TYPE_OTHER = 1
+DMTF_DISK_TYPE_HDD = 2
+DMTF_DISK_TYPE_SSD = 3
+DMTF_DISK_TYPE_HYBRID = 4
+
+_DMTF_DISK_TYPE_2_LSM = {
+ DMTF_DISK_TYPE_UNKNOWN: Disk.TYPE_UNKNOWN,
+ DMTF_DISK_TYPE_OTHER: Disk.TYPE_OTHER,
+ DMTF_DISK_TYPE_HDD: Disk.TYPE_HDD,
+ DMTF_DISK_TYPE_SSD: Disk.TYPE_SSD,
+ DMTF_DISK_TYPE_HYBRID: Disk.TYPE_HYBRID,
+}
+
+
+def dmtf_disk_type_2_lsm_disk_type(dmtf_disk_type):
+ if dmtf_disk_type in _DMTF_DISK_TYPE_2_LSM.keys():
+ return _DMTF_DISK_TYPE_2_LSM[dmtf_disk_type]
+ else:
+ return Disk.TYPE_UNKNOWN
+
+
+DMTF_STATUS_UNKNOWN = 0
+DMTF_STATUS_OTHER = 1
+DMTF_STATUS_OK = 2
+DMTF_STATUS_DEGRADED = 3
+DMTF_STATUS_STRESSED = 4
+DMTF_STATUS_PREDICTIVE_FAILURE = 5
+DMTF_STATUS_ERROR = 6
+DMTF_STATUS_NON_RECOVERABLE_ERROR = 7
+DMTF_STATUS_STARTING = 8
+DMTF_STATUS_STOPPING = 9
+DMTF_STATUS_STOPPED = 10
+DMTF_STATUS_IN_SERVICE = 11
+DMTF_STATUS_NO_CONTACT = 12
+DMTF_STATUS_LOST_COMMUNICATION = 13
+DMTF_STATUS_ABORTED = 14
+DMTF_STATUS_DORMANT = 15
+DMTF_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16
+DMTF_STATUS_COMPLETED = 17
+DMTF_STATUS_POWER_MODE = 18
\ No newline at end of file
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 7ba694b..84537bc 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -28,14 +28,17 @@ import re

import pywbem
from pywbem import CIMError
+from smis_constants import *
+import smis_cap

-from lsm import (IStorageAreaNetwork, error, uri_parse, LsmError, ErrorNumber,
- JobStatus, md5, Pool, Volume, AccessGroup, System,
- Capabilities, Disk, VERSION, TargetPort,
+from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
+ JobStatus, md5, Volume, AccessGroup,
+ VERSION, TargetPort,
search_property)

-from dmtf import DMTF
-from utils import merge_list
+from dmtf import *
+from utils import (merge_list, handle_cim_errors, hex_string_format)
+
from smis_common import SmisCommon

## Variable Naming scheme:
@@ -79,66 +82,6 @@ from smis_common import SmisCommon
# Group M&M SNIA SMI-S 'Group Masking and Mapping' profile


-def handle_cim_errors(method):
- def cim_wrapper(*args, **kwargs):
- try:
- return method(*args, **kwargs)
- except LsmError as lsm:
- raise
- except CIMError as ce:
- error_code, desc = ce
-
- if error_code == 0:
- if 'Socket error' in desc:
- if 'Errno 111' in desc:
- raise LsmError(ErrorNumber.NETWORK_CONNREFUSED,
- 'Connection refused')
- if 'Errno 113' in desc:
- raise LsmError(ErrorNumber.NETWORK_HOSTDOWN,
- 'Host is down')
- elif 'SSL error' in desc:
- raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION,
- desc)
- elif 'The web server returned a bad status line':
- raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION,
- desc)
- elif 'HTTP error' in desc:
- raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION,
- desc)
- raise LsmError(ErrorNumber.PLUGIN_BUG, desc)
- except pywbem.cim_http.AuthError as ae:
- raise LsmError(ErrorNumber.PLUGIN_AUTH_FAILED, "Unauthorized user")
- except pywbem.cim_http.Error as te:
- raise LsmError(ErrorNumber.NETWORK_ERROR, str(te))
- except Exception as e:
- error("Unexpected exception:\n" + traceback.format_exc())
- raise LsmError(ErrorNumber.PLUGIN_BUG, str(e),
- traceback.format_exc())
- return cim_wrapper
-
-
-def _spec_ver_str_to_num(spec_ver_str):
- """
- Convert version string stored in CIM_RegisteredProfile to a integer.
- Example:
- "1.5.1" -> 1,005,001
- """
- tmp_list = [0, 0, 0]
- tmp_list = spec_ver_str.split(".")
- if len(tmp_list) == 2:
- tmp_list.extend([0])
- if len(tmp_list) == 3:
- return (int(tmp_list[0]) * 10 ** 6 +
- int(tmp_list[1]) * 10 ** 3 +
- int(tmp_list[2]))
- return None
-
-
-def _hex_string_format(hex_str, length, every):
- hex_str = hex_str.lower()
- return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
-
-
def _lsm_init_id_to_snia(lsm_init_id):
"""
If lsm_init_id is a WWPN, convert it to SNIA format:
@@ -185,201 +128,15 @@ def _lsm_init_type_to_dmtf(init_type):
raise LsmError(ErrorNumber.NO_SUPPORT,
"Does not support provided init_type: %d" % init_type)

+
class Smis(IStorageAreaNetwork):
"""
SMI-S plug-ing which exposes a small subset of the overall provided
functionality of SMI-S
"""
-
- # SMI-S job 'JobState' enumerations
- (JS_NEW, JS_STARTING, JS_RUNNING, JS_SUSPENDED, JS_SHUTTING_DOWN,
- JS_COMPLETED,
- JS_TERMINATED, JS_KILLED, JS_EXCEPTION) = (2, 3, 4, 5, 6, 7, 8, 9, 10)
-
- # SMI-S job 'OperationalStatus' enumerations
- (JOB_OK, JOB_ERROR, JOB_STOPPED, JOB_COMPLETE) = (2, 6, 10, 17)
-
- # SMI-S invoke return values we are interested in
- # Reference: Page 54 in 1.5 SMI-S block specification
- (INVOKE_OK,
- INVOKE_NOT_SUPPORTED,
- INVOKE_TIMEOUT,
- INVOKE_FAILED,
- INVOKE_INVALID_PARAMETER,
- INVOKE_IN_USE,
- INVOKE_ASYNC,
- INVOKE_SIZE_NOT_SUPPORTED) = (0, 1, 3, 4, 5, 6, 4096, 4097)
-
- # SMI-S replication enumerations
- (SYNC_TYPE_MIRROR, SYNC_TYPE_SNAPSHOT, SYNC_TYPE_CLONE) = (6, 7, 8)
-
- # DMTF 2.29.1 (which SNIA SMI-S 1.6 based on)
- # CIM_StorageVolume['NameFormat']
- VOL_NAME_FORMAT_OTHER = 1
- VOL_NAME_FORMAT_VPD83_NNA6 = 2
- VOL_NAME_FORMAT_VPD83_NNA5 = 3
- VOL_NAME_FORMAT_VPD83_TYPE2 = 4
- VOL_NAME_FORMAT_VPD83_TYPE1 = 5
- VOL_NAME_FORMAT_VPD83_TYPE0 = 6
- VOL_NAME_FORMAT_SNVM = 7
- VOL_NAME_FORMAT_NODE_WWN = 8
- VOL_NAME_FORMAT_NNA = 9
- VOL_NAME_FORMAT_EUI64 = 10
- VOL_NAME_FORMAT_T10VID = 11
-
- # CIM_StorageVolume['NameNamespace']
- VOL_NAME_SPACE_OTHER = 1
- VOL_NAME_SPACE_VPD83_TYPE3 = 2
- VOL_NAME_SPACE_VPD83_TYPE2 = 3
- VOL_NAME_SPACE_VPD83_TYPE1 = 4
- VOL_NAME_SPACE_VPD80 = 5
- VOL_NAME_SPACE_NODE_WWN = 6
- VOL_NAME_SPACE_SNVM = 7
-
- JOB_RETRIEVE_NONE = 0
- JOB_RETRIEVE_VOLUME = 1
- JOB_RETRIEVE_POOL = 2
-
- # DMTF CIM 2.37.0 experimental CIM_StoragePool['Usage']
- DMTF_POOL_USAGE_UNRESTRICTED = 2
- DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM = 3
- DMTF_POOL_USAGE_DELTA = 4
- DMTF_POOL_USAGE_SPARE = 8
-
- # DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
- # ['SupportedStorageElementFeatures']
- DMTF_SUPPORT_VOL_CREATE = 3
- DMTF_SUPPORT_ELEMENT_EXPAND = 12
- DMTF_SUPPORT_ELEMENT_REDUCE = 13
-
- # DMTF CIM 2.37.0 experimental CIM_StorageConfigurationCapabilities
- # ['SupportedStorageElementTypes']
- DMTF_ELEMENT_THICK_VOLUME = 2
- DMTF_ELEMENT_THIN_VOLUME = 5
-
- # DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
- # ['SupportedStoragePoolFeatures']
- DMTF_ST_POOL_FEATURE_INEXTS = 2
- DMTF_ST_POOL_FEATURE_SINGLE_INPOOL = 3
- DMTF_ST_POOL_FEATURE_MULTI_INPOOL = 4
-
- # DMTF CIM 2.38.0+ CIM_StorageSetting['ThinProvisionedPoolType']
- DMTF_THINP_POOL_TYPE_ALLOCATED = pywbem.Uint16(7)
-
- # DMTF Disk Type
- DMTF_DISK_TYPE_UNKNOWN = 0
- DMTF_DISK_TYPE_OTHER = 1
- DMTF_DISK_TYPE_HDD = 2
- DMTF_DISK_TYPE_SSD = 3
- DMTF_DISK_TYPE_HYBRID = 4
-
- _DMTF_DISK_TYPE_2_LSM = {
- DMTF_DISK_TYPE_UNKNOWN: Disk.TYPE_UNKNOWN,
- DMTF_DISK_TYPE_OTHER: Disk.TYPE_OTHER,
- DMTF_DISK_TYPE_HDD: Disk.TYPE_HDD,
- DMTF_DISK_TYPE_SSD: Disk.TYPE_SSD,
- DMTF_DISK_TYPE_HYBRID: Disk.TYPE_HYBRID,
- }
-
- @staticmethod
- def dmtf_disk_type_2_lsm_disk_type(dmtf_disk_type):
- if dmtf_disk_type in Smis._DMTF_DISK_TYPE_2_LSM.keys():
- return Smis._DMTF_DISK_TYPE_2_LSM[dmtf_disk_type]
- else:
- return Disk.TYPE_UNKNOWN
-
- DMTF_STATUS_UNKNOWN = 0
- DMTF_STATUS_OTHER = 1
- DMTF_STATUS_OK = 2
- DMTF_STATUS_DEGRADED = 3
- DMTF_STATUS_STRESSED = 4
- DMTF_STATUS_PREDICTIVE_FAILURE = 5
- DMTF_STATUS_ERROR = 6
- DMTF_STATUS_NON_RECOVERABLE_ERROR = 7
- DMTF_STATUS_STARTING = 8
- DMTF_STATUS_STOPPING = 9
- DMTF_STATUS_STOPPED = 10
- DMTF_STATUS_IN_SERVICE = 11
- DMTF_STATUS_NO_CONTACT = 12
- DMTF_STATUS_LOST_COMMUNICATION = 13
- DMTF_STATUS_ABORTED = 14
- DMTF_STATUS_DORMANT = 15
- DMTF_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16
- DMTF_STATUS_COMPLETED = 17
- DMTF_STATUS_POWER_MODE = 18
-
-
- IAAN_WBEM_HTTP_PORT = 5988
- IAAN_WBEM_HTTPS_PORT = 5989
-
- MASK_TYPE_NO_SUPPORT = 0
- MASK_TYPE_MASK = 1
- MASK_TYPE_GROUP = 2
-
_INVOKE_MAX_LOOP_COUNT = 60
_INVOKE_CHECK_INTERVAL = 5

- class RepSvc(object):
-
- class Action(object):
- CREATE_ELEMENT_REPLICA = 2
-
- class RepTypes(object):
- # SMI-S replication service capabilities
- SYNC_MIRROR_LOCAL = 2
- ASYNC_MIRROR_LOCAL = 3
- SYNC_MIRROR_REMOTE = 4
- ASYNC_MIRROR_REMOTE = 5
- SYNC_SNAPSHOT_LOCAL = 6
- ASYNC_SNAPSHOT_LOCAL = 7
- SYNC_SNAPSHOT_REMOTE = 8
- ASYNC_SNAPSHOT_REMOTE = 9
- SYNC_CLONE_LOCAL = 10
- ASYNC_CLONE_LOCAL = 11
- SYNC_CLONE_REMOTE = 12
- ASYNC_CLONE_REMOTE = 13
-
- class CopyStates(object):
- INITIALIZED = 2
- UNSYNCHRONIZED = 3
- SYNCHRONIZED = 4
- INACTIVE = 8
-
- class CopyTypes(object):
- ASYNC = 2 # Async. mirror
- SYNC = 3 # Sync. mirror
- UNSYNCASSOC = 4 # lsm Clone
- UNSYNCUNASSOC = 5 # lsm Copy
-
- class Synchronized(object):
- class SyncState(object):
- INITIALIZED = 2
- PREPAREINPROGRESS = 3
- PREPARED = 4
- RESYNCINPROGRESS = 5
- SYNCHRONIZED = 6
- FRACTURE_IN_PROGRESS = 7
- QUIESCEINPROGRESS = 8
- QUIESCED = 9
- RESTORE_IN_PROGRESSS = 10
- IDLE = 11
- BROKEN = 12
- FRACTURED = 13
- FROZEN = 14
- COPY_IN_PROGRESS = 15
-
- # SMI-S mode for mirror updates
- (CREATE_ELEMENT_REPLICA_MODE_SYNC,
- CREATE_ELEMENT_REPLICA_MODE_ASYNC) = (2, 3)
-
- # SMI-S volume 'OperationalStatus' enumerations
- (VOL_OP_STATUS_OK, VOL_OP_STATUS_DEGRADED, VOL_OP_STATUS_ERR,
- VOL_OP_STATUS_STARTING,
- VOL_OP_STATUS_DORMANT) = (2, 3, 6, 8, 15)
-
- # SMI-S ExposePaths device access enumerations
- (EXPOSE_PATHS_DA_READ_WRITE, EXPOSE_PATHS_DA_READ_ONLY) = (2, 3)
-
def __init__(self):
self._c = None
self.tmo = 0
@@ -416,59 +173,24 @@ class Smis(IStorageAreaNetwork):
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))

- def _get_class_instance(self, class_name, prop_name, prop_value,
- raise_error=True, property_list=None):
- """
- Gets an instance of a class that optionally matches a specific
- property name and value
- """
- instances = None
- if property_list is None:
- property_list = [prop_name]
- else:
- property_list = merge_list(property_list, [prop_name])
-
- try:
- cim_xxxs = self._c.EnumerateInstances(
- class_name, PropertyList=property_list)
- except CIMError as ce:
- error_code = tuple(ce)[0]
-
- if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
- raise_error is False:
- return None
- else:
- raise
-
- for cim_xxx in cim_xxxs:
- if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
- return cim_xxx
-
- if raise_error:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
- return None
-
def _pi(self, msg, retrieve_data, rc, out):
"""
Handle the the process of invoking an operation.
"""
# Check to see if operation is done
- if rc == Smis.INVOKE_OK:
- if retrieve_data == Smis.JOB_RETRIEVE_VOLUME:
+ if rc == INVOKE_OK:
+ if retrieve_data == JOB_RETRIEVE_VOLUME:
return None, self._new_vol_from_name(out)
- elif retrieve_data == Smis.JOB_RETRIEVE_POOL:
+ elif retrieve_data == JOB_RETRIEVE_POOL:
return None, self._new_pool_from_name(out)
else:
return None, None

- elif rc == Smis.INVOKE_ASYNC:
+ elif rc == INVOKE_ASYNC:
# We have an async operation
job_id = self._job_id(out['Job'], retrieve_data)
return job_id, None
- elif rc == Smis.INVOKE_NOT_SUPPORTED:
+ elif rc == INVOKE_NOT_SUPPORTED:
raise LsmError(
ErrorNumber.NO_SUPPORT,
'SMI-S error code indicates operation not supported')
@@ -511,12 +233,12 @@ class Smis(IStorageAreaNetwork):
Enumerate CIM_RegisteredProfile in userdefined namespace.
"""
protocol = 'http'
- port = Smis.IAAN_WBEM_HTTP_PORT
+ port = IAAN_WBEM_HTTP_PORT
u = uri_parse(uri, ['scheme', 'netloc', 'host'], None)

if u['scheme'].lower() == 'smispy+ssl':
protocol = 'https'
- port = Smis.IAAN_WBEM_HTTPS_PORT
+ port = IAAN_WBEM_HTTPS_PORT

if 'port' in u:
port = u['port']
@@ -548,312 +270,23 @@ class Smis(IStorageAreaNetwork):

self.tmo = timeout

+ @handle_cim_errors
def time_out_set(self, ms, flags=0):
self.tmo = ms

+ @handle_cim_errors
def time_out_get(self, flags=0):
return self.tmo

+ @handle_cim_errors
def plugin_unregister(self, flags=0):
self._c = None

- def _bsp_cap_set(self, cim_sys_path, cap):
- """
- Set capabilities for these methods:
- volumes()
- volume_create()
- volume_resize()
- volume_delete()
- """
- # CIM_StorageConfigurationService is optional.
- cim_scs_path = self._get_cim_service_path(
- cim_sys_path, 'CIM_StorageConfigurationService')
-
- if cim_scs_path is None:
- return
-
- # These methods are mandatory for CIM_StorageConfigurationService:
- # CreateOrModifyElementFromStoragePool()
- # ReturnToStoragePool()
- # But SNIA never defined which function of
- # CreateOrModifyElementFromStoragePool() is mandatory.
- # Hence we check CIM_StorageConfigurationCapabilities
- # which is mandatory if CIM_StorageConfigurationService is supported.
- cim_scs_cap = self._c.Associators(
- cim_scs_path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities',
- PropertyList=['SupportedAsynchronousActions',
- 'SupportedSynchronousActions',
- 'SupportedStorageElementTypes'])[0]
-
- element_types = cim_scs_cap['SupportedStorageElementTypes']
- sup_actions = []
-
- if 'SupportedSynchronousActions' in cim_scs_cap:
- if cim_scs_cap['SupportedSynchronousActions']:
- sup_actions.extend(cim_scs_cap['SupportedSynchronousActions'])
-
- if 'SupportedAsynchronousActions' in cim_scs_cap:
- if cim_scs_cap['SupportedAsynchronousActions']:
- sup_actions.extend(cim_scs_cap['SupportedAsynchronousActions'])
-
- if DMTF.SCS_CAP_SUP_ST_VOLUME in element_types or \
- DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
- cap.set(Capabilities.VOLUMES)
- if DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
- cap.set(Capabilities.VOLUME_THIN)
-
- if DMTF.SCS_CAP_VOLUME_CREATE in sup_actions:
- cap.set(Capabilities.VOLUME_CREATE)
-
- if DMTF.SCS_CAP_VOLUME_DELETE in sup_actions:
- cap.set(Capabilities.VOLUME_DELETE)
-
- if DMTF.SCS_CAP_VOLUME_MODIFY in sup_actions:
- cap.set(Capabilities.VOLUME_RESIZE)
-
- return
-
- def _disk_cap_set(self, cim_sys_path, cap):
- if not self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return
-
- cap.set(Capabilities.DISKS)
- return
-
- def _rs_supported_capabilities(self, system, cap):
- """
- Interrogate the supported features of the replication service
- """
- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, raise_error=False)
- if rs:
- rs_cap = self._c.Associators(
- rs.path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_ReplicationServiceCapabilities')[0]
-
- s_rt = rs_cap['SupportedReplicationTypes']
-
- if self.RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt or \
- self.RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt:
- cap.set(Capabilities.VOLUME_REPLICATE)
-
- # Mirror support is not working and is not supported at this time.
- # if self.RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
- # cap.set(Capabilities.DeviceID)
-
- # if self.RepSvc.RepTypes.ASYNC_MIRROR_LOCAL \
- # in s_rt:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
-
- if self.RepSvc.RepTypes.SYNC_SNAPSHOT_LOCAL in s_rt or \
- self.RepSvc.RepTypes.ASYNC_SNAPSHOT_LOCAL in s_rt:
- cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
-
- if self.RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt or \
- self.RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
- cap.set(Capabilities.VOLUME_REPLICATE_COPY)
- else:
- # Try older storage configuration service
-
- rs = self._get_class_instance("CIM_StorageConfigurationService",
- 'SystemName',
- system.id, raise_error=False)
-
- if rs:
- rs_cap = self._c.Associators(
- rs.path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
-
- if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
- sct = rs_cap['SupportedCopyTypes']
-
- if sct and len(sct):
- cap.set(Capabilities.VOLUME_REPLICATE)
-
- # Mirror support is not working and is not supported at
- # this time.
-
- # if Smis.CopyTypes.ASYNC in sct:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
-
- # if Smis.CopyTypes.SYNC in sct:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_SYNC)
-
- if Smis.CopyTypes.UNSYNCASSOC in sct:
- cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
-
- if Smis.CopyTypes.UNSYNCUNASSOC in sct:
- cap.set(Capabilities.VOLUME_REPLICATE_COPY)
-
- def _mask_map_cap_set(self, cim_sys_path, cap):
- """
- In SNIA SMI-S 1.4rev6 'Masking and Mapping' profile:
- CIM_ControllerConfigurationService is mandatory
- and it's ExposePaths() and HidePaths() are mandatory
- """
- if not self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return
-
- cap.set(Capabilities.ACCESS_GROUPS)
- cap.set(Capabilities.VOLUME_MASK)
- cap.set(Capabilities.VOLUME_UNMASK)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
- cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
- cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
-
- # EMC VNX does not support CreateStorageHardwareID for iSCSI
- # and require WWNN for WWPN. Hence both are not supported.
- if cim_sys_path.classname == 'Clar_StorageSystem':
- return
-
- if self._fc_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
- if self._iscsi_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
- return
-
- def _common_capabilities(self, system):
- cap = Capabilities()
-
- self._rs_supported_capabilities(system, cap)
- return cap
-
- def _tgt_cap_set(self, cim_sys_path, cap):
-
- # LSI MegaRAID actually not support FC Target and iSCSI target,
- # They expose empty list of CIM_FCPort
- if cim_sys_path.classname == 'LSIESG_MegaRAIDHBA':
- return
-
- flag_fc_support = self._c.profile_check(
- SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- # One more check for NetApp Typo:
- # NetApp: 'FC Target Port'
- # SMI-S: 'FC Target Ports'
- # Bug reported.
- if not flag_fc_support:
- flag_fc_support = self._c.profile_check(
- 'FC Target Port',
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- flag_iscsi_support = self._c.profile_check(
- SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
-
- if flag_fc_support or flag_iscsi_support:
- cap.set(Capabilities.TARGET_PORTS)
- return
-
- def _group_mask_map_cap_set(self, cim_sys_path, cap):
- """
- We set caps for these methods recording to 1.5+ Group M&M profile:
- access_groups()
- access_groups_granted_to_volume()
- volumes_accessible_by_access_group()
- access_group_initiator_add()
- access_group_initiator_delete()
- volume_mask()
- volume_unmask()
- access_group_create()
- access_group_delete()
- """
- # These are mandatory in SNIA SMI-S.
- # We are not in the position of SNIA SMI-S certification.
- cap.set(Capabilities.ACCESS_GROUPS)
- cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
- cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
- cap.set(Capabilities.VOLUME_MASK)
- if self._fc_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
- cap.set(Capabilities.ACCESS_GROUP_CREATE_WWPN)
- if self._iscsi_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
- cap.set(Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN)
-
- # RemoveMembers is also mandatory
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
-
- cim_gmm_cap_pros = [
- 'SupportedAsynchronousActions',
- 'SupportedSynchronousActions',
- 'SupportedDeviceGroupFeatures']
-
- cim_gmm_cap = self._c.Associators(
- cim_sys_path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_GroupMaskingMappingCapabilities',
- PropertyList=cim_gmm_cap_pros)[0]
-
- # if empty dev group in spc is allowed, RemoveMembers() is enough
- # to do volume_unmask(). RemoveMembers() is mandatory.
- if DMTF.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
- cim_gmm_cap['SupportedDeviceGroupFeatures']:
- cap.set(Capabilities.VOLUME_UNMASK)
-
- # DeleteMaskingView() is optional, this is required by volume_unmask()
- # when empty dev group in spc not allowed.
- elif ((DMTF.GMM_CAP_DELETE_SPC in
- cim_gmm_cap['SupportedSynchronousActions']) or
- (DMTF.GMM_CAP_DELETE_SPC in
- cim_gmm_cap['SupportedAsynchronousActions'])):
- cap.set(Capabilities.VOLUME_UNMASK)
-
- # DeleteGroup is optional, this is required by access_group_delete()
- if ((DMTF.GMM_CAP_DELETE_GROUP in
- cim_gmm_cap['SupportedSynchronousActions']) or
- (DMTF.GMM_CAP_DELETE_GROUP in
- cim_gmm_cap['SupportedAsynchronousActions'])):
- cap.set(Capabilities.ACCESS_GROUP_DELETE)
- return None
-
@handle_cim_errors
def capabilities(self, system, flags=0):
- if self._c.is_netappe():
- cap = self._common_capabilities(system)
-
- #TODO We need to investigate why our interrogation code doesn't
- #work.
- #The array is telling us one thing, but when we try to use it, it
- #doesn't work
- return cap
-
cim_sys = self._get_cim_instance_by_id(
'System', system.id, raise_error=True)
-
- cap = Capabilities()
-
- # 'Block Services Package' profile
- self._bsp_cap_set(cim_sys.path, cap)
-
- # 'Disk Drive Lite' profile
- self._disk_cap_set(cim_sys.path, cap)
-
- # 'Masking and Mapping' and 'Group Masking and Mapping' profiles
- mask_type = self._mask_type()
- if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = Smis.MASK_TYPE_MASK
-
- if mask_type == Smis.MASK_TYPE_GROUP:
- self._group_mask_map_cap_set(cim_sys.path, cap)
- else:
- self._mask_map_cap_set(cim_sys.path, cap)
-
- # 'FC Target Ports' and 'iSCSI Target Ports' profiles
- self._tgt_cap_set(cim_sys.path, cap)
-
- self._rs_supported_capabilities(system, cap)
- return cap
+ return smis_cap.get(self._c, cim_sys, system)

@handle_cim_errors
def plugin_info(self, flags=0):
@@ -870,8 +303,8 @@ class Smis(IStorageAreaNetwork):
op = status['OperationalStatus']

if (len(op) > 1 and
- ((op[0] == Smis.JOB_OK and op[1] == Smis.JOB_COMPLETE) or
- (op[0] == Smis.JOB_COMPLETE and op[1] == Smis.JOB_OK))):
+ ((op[0] == JOB_OK and op[1] == JOB_COMPLETE) or
+ (op[0] == JOB_COMPLETE and op[1] == JOB_OK))):
rc = True

return rc
@@ -892,7 +325,7 @@ class Smis(IStorageAreaNetwork):

job_state = cim_job['JobState']

- if job_state in (Smis.JS_NEW, Smis.JS_STARTING, Smis.JS_RUNNING):
+ if job_state in (JS_NEW, JS_STARTING, JS_RUNNING):
status = JobStatus.INPROGRESS

pc = cim_job['PercentComplete']
@@ -901,15 +334,15 @@ class Smis(IStorageAreaNetwork):
else:
percent_complete = pc

- elif job_state == Smis.JS_COMPLETED:
+ elif job_state == JS_COMPLETED:
status = JobStatus.COMPLETE
percent_complete = 100

if Smis._job_completed_ok(cim_job):
(ignore, retrieve_data) = self._parse_job_id(job_id)
- if retrieve_data == Smis.JOB_RETRIEVE_VOLUME:
+ if retrieve_data == JOB_RETRIEVE_VOLUME:
completed_item = self._new_vol_from_job(cim_job)
- elif retrieve_data == Smis.JOB_RETRIEVE_POOL:
+ elif retrieve_data == JOB_RETRIEVE_POOL:
completed_item = self._new_pool_from_job(cim_job)
else:
status = JobStatus.ERROR
@@ -1074,7 +507,7 @@ class Smis(IStorageAreaNetwork):
"""
tmp_list = job_id.split('@', 2)
md5_str = tmp_list[0]
- retrieve_data = Smis.JOB_RETRIEVE_NONE
+ retrieve_data = JOB_RETRIEVE_NONE
if len(tmp_list) == 2:
retrieve_data = int(tmp_list[1])
return (md5_str, retrieve_data)
@@ -1195,14 +628,14 @@ class Smis(IStorageAreaNetwork):
# VOL_NAME_FORMAT_OTHER(1) based on DMTF.
# Will remove the Smis.VOL_NAME_FORMAT_OTHER condition if confirmed as
# SNIA document fault.
- if (nf == Smis.VOL_NAME_FORMAT_NNA and
- nn == Smis.VOL_NAME_FORMAT_OTHER) or \
- (nf == Smis.VOL_NAME_FORMAT_NNA and
- nn == Smis.VOL_NAME_SPACE_VPD83_TYPE3) or \
- (nf == Smis.VOL_NAME_FORMAT_EUI64 and
- nn == Smis.VOL_NAME_SPACE_VPD83_TYPE2) or \
- (nf == Smis.VOL_NAME_FORMAT_T10VID and
- nn == Smis.VOL_NAME_SPACE_VPD83_TYPE1):
+ if (nf == VOL_NAME_FORMAT_NNA and
+ nn == VOL_NAME_FORMAT_OTHER) or \
+ (nf == VOL_NAME_FORMAT_NNA and
+ nn == VOL_NAME_SPACE_VPD83_TYPE3) or \
+ (nf == VOL_NAME_FORMAT_EUI64 and
+ nn == VOL_NAME_SPACE_VPD83_TYPE2) or \
+ (nf == VOL_NAME_FORMAT_T10VID and
+ nn == VOL_NAME_SPACE_VPD83_TYPE1):
return name

@staticmethod
@@ -1459,7 +892,7 @@ class Smis(IStorageAreaNetwork):
for cim_pool in self._cim_pools_of(cim_sys.path, cim_pool_pros):
# Skip spare storage pool.
if 'Usage' in cim_pool and \
- cim_pool['Usage'] == Smis.DMTF_POOL_USAGE_SPARE:
+ cim_pool['Usage'] == DMTF_POOL_USAGE_SPARE:
continue
# Skip IBM ArrayPool and ArraySitePool
# ArrayPool is holding RAID info.
@@ -1616,8 +1049,8 @@ class Smis(IStorageAreaNetwork):
"Unsupported provisioning")

# Get the Configuration service for the system we are interested in.
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', pool.system_id)
sp = self._get_cim_instance_by_id('Pool', pool.id)

in_params = {'ElementName': volume_name,
@@ -1626,7 +1059,7 @@ class Smis(IStorageAreaNetwork):
'Size': pywbem.Uint64(size_bytes)}

try:
- return self._pi("volume_create", Smis.JOB_RETRIEVE_VOLUME,
+ return self._pi("volume_create", JOB_RETRIEVE_VOLUME,
*(self._c.InvokeMethod(
'CreateOrModifyElementFromStoragePool',
scs.path, **in_params)))
@@ -1650,13 +1083,13 @@ class Smis(IStorageAreaNetwork):

def _detach_netapp_e(self, vol, sync):
#Get the Configuration service for the system we are interested in.
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', vol.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', vol.system_id)

in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}

- job_id = self._pi("_detach", Smis.JOB_RETRIEVE_NONE,
+ job_id = self._pi("_detach", JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod(
'ModifySynchronization', scs.path,
**in_params)))[0]
@@ -1667,14 +1100,14 @@ class Smis(IStorageAreaNetwork):
if self._c.is_netappe():
return self._detach_netapp_e(vol, sync)

- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- vol.system_id, raise_error=False)
+ rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
+ vol.system_id, raise_error=False)

if rs:
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}

- job_id = self._pi("_detach", Smis.JOB_RETRIEVE_NONE,
+ job_id = self._pi("_detach", JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod(
'ModifyReplicaSynchronization', rs.path,
**in_params)))[0]
@@ -1757,8 +1190,8 @@ class Smis(IStorageAreaNetwork):

if 'SyncState' in s and 'CopyType' in s:
if s['SyncState'] == \
- Smis.Synchronized.SyncState.SYNCHRONIZED and \
- (s['CopyType'] != Smis.CopyTypes.UNSYNCASSOC):
+ Synchronized.SyncState.SYNCHRONIZED and \
+ (s['CopyType'] != CopyTypes.UNSYNCASSOC):
if 'SyncedElement' in s:
item = s['SyncedElement']

@@ -1772,8 +1205,8 @@ class Smis(IStorageAreaNetwork):
self._detach(vol, s)

def _volume_delete_netapp_e(self, volume, flags=0):
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', volume.system_id)
lun = self._get_cim_instance_by_id('Volume', volume.id)

#If we actually have an association to delete, the volume will be
@@ -1782,7 +1215,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'TheElement': lun.path}

#Delete returns None or Job number
- return self._pi("volume_delete", Smis.JOB_RETRIEVE_NONE,
+ return self._pi("volume_delete", JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod('ReturnToStoragePool',
scs.path, **in_params)))[0]

@@ -1800,8 +1233,8 @@ class Smis(IStorageAreaNetwork):
"""
Delete a volume
"""
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', volume.system_id)
lun = self._get_cim_instance_by_id('Volume', volume.id)

self._deal_volume_associations(volume, lun)
@@ -1809,7 +1242,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'TheElement': lun.path}

# Delete returns None or Job number
- return self._pi("volume_delete", Smis.JOB_RETRIEVE_NONE,
+ return self._pi("volume_delete", JOB_RETRIEVE_NONE,
*(self._c.InvokeMethod('ReturnToStoragePool',
scs.path,
**in_params)))[0]
@@ -1819,15 +1252,15 @@ class Smis(IStorageAreaNetwork):
"""
Re-size a volume
"""
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', volume.system_id)
lun = self._get_cim_instance_by_id('Volume', volume.id)

in_params = {'ElementType': pywbem.Uint16(2),
'TheElement': lun.path,
'Size': pywbem.Uint64(new_size_bytes)}

- return self._pi("volume_resize", Smis.JOB_RETRIEVE_VOLUME,
+ return self._pi("volume_resize", JOB_RETRIEVE_VOLUME,
*(self._c.InvokeMethod(
'CreateOrModifyElementFromStoragePool',
scs.path, **in_params)))
@@ -1840,8 +1273,8 @@ class Smis(IStorageAreaNetwork):
"""
rc = [None, None]

- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system_id, raise_error=False)
+ rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
+ system_id, raise_error=False)

if rs:
rs_cap = self._c.Associators(
@@ -1852,30 +1285,30 @@ class Smis(IStorageAreaNetwork):
s_rt = rs_cap['SupportedReplicationTypes']

if rep_type == Volume.REPLICATE_COPY:
- if self.RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt:
- rc[0] = Smis.SYNC_TYPE_CLONE
- rc[1] = Smis.CREATE_ELEMENT_REPLICA_MODE_SYNC
- elif self.RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
- rc[0] = Smis.SYNC_TYPE_CLONE
- rc[1] = Smis.CREATE_ELEMENT_REPLICA_MODE_ASYNC
+ if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt:
+ rc[0] = SYNC_TYPE_CLONE
+ rc[1] = CREATE_ELEMENT_REPLICA_MODE_SYNC
+ elif RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
+ rc[0] = SYNC_TYPE_CLONE
+ rc[1] = CREATE_ELEMENT_REPLICA_MODE_ASYNC

elif rep_type == Volume.REPLICATE_MIRROR_ASYNC:
- if self.RepSvc.RepTypes.ASYNC_MIRROR_LOCAL in s_rt:
- rc[0] = Smis.SYNC_TYPE_MIRROR
- rc[1] = Smis.CREATE_ELEMENT_REPLICA_MODE_ASYNC
+ if RepSvc.RepTypes.ASYNC_MIRROR_LOCAL in s_rt:
+ rc[0] = SYNC_TYPE_MIRROR
+ rc[1] = CREATE_ELEMENT_REPLICA_MODE_ASYNC

elif rep_type == Volume.REPLICATE_MIRROR_SYNC:
- if self.RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
- rc[0] = Smis.SYNC_TYPE_MIRROR
- rc[1] = Smis.CREATE_ELEMENT_REPLICA_MODE_SYNC
+ if RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
+ rc[0] = SYNC_TYPE_MIRROR
+ rc[1] = CREATE_ELEMENT_REPLICA_MODE_SYNC

elif rep_type == Volume.REPLICATE_CLONE:
- if self.RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt:
- rc[0] = Smis.SYNC_TYPE_SNAPSHOT
- rc[1] = Smis.CREATE_ELEMENT_REPLICA_MODE_SYNC
- elif self.RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
- rc[0] = Smis.SYNC_TYPE_SNAPSHOT
- rc[1] = Smis.CREATE_ELEMENT_REPLICA_MODE_ASYNC
+ if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt:
+ rc[0] = SYNC_TYPE_SNAPSHOT
+ rc[1] = CREATE_ELEMENT_REPLICA_MODE_SYNC
+ elif RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
+ rc[0] = SYNC_TYPE_SNAPSHOT
+ rc[1] = CREATE_ELEMENT_REPLICA_MODE_ASYNC

if rc[0] is None:
raise LsmError(ErrorNumber.NO_SUPPORT,
@@ -1892,8 +1325,9 @@ class Smis(IStorageAreaNetwork):
or rep_type == Volume.REPLICATE_MIRROR_SYNC:
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")

- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- volume_src.system_id, raise_error=False)
+ rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
+ volume_src.system_id,
+ raise_error=False)

if pool is not None:
cim_pool = self._get_cim_instance_by_id('Pool', pool.id)
@@ -1913,7 +1347,7 @@ class Smis(IStorageAreaNetwork):
#'Mode': pywbem.Uint16(mode),
'SourceElement': lun.path,
'WaitForCopyState':
- pywbem.Uint16(Smis.CopyStates.SYNCHRONIZED)}
+ pywbem.Uint16(CopyStates.SYNCHRONIZED)}

else:
# Check for older support via storage configuration service
@@ -1921,19 +1355,19 @@ class Smis(IStorageAreaNetwork):
method = 'CreateReplica'

# Check for storage configuration service
- rs = self._get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', volume_src.system_id,
- raise_error=False)
+ rs = self._c.get_class_instance("CIM_StorageConfigurationService",
+ 'SystemName', volume_src.system_id,
+ raise_error=False)

ct = Volume.REPLICATE_CLONE
if rep_type == Volume.REPLICATE_CLONE:
- ct = Smis.CopyTypes.UNSYNCASSOC
+ ct = CopyTypes.UNSYNCASSOC
elif rep_type == Volume.REPLICATE_COPY:
- ct = Smis.CopyTypes.UNSYNCUNASSOC
+ ct = CopyTypes.UNSYNCUNASSOC
elif rep_type == Volume.REPLICATE_MIRROR_ASYNC:
- ct = Smis.CopyTypes.ASYNC
+ ct = CopyTypes.ASYNC
elif rep_type == Volume.REPLICATE_MIRROR_SYNC:
- ct = Smis.CopyTypes.SYNC
+ ct = CopyTypes.SYNC

in_params = {'ElementName': name,
'CopyType': pywbem.Uint16(ct),
@@ -1945,7 +1379,7 @@ class Smis(IStorageAreaNetwork):

try:

- return self._pi("volume_replicate", Smis.JOB_RETRIEVE_VOLUME,
+ return self._pi("volume_replicate", JOB_RETRIEVE_VOLUME,
*(self._c.InvokeMethod(method,
rs.path, **in_params)))
except CIMError:
@@ -1954,33 +1388,9 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")

- def _get_cim_service_path(self, cim_sys_path, class_name):
- """
- Return None if not supported
- """
- try:
- cim_srvs = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass=class_name)
- except CIMError as ce:
- if ce[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
- return None
- else:
- raise
- if len(cim_srvs) == 1:
- return cim_srvs[0]
- elif len(cim_srvs) == 0:
- return None
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_get_cim_service_path(): Got unexpected(not 1) "
- "count of %s from cim_sys %s: %s" %
- (class_name, cim_sys_path, cim_srvs))
-
def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
vol_id):
- rc = Smis.INVOKE_FAILED
+ rc = INVOKE_FAILED
out = None

in_params = {
@@ -2015,7 +1425,7 @@ class Smis(IStorageAreaNetwork):
we will mask to all target ports.
Return CIMInstanceName of CIM_TargetMaskingGroup
"""
- rc = Smis.INVOKE_FAILED
+ rc = INVOKE_FAILED
out = None

in_params = {
@@ -2109,7 +1519,7 @@ class Smis(IStorageAreaNetwork):
'Volume', volume.id, ['Name'],
raise_error=True)

- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')

cim_spcs_path = self._c.AssociatorNames(
@@ -2164,15 +1574,15 @@ class Smis(IStorageAreaNetwork):
"""
Grant access to a volume to an group
"""
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
# Workaround for EMC VNX/CX
- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = Smis.MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK

- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._volume_mask_group(access_group, volume, flags)
return self._volume_mask_old(access_group, volume, flags)

@@ -2189,13 +1599,13 @@ class Smis(IStorageAreaNetwork):

cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
- cim_css_path = self._get_cim_service_path(
+ cim_css_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

cim_vol = self._get_cim_instance_by_id(
'Volume', volume.id, ['Name'], raise_error=True)

- da = Smis.EXPOSE_PATHS_DA_READ_WRITE
+ da = EXPOSE_PATHS_DA_READ_WRITE

in_params = {'LUNames': [cim_vol['Name']],
'ProtocolControllers': [cim_spc.path],
@@ -2245,7 +1655,7 @@ class Smis(IStorageAreaNetwork):
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")

- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')

cim_spcs_path = self._c.AssociatorNames(
@@ -2308,22 +1718,22 @@ class Smis(IStorageAreaNetwork):

@handle_cim_errors
def volume_unmask(self, access_group, volume, flags=0):
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
# Workaround for EMC VNX/CX
- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = Smis.MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK

- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._volume_unmask_group(access_group, volume)
return self._volume_unmask_old(access_group, volume)

def _volume_unmask_old(self, access_group, volume):
cim_sys = self._get_cim_instance_by_id(
'System', access_group.system_id, raise_error=True)
- cim_ccs_path = self._get_cim_service_path(
+ cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

cim_vol = self._get_cim_instance_by_id(
@@ -2508,18 +1918,18 @@ class Smis(IStorageAreaNetwork):

@handle_cim_errors
def volumes_accessible_by_access_group(self, access_group, flags=0):
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vols = []
cim_vol_pros = self._cim_vol_pros()

# Workaround for EMC VNX/CX
- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', access_group.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = Smis.MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK

- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg = self._cim_init_mg_of_id(
access_group.id, raise_error=True)

@@ -2548,19 +1958,19 @@ class Smis(IStorageAreaNetwork):
@handle_cim_errors
def access_groups_granted_to_volume(self, volume, flags=0):
rc = []
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vol = self._get_cim_instance_by_id(
'Volume', volume.id, raise_error=True)

# Workaround for EMC VNX/CX
- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = Smis.MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK

cim_spc_pros = None
- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_spc_pros = []
else:
cim_spc_pros = self._cim_spc_pros()
@@ -2571,7 +1981,7 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_SCSIProtocolController',
PropertyList=cim_spc_pros)

- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg_pros = self._cim_init_mg_pros()
for cim_spc in cim_spcs:
cim_init_mgs = self._c.Associators(
@@ -2630,7 +2040,7 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = []

- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys_path, 'CIM_GroupMaskingMappingService')

return self._c.Associators(
@@ -2639,35 +2049,10 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)

- def _mask_type(self, raise_error=False):
- """
- Return Smis.MASK_TYPE_NO_SUPPORT, MASK_TYPE_MASK or MASK_TYPE_GROUP
- if 'Group Masking and Mapping' profile is supported, return
- MASK_TYPE_GROUP
-
- If raise_error == False, just return Smis.MASK_TYPE_NO_SUPPORT
- or, raise NO_SUPPORT error.
- """
- if self._c.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_5,
- raise_error=False):
- return Smis.MASK_TYPE_GROUP
- if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return Smis.MASK_TYPE_MASK
- if raise_error:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Target SMI-S provider does not support "
- "%s version %s or %s version %s" %
- (SmisCommon.SNIA_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_4,
- SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5))
- return Smis.MASK_TYPE_NO_SUPPORT
-
@handle_cim_errors
def access_groups(self, search_key=None, search_value=None, flags=0):
rc = []
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)

cim_sys_pros = self._property_list_of_id('System')
cim_syss = self._root_cim_syss(cim_sys_pros)
@@ -2678,16 +2063,16 @@ class Smis(IStorageAreaNetwork):
# Workaround for EMC VNX/CX.
# Even they claim support of Group M&M via
# CIM_RegisteredProfile, but actually they don't support it.
- mask_type = Smis.MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK

system_id = self._sys_id(cim_sys)
- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg_pros = self._cim_init_mg_pros()
cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
cim_init_mg_pros)
rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
for x in cim_init_mgs))
- elif mask_type == Smis.MASK_TYPE_MASK:
+ elif mask_type == smis_cap.MASK_TYPE_MASK:
cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
rc.extend(
list(self._cim_spc_to_lsm(cim_spc, system_id)
@@ -2725,7 +2110,7 @@ class Smis(IStorageAreaNetwork):
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._get_cim_service_path(
+ cim_hw_srv_path = self._c.get_cim_service_path(
cim_sys_path, 'CIM_StorageHardwareIDManagementService')

in_params = {'StorageID': init_id,
@@ -2763,7 +2148,7 @@ class Smis(IStorageAreaNetwork):
cim_init_path = self._cim_init_path_check_or_create(
cim_sys.path, init_id, init_type)

- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')

in_params = {
@@ -2787,9 +2172,9 @@ class Smis(IStorageAreaNetwork):
def access_group_initiator_add(self, access_group, init_id, init_type,
flags=0):
init_id = _lsm_init_id_to_snia(init_id)
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)

- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._ag_init_add_group(access_group, init_id, init_type)
else:
return self._ag_init_add_old(access_group, init_id, init_type)
@@ -2822,7 +2207,7 @@ class Smis(IStorageAreaNetwork):

self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)

- cim_ccs_path = self._get_cim_service_path(
+ cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

in_params = {'InitiatorPortIDs': [init_id],
@@ -2871,7 +2256,7 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")

- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')

# RemoveMembers from InitiatorMaskingGroup
@@ -2898,9 +2283,9 @@ class Smis(IStorageAreaNetwork):
"SMI-S plugin does not support "
"access_group_initiator_delete() against NetApp-E")
init_id = _lsm_init_id_to_snia(init_id)
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)

- if mask_type == Smis.MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._ag_init_del_group(access_group, init_id)
else:
return self._ag_init_del_old(access_group, init_id)
@@ -2911,7 +2296,7 @@ class Smis(IStorageAreaNetwork):

cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)

- cim_ccs_path = self._get_cim_service_path(
+ cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

hide_params = {'InitiatorPortIDs': [init_id],
@@ -3023,7 +2408,7 @@ class Smis(IStorageAreaNetwork):

if disk_type == Disk.TYPE_UNKNOWN and 'DiskType' in cim_disk:
disk_type = \
- Smis.dmtf_disk_type_2_lsm_disk_type(cim_disk['DiskType'])
+ dmtf_disk_type_2_lsm_disk_type(cim_disk['DiskType'])

# LSI way for checking disk type
if not disk_type and cim_disk.classname == 'LSIESG_DiskDrive':
@@ -3137,11 +2522,11 @@ class Smis(IStorageAreaNetwork):
if 'SupportedStorageElementFeatures' in cim_scc:
supported_features = cim_scc['SupportedStorageElementFeatures']

- if Smis.DMTF_SUPPORT_VOL_CREATE in supported_features:
+ if DMTF_SUPPORT_VOL_CREATE in supported_features:
element_type |= Pool.ELEMENT_TYPE_VOLUME
- if Smis.DMTF_SUPPORT_ELEMENT_EXPAND not in supported_features:
+ if DMTF_SUPPORT_ELEMENT_EXPAND not in supported_features:
unsupported |= Pool.UNSUPPORTED_VOLUME_GROW
- if Smis.DMTF_SUPPORT_ELEMENT_REDUCE not in supported_features:
+ if DMTF_SUPPORT_ELEMENT_REDUCE not in supported_features:
unsupported |= Pool.UNSUPPORTED_VOLUME_SHRINK

else:
@@ -3162,12 +2547,12 @@ class Smis(IStorageAreaNetwork):
if 'Usage' in cim_pool:
usage = cim_pool['Usage']

- if usage == Smis.DMTF_POOL_USAGE_UNRESTRICTED:
+ if usage == DMTF_POOL_USAGE_UNRESTRICTED:
element_type |= Pool.ELEMENT_TYPE_VOLUME
- if usage == Smis.DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM or \
- usage > Smis.DMTF_POOL_USAGE_DELTA:
+ if usage == DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM or \
+ usage > DMTF_POOL_USAGE_DELTA:
element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
- if usage == Smis.DMTF_POOL_USAGE_DELTA:
+ if usage == DMTF_POOL_USAGE_DELTA:
# We blitz all the other elements types for this designation
element_type = Pool.ELEMENT_TYPE_DELTA

@@ -3218,54 +2603,6 @@ class Smis(IStorageAreaNetwork):
else:
return cim_syss

- def _fc_tgt_is_supported(self, cim_sys_path):
- """
- Return True if FC Target Port 1.4+ profile is supported.
- """
- flag_fc_support = self._c.profile_check(
- SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- # One more check for NetApp Typo:
- # NetApp: 'FC Target Port'
- # SMI-S: 'FC Target Ports'
- # Bug reported.
- if not flag_fc_support:
- flag_fc_support = self._c.profile_check(
- 'FC Target Port',
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- if flag_fc_support:
- return True
- else:
- return False
-
- def _iscsi_tgt_is_supported(self, cim_sys_path):
- """
- Return True if FC Target Port 1.4+ profile is supported.
- We use CIM_iSCSIProtocolEndpoint as it's a start point we are
- using in our code of target_ports().
- """
- if self._c.profile_check(SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return True
- return False
-
- def _multi_sys_is_supported(self):
- """
- Return True if Multiple ComputerSystem 1.4+ profile is supported.
- Return False else.
- """
- flag_multi_sys_support = self._c.profile_check(
- SmisCommon.SNIA_MULTI_SYS_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- if flag_multi_sys_support:
- return True
- else:
- return False
-
@staticmethod
def _is_frontend_fc_tgt(cim_fc_tgt):
"""
@@ -3288,7 +2625,7 @@ class Smis(IStorageAreaNetwork):
else:
property_list = merge_list(property_list, ['UsageRestriction'])
all_cim_syss_path = [cim_sys_path]
- if self._multi_sys_is_supported():
+ if smis_cap.multi_sys_is_supported(self._c):
all_cim_syss_path.extend(
self._leaf_cim_syss_path_of(cim_sys_path))
for cur_cim_sys_path in all_cim_syss_path:
@@ -3311,7 +2648,7 @@ class Smis(IStorageAreaNetwork):
port_type = _lsm_tgt_port_type_of_cim_fc_tgt(cim_fc_tgt)
# SNIA define WWPN string as upper, no splitter, 16 digits.
# No need to check.
- wwpn = _hex_string_format(cim_fc_tgt['PermanentAddress'], 16, 2)
+ wwpn = hex_string_format(cim_fc_tgt['PermanentAddress'], 16, 2)
port_name = cim_fc_tgt['ElementName']
plugin_data = None
return TargetPort(port_id, port_type, wwpn, wwpn, wwpn, port_name,
@@ -3367,7 +2704,7 @@ class Smis(IStorageAreaNetwork):
else:
property_list = merge_list(property_list, ['Role'])
all_cim_syss_path = [cim_sys_path]
- if self._multi_sys_is_supported():
+ if smis_cap.multi_sys_is_supported(self._c):
all_cim_syss_path.extend(
self._leaf_cim_syss_path_of(cim_sys_path))
for cur_cim_sys_path in all_cim_syss_path:
@@ -3486,7 +2823,7 @@ class Smis(IStorageAreaNetwork):
port_name = nic[1]
if mac_address:
# Convert to lsm require form
- mac_address = _hex_string_format(mac_address, 12, 2)
+ mac_address = hex_string_format(mac_address, 12, 2)

if ipv4_addr:
network_address = "%s:%s" % (ipv4_addr, tcp_port)
@@ -3503,7 +2840,7 @@ class Smis(IStorageAreaNetwork):
if len(ipv6_addr) == 39:
ipv6_addr = ipv6_addr.replace(':', '')
if len(ipv6_addr) == 32:
- ipv6_addr = _hex_string_format(
+ ipv6_addr = hex_string_format(
ipv6_addr, 32, 4)

network_address = "[%s]:%s" % (ipv6_addr, tcp_port)
@@ -3557,8 +2894,8 @@ class Smis(IStorageAreaNetwork):
property_list=self._property_list_of_id('System'))
for cim_sys in cim_syss:
system_id = self._sys_id(cim_sys)
- flag_fc_support = self._fc_tgt_is_supported(cim_sys.path)
- flag_iscsi_support = self._iscsi_tgt_is_supported(cim_sys.path)
+ flag_fc_support = smis_cap.fc_tgt_is_supported(self._c)
+ flag_iscsi_support = smis_cap.iscsi_tgt_is_supported(self._c)

# Assuming: if one system does not support target_ports(),
# all systems from the same provider will not support
@@ -3630,7 +2967,7 @@ class Smis(IStorageAreaNetwork):
Return CIM_InstanceName
Assuming only one CIM_InstanceName will get.
"""
- if rc == Smis.INVOKE_OK:
+ if rc == INVOKE_OK:
if out_key is None:
return None
if out_key in out:
@@ -3645,7 +2982,7 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.PLUGIN_BUG,
"_wait_invoke(), %s not exist in out %s" %
(out_key, out.items()))
- elif rc == Smis.INVOKE_ASYNC:
+ elif rc == INVOKE_ASYNC:
cim_job_path = out['Job']
loop_counter = 0
job_pros = ['JobState', 'PercentComplete', 'ErrorDescription',
@@ -3656,12 +2993,12 @@ class Smis(IStorageAreaNetwork):
PropertyList=job_pros,
LocalOnly=False)
job_state = cim_job['JobState']
- if job_state in (Smis.JS_NEW, Smis.JS_STARTING,
- Smis.JS_RUNNING):
+ if job_state in (JS_NEW, JS_STARTING,
+ JS_RUNNING):
loop_counter += 1
time.sleep(Smis._INVOKE_CHECK_INTERVAL)
continue
- elif job_state == Smis.JS_COMPLETED:
+ elif job_state == JS_COMPLETED:
if expect_class is None:
return None
cim_xxxs_path = self._c.AssociatorNames(
@@ -3788,8 +3125,8 @@ class Smis(IStorageAreaNetwork):
"EMC VNX/CX which lacks the support of SNIA 1.5+ "
"Group Masking and Mapping profile")

- flag_fc_support = self._fc_tgt_is_supported(cim_sys.path)
- flag_iscsi_support = self._iscsi_tgt_is_supported(cim_sys.path)
+ flag_fc_support = smis_cap.fc_tgt_is_supported(self._c)
+ flag_iscsi_support = smis_cap.iscsi_tgt_is_supported(self._c)

if init_type == AccessGroup.INIT_TYPE_WWPN and not flag_fc_support:
raise LsmError(ErrorNumber.NO_SUPPORT,
@@ -3808,7 +3145,7 @@ class Smis(IStorageAreaNetwork):
cim_sys.path, init_id, init_type)

# Create CIM_InitiatorMaskingGroup
- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')

in_params = {'GroupName': name,
@@ -3866,6 +3203,7 @@ class Smis(IStorageAreaNetwork):
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
return self._cim_init_mg_to_lsm(cim_init_mg, system.id)

+ @handle_cim_errors
def access_group_delete(self, access_group, flags=0):
self._c.profile_check(
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
new file mode 100644
index 0000000..ae11460
--- /dev/null
+++ b/plugin/smispy/smis_cap.py
@@ -0,0 +1,398 @@
+# 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
+# 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
+
+from lsm import Capabilities, LsmError, ErrorNumber
+from smis_constants import *
+from dmtf import *
+from smis_common import SmisCommon
+
+MASK_TYPE_NO_SUPPORT = 0
+MASK_TYPE_MASK = 1
+MASK_TYPE_GROUP = 2
+
+
+def _rs_supported_capabilities(smis_common, system, cap):
+ """
+ Interrogate the supported features of the replication service
+ """
+ rs = smis_common.get_class_instance("CIM_ReplicationService", 'SystemName',
+ system.id, raise_error=False)
+ if rs:
+ rs_cap = smis_common.Associators(
+ rs.path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_ReplicationServiceCapabilities')[0]
+
+ s_rt = rs_cap['SupportedReplicationTypes']
+
+ if RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt or \
+ RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt:
+ cap.set(Capabilities.VOLUME_REPLICATE)
+
+ # Mirror support is not working and is not supported at this time.
+ # if RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
+ # cap.set(Capabilities.DeviceID)
+
+ # if RepSvc.RepTypes.ASYNC_MIRROR_LOCAL \
+ # in s_rt:
+ # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
+
+ if RepSvc.RepTypes.SYNC_SNAPSHOT_LOCAL in s_rt or \
+ RepSvc.RepTypes.ASYNC_SNAPSHOT_LOCAL in s_rt:
+ cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
+
+ if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt or \
+ RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
+ cap.set(Capabilities.VOLUME_REPLICATE_COPY)
+ else:
+ # Try older storage configuration service
+
+ rs = smis_common.get_class_instance("CIM_StorageConfigurationService",
+ 'SystemName', system.id,
+ raise_error=False)
+
+ if rs:
+ rs_cap = smis_common.Associators(
+ rs.path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_StorageConfigurationCapabilities')[0]
+
+ if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
+ sct = rs_cap['SupportedCopyTypes']
+
+ if sct and len(sct):
+ cap.set(Capabilities.VOLUME_REPLICATE)
+
+ # Mirror support is not working and is not supported at
+ # this time.
+
+ # if CopyTypes.ASYNC in sct:
+ # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
+
+ # if CopyTypes.SYNC in sct:
+ # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_SYNC)
+
+ if CopyTypes.UNSYNCASSOC in sct:
+ cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
+
+ if CopyTypes.UNSYNCUNASSOC in sct:
+ cap.set(Capabilities.VOLUME_REPLICATE_COPY)
+
+
+def _bsp_cap_set(smis_common, cim_sys_path, cap):
+ """
+ Set capabilities for these methods:
+ volumes()
+ volume_create()
+ volume_resize()
+ volume_delete()
+ """
+ # CIM_StorageConfigurationService is optional.
+ cim_scs_path = smis_common.get_cim_service_path(
+ cim_sys_path, 'CIM_StorageConfigurationService')
+
+ if cim_scs_path is None:
+ return
+
+ # These methods are mandatory for CIM_StorageConfigurationService:
+ # CreateOrModifyElementFromStoragePool()
+ # ReturnToStoragePool()
+ # But SNIA never defined which function of
+ # CreateOrModifyElementFromStoragePool() is mandatory.
+ # Hence we check CIM_StorageConfigurationCapabilities
+ # which is mandatory if CIM_StorageConfigurationService is supported.
+ cim_scs_cap = smis_common.Associators(
+ cim_scs_path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedAsynchronousActions',
+ 'SupportedSynchronousActions',
+ 'SupportedStorageElementTypes'])[0]
+
+ element_types = cim_scs_cap['SupportedStorageElementTypes']
+ sup_actions = []
+
+ if 'SupportedSynchronousActions' in cim_scs_cap:
+ if cim_scs_cap['SupportedSynchronousActions']:
+ sup_actions.extend(cim_scs_cap['SupportedSynchronousActions'])
+
+ if 'SupportedAsynchronousActions' in cim_scs_cap:
+ if cim_scs_cap['SupportedAsynchronousActions']:
+ sup_actions.extend(cim_scs_cap['SupportedAsynchronousActions'])
+
+ if DMTF.SCS_CAP_SUP_ST_VOLUME in element_types or \
+ DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
+ cap.set(Capabilities.VOLUMES)
+ if DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
+ cap.set(Capabilities.VOLUME_THIN)
+
+ if DMTF.SCS_CAP_VOLUME_CREATE in sup_actions:
+ cap.set(Capabilities.VOLUME_CREATE)
+
+ if DMTF.SCS_CAP_VOLUME_DELETE in sup_actions:
+ cap.set(Capabilities.VOLUME_DELETE)
+
+ if DMTF.SCS_CAP_VOLUME_MODIFY in sup_actions:
+ cap.set(Capabilities.VOLUME_RESIZE)
+
+ return
+
+
+def _disk_cap_set(smis_common, cim_sys_path, cap):
+ if not smis_common.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return
+
+ cap.set(Capabilities.DISKS)
+ return
+
+
+def _group_mask_map_cap_set(smis_common, cim_sys_path, cap):
+ """
+ We set caps for these methods recording to 1.5+ Group M&M profile:
+ access_groups()
+ access_groups_granted_to_volume()
+ volumes_accessible_by_access_group()
+ access_group_initiator_add()
+ access_group_initiator_delete()
+ volume_mask()
+ volume_unmask()
+ access_group_create()
+ access_group_delete()
+ """
+ # These are mandatory in SNIA SMI-S.
+ # We are not in the position of SNIA SMI-S certification.
+ cap.set(Capabilities.ACCESS_GROUPS)
+ cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
+ cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
+ cap.set(Capabilities.VOLUME_MASK)
+ if fc_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
+ cap.set(Capabilities.ACCESS_GROUP_CREATE_WWPN)
+ if iscsi_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
+ cap.set(Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN)
+
+ # RemoveMembers is also mandatory
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
+
+ cim_gmm_cap_pros = [
+ 'SupportedAsynchronousActions',
+ 'SupportedSynchronousActions',
+ 'SupportedDeviceGroupFeatures']
+
+ cim_gmm_cap = smis_common.Associators(
+ cim_sys_path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_GroupMaskingMappingCapabilities',
+ PropertyList=cim_gmm_cap_pros)[0]
+
+ # if empty dev group in spc is allowed, RemoveMembers() is enough
+ # to do volume_unmask(). RemoveMembers() is mandatory.
+ if DMTF.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
+ cim_gmm_cap['SupportedDeviceGroupFeatures']:
+ cap.set(Capabilities.VOLUME_UNMASK)
+
+ # DeleteMaskingView() is optional, this is required by volume_unmask()
+ # when empty dev group in spc not allowed.
+ elif ((DMTF.GMM_CAP_DELETE_SPC in
+ cim_gmm_cap['SupportedSynchronousActions']) or
+ (DMTF.GMM_CAP_DELETE_SPC in
+ cim_gmm_cap['SupportedAsynchronousActions'])):
+ cap.set(Capabilities.VOLUME_UNMASK)
+
+ # DeleteGroup is optional, this is required by access_group_delete()
+ if ((DMTF.GMM_CAP_DELETE_GROUP in
+ cim_gmm_cap['SupportedSynchronousActions']) or
+ (DMTF.GMM_CAP_DELETE_GROUP in
+ cim_gmm_cap['SupportedAsynchronousActions'])):
+ cap.set(Capabilities.ACCESS_GROUP_DELETE)
+ return None
+
+
+def _mask_map_cap_set(smis_common, cim_sys_path, cap):
+ """
+ In SNIA SMI-S 1.4rev6 'Masking and Mapping' profile:
+ CIM_ControllerConfigurationService is mandatory
+ and it's ExposePaths() and HidePaths() are mandatory
+ """
+ if not smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return
+
+ cap.set(Capabilities.ACCESS_GROUPS)
+ cap.set(Capabilities.VOLUME_MASK)
+ cap.set(Capabilities.VOLUME_UNMASK)
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
+ cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
+ cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
+
+ # EMC VNX does not support CreateStorageHardwareID for iSCSI
+ # and require WWNN for WWPN. Hence both are not supported.
+ if cim_sys_path.classname == 'Clar_StorageSystem':
+ return
+
+ if fc_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
+ if iscsi_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
+ return
+
+
+def _tgt_cap_set(smis_common, cim_sys_path, cap):
+
+ # LSI MegaRAID actually not support FC Target and iSCSI target,
+ # They expose empty list of CIM_FCPort
+ if cim_sys_path.classname == 'LSIESG_MegaRAIDHBA':
+ return
+
+ flag_fc_support = smis_common.profile_check(
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ # One more check for NetApp Typo:
+ # NetApp: 'FC Target Port'
+ # SMI-S: 'FC Target Ports'
+ # Bug reported.
+ if not flag_fc_support:
+ flag_fc_support = smis_common.profile_check(
+ 'FC Target Port',
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ flag_iscsi_support = smis_common.profile_check(
+ SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+
+ if flag_fc_support or flag_iscsi_support:
+ cap.set(Capabilities.TARGET_PORTS)
+ return
+
+
+def mask_type(smis_common, raise_error=False):
+ """
+ Return MASK_TYPE_NO_SUPPORT, MASK_TYPE_MASK or MASK_TYPE_GROUP
+ if 'Group Masking and Mapping' profile is supported, return
+ MASK_TYPE_GROUP
+
+ If raise_error == False, just return MASK_TYPE_NO_SUPPORT
+ or, raise NO_SUPPORT error.
+ """
+ if smis_common.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_5,
+ raise_error=False):
+ return MASK_TYPE_GROUP
+ if smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return MASK_TYPE_MASK
+ if raise_error:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support "
+ "%s version %s or %s version %s" %
+ (SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SNIA_GROUP_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_5))
+ return MASK_TYPE_NO_SUPPORT
+
+
+def fc_tgt_is_supported(smis_common):
+ """
+ Return True if FC Target Port 1.4+ profile is supported.
+ """
+ flag_fc_support = smis_common.profile_check(
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ # One more check for NetApp Typo:
+ # NetApp: 'FC Target Port'
+ # SMI-S: 'FC Target Ports'
+ # Bug reported.
+ if not flag_fc_support:
+ flag_fc_support = smis_common.profile_check(
+ 'FC Target Port',
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ if flag_fc_support:
+ return True
+ else:
+ return False
+
+
+def iscsi_tgt_is_supported(smis_common):
+ """
+ Return True if FC Target Port 1.4+ profile is supported.
+ We use CIM_iSCSIProtocolEndpoint as it's a start point we are
+ using in our code of target_ports().
+ """
+ if smis_common.profile_check(SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return True
+ return False
+
+
+def multi_sys_is_supported(smis_common):
+ """
+ Return True if Multiple ComputerSystem 1.4+ profile is supported.
+ Return False else.
+ """
+ flag_multi_sys_support = smis_common.profile_check(
+ SmisCommon.SNIA_MULTI_SYS_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ if flag_multi_sys_support:
+ return True
+ else:
+ return False
+
+
+def get(smis_common, cim_sys, system):
+ cap = Capabilities()
+
+ if smis_common.is_netappe():
+ _rs_supported_capabilities(smis_common, system, cap)
+
+ #TODO We need to investigate why our interrogation code doesn't
+ #work.
+ #The array is telling us one thing, but when we try to use it, it
+ #doesn't work
+ return cap
+
+ # 'Block Services Package' profile
+ _bsp_cap_set(smis_common, cim_sys.path, cap)
+
+ # 'Disk Drive Lite' profile
+ _disk_cap_set(smis_common, cim_sys.path, cap)
+
+ # 'Masking and Mapping' and 'Group Masking and Mapping' profiles
+ mt = mask_type(smis_common)
+ if cim_sys.path.classname == 'Clar_StorageSystem':
+ mt = MASK_TYPE_MASK
+
+ if mask_type == MASK_TYPE_GROUP:
+ _group_mask_map_cap_set(smis_common, cim_sys.path, cap)
+ else:
+ _mask_map_cap_set(smis_common, cim_sys.path, cap)
+
+ # 'FC Target Ports' and 'iSCSI Target Ports' profiles
+ _tgt_cap_set(smis_common, cim_sys.path, cap)
+
+ _rs_supported_capabilities(smis_common, system, cap)
+ return cap
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index cf01b8f..6f91b20 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -27,6 +27,7 @@ import pywbem

from dmtf import DMTF
from lsm import LsmError, ErrorNumber
+from utils import (merge_list)


def _profile_register_load(wbem_conn):
@@ -139,6 +140,7 @@ def _profile_spec_ver_to_num(spec_ver_str):
int(tmp_list[2]))
return None

+
class SmisCommon(object):
SNIA_BLK_ROOT_PROFILE = 'Array'
SNIA_BLK_SRVS_PROFILE = 'Block Services'
@@ -226,6 +228,65 @@ class SmisCommon(object):
return _profile_check(
self._profile_dict, profile_name, spec_ver, raise_error)

+ def get_class_instance(self, class_name, prop_name, prop_value,
+ raise_error=True, property_list=None):
+ """
+ Gets an instance of a class that optionally matches a specific
+ property name and value
+ """
+ instances = None
+ if property_list is None:
+ property_list = [prop_name]
+ else:
+ property_list = merge_list(property_list, [prop_name])
+
+ try:
+ cim_xxxs = self.EnumerateInstances(
+ class_name, PropertyList=property_list)
+ except CIMError as ce:
+ error_code = tuple(ce)[0]
+
+ if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
+ raise_error is False:
+ return None
+ else:
+ raise
+
+ for cim_xxx in cim_xxxs:
+ if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
+ return cim_xxx
+
+ if raise_error:
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Unable to find class instance %s " % class_name +
+ "with property %s " % prop_name +
+ "with value %s" % prop_value)
+ return None
+
+ def get_cim_service_path(self, cim_sys_path, class_name):
+ """
+ Return None if not supported
+ """
+ try:
+ cim_srvs = self.AssociatorNames(
+ cim_sys_path,
+ AssocClass='CIM_HostedService',
+ ResultClass=class_name)
+ except CIMError as ce:
+ if ce[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
+ return None
+ else:
+ raise
+ if len(cim_srvs) == 1:
+ return cim_srvs[0]
+ elif len(cim_srvs) == 0:
+ return None
+ else:
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "_get_cim_service_path(): Got unexpected(not 1) "
+ "count of %s from cim_sys %s: %s" %
+ (class_name, cim_sys_path, cim_srvs))
+
def _vendor_namespace(self):
if self.root_blk_cim_rp:
cim_syss_path = self._wbem_conn.AssociatorNames(
diff --git a/plugin/smispy/smis_constants.py b/plugin/smispy/smis_constants.py
new file mode 100644
index 0000000..0536cf5
--- /dev/null
+++ b/plugin/smispy/smis_constants.py
@@ -0,0 +1,132 @@
+# 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
+# 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
+
+ # SMI-S job 'JobState' enumerations
+(JS_NEW, JS_STARTING, JS_RUNNING, JS_SUSPENDED, JS_SHUTTING_DOWN,
+ JS_COMPLETED,
+ JS_TERMINATED, JS_KILLED, JS_EXCEPTION) = (2, 3, 4, 5, 6, 7, 8, 9, 10)
+
+# SMI-S job 'OperationalStatus' enumerations
+(JOB_OK, JOB_ERROR, JOB_STOPPED, JOB_COMPLETE) = (2, 6, 10, 17)
+
+# SMI-S invoke return values we are interested in
+# Reference: Page 54 in 1.5 SMI-S block specification
+(INVOKE_OK,
+ INVOKE_NOT_SUPPORTED,
+ INVOKE_TIMEOUT,
+ INVOKE_FAILED,
+ INVOKE_INVALID_PARAMETER,
+ INVOKE_IN_USE,
+ INVOKE_ASYNC,
+ INVOKE_SIZE_NOT_SUPPORTED) = (0, 1, 3, 4, 5, 6, 4096, 4097)
+
+# SMI-S replication enumerations
+(SYNC_TYPE_MIRROR, SYNC_TYPE_SNAPSHOT, SYNC_TYPE_CLONE) = (6, 7, 8)
+
+# DMTF 2.29.1 (which SNIA SMI-S 1.6 based on)
+# CIM_StorageVolume['NameFormat']
+VOL_NAME_FORMAT_OTHER = 1
+VOL_NAME_FORMAT_VPD83_NNA6 = 2
+VOL_NAME_FORMAT_VPD83_NNA5 = 3
+VOL_NAME_FORMAT_VPD83_TYPE2 = 4
+VOL_NAME_FORMAT_VPD83_TYPE1 = 5
+VOL_NAME_FORMAT_VPD83_TYPE0 = 6
+VOL_NAME_FORMAT_SNVM = 7
+VOL_NAME_FORMAT_NODE_WWN = 8
+VOL_NAME_FORMAT_NNA = 9
+VOL_NAME_FORMAT_EUI64 = 10
+VOL_NAME_FORMAT_T10VID = 11
+
+# CIM_StorageVolume['NameNamespace']
+VOL_NAME_SPACE_OTHER = 1
+VOL_NAME_SPACE_VPD83_TYPE3 = 2
+VOL_NAME_SPACE_VPD83_TYPE2 = 3
+VOL_NAME_SPACE_VPD83_TYPE1 = 4
+VOL_NAME_SPACE_VPD80 = 5
+VOL_NAME_SPACE_NODE_WWN = 6
+VOL_NAME_SPACE_SNVM = 7
+
+JOB_RETRIEVE_NONE = 0
+JOB_RETRIEVE_VOLUME = 1
+JOB_RETRIEVE_POOL = 2
+
+IAAN_WBEM_HTTP_PORT = 5988
+IAAN_WBEM_HTTPS_PORT = 5989
+
+
+class RepSvc(object):
+
+ class Action(object):
+ CREATE_ELEMENT_REPLICA = 2
+
+ class RepTypes(object):
+ # SMI-S replication service capabilities
+ SYNC_MIRROR_LOCAL = 2
+ ASYNC_MIRROR_LOCAL = 3
+ SYNC_MIRROR_REMOTE = 4
+ ASYNC_MIRROR_REMOTE = 5
+ SYNC_SNAPSHOT_LOCAL = 6
+ ASYNC_SNAPSHOT_LOCAL = 7
+ SYNC_SNAPSHOT_REMOTE = 8
+ ASYNC_SNAPSHOT_REMOTE = 9
+ SYNC_CLONE_LOCAL = 10
+ ASYNC_CLONE_LOCAL = 11
+ SYNC_CLONE_REMOTE = 12
+ ASYNC_CLONE_REMOTE = 13
+
+
+class CopyStates(object):
+ INITIALIZED = 2
+ UNSYNCHRONIZED = 3
+ SYNCHRONIZED = 4
+ INACTIVE = 8
+
+
+class CopyTypes(object):
+ ASYNC = 2 # Async. mirror
+ SYNC = 3 # Sync. mirror
+ UNSYNCASSOC = 4 # lsm Clone
+ UNSYNCUNASSOC = 5 # lsm Copy
+
+
+class Synchronized(object):
+ class SyncState(object):
+ INITIALIZED = 2
+ PREPAREINPROGRESS = 3
+ PREPARED = 4
+ RESYNCINPROGRESS = 5
+ SYNCHRONIZED = 6
+ FRACTURE_IN_PROGRESS = 7
+ QUIESCEINPROGRESS = 8
+ QUIESCED = 9
+ RESTORE_IN_PROGRESSS = 10
+ IDLE = 11
+ BROKEN = 12
+ FRACTURED = 13
+ FROZEN = 14
+ COPY_IN_PROGRESS = 15
+
+# SMI-S mode for mirror updates
+(CREATE_ELEMENT_REPLICA_MODE_SYNC,
+ CREATE_ELEMENT_REPLICA_MODE_ASYNC) = (2, 3)
+
+# SMI-S volume 'OperationalStatus' enumerations
+(VOL_OP_STATUS_OK, VOL_OP_STATUS_DEGRADED, VOL_OP_STATUS_ERR,
+ VOL_OP_STATUS_STARTING,
+ VOL_OP_STATUS_DORMANT) = (2, 3, 6, 8, 15)
+
+# SMI-S ExposePaths device access enumerations
+(EXPOSE_PATHS_DA_READ_WRITE, EXPOSE_PATHS_DA_READ_ONLY) = (2, 3)
\ No newline at end of file
diff --git a/plugin/smispy/utils.py b/plugin/smispy/utils.py
index 9b0bbbc..95332b8 100644
--- a/plugin/smispy/utils.py
+++ b/plugin/smispy/utils.py
@@ -15,5 +15,54 @@
#
# Author: Gris Ge <***@redhat.com>

+import traceback
+from lsm import (LsmError, ErrorNumber, error)
+from pywbem import (CIMError)
+import pywbem
+
+
def merge_list(list_a, list_b):
return list(set(list_a + list_b))
+
+
+def handle_cim_errors(method):
+ def cim_wrapper(*args, **kwargs):
+ try:
+ return method(*args, **kwargs)
+ except LsmError as lsm:
+ raise
+ except CIMError as ce:
+ error_code, desc = ce
+
+ if error_code == 0:
+ if 'Socket error' in desc:
+ if 'Errno 111' in desc:
+ raise LsmError(ErrorNumber.NETWORK_CONNREFUSED,
+ 'Connection refused')
+ if 'Errno 113' in desc:
+ raise LsmError(ErrorNumber.NETWORK_HOSTDOWN,
+ 'Host is down')
+ elif 'SSL error' in desc:
+ raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION,
+ desc)
+ elif 'The web server returned a bad status line':
+ raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION,
+ desc)
+ elif 'HTTP error' in desc:
+ raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION,
+ desc)
+ raise LsmError(ErrorNumber.PLUGIN_BUG, desc)
+ except pywbem.cim_http.AuthError as ae:
+ raise LsmError(ErrorNumber.PLUGIN_AUTH_FAILED, "Unauthorized user")
+ except pywbem.cim_http.Error as te:
+ raise LsmError(ErrorNumber.NETWORK_ERROR, str(te))
+ except Exception as e:
+ error("Unexpected exception:\n" + traceback.format_exc())
+ raise LsmError(ErrorNumber.PLUGIN_BUG, str(e),
+ traceback.format_exc())
+ return cim_wrapper
+
+
+def hex_string_format(hex_str, length, every):
+ hex_str = hex_str.lower()
+ return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:41 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Update plugin_test.py to read LSM_TEST_URI and LSM_TEST_PASSWORD
if command line arguments didn't provided URI and password.

* Update lsmenv to set LSM_TEST_URI and LSM_TEST_PASSWORD for given device
alias.

* Create a shortcut in lsmenv for plugin_test.py. Example:
lsmenv vnx plugin_test

* This patch just save my time of typing uri and password for plugin_test.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/plugin_test.py | 10 +++++++++-
tools/lsmenv | 40 ++++++++++++++++++++++++++++++----------
2 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/test/plugin_test.py b/test/plugin_test.py
index 1464a55..a79cc8f 100755
--- a/test/plugin_test.py
+++ b/test/plugin_test.py
@@ -28,6 +28,7 @@ import atexit
import sys
import yaml
import re
+import os
from lsm import LsmError, ErrorNumber

results = {}
@@ -1042,13 +1043,20 @@ if __name__ == "__main__":

parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--password', default=None)
- parser.add_argument('--uri', default='sim://')
+ parser.add_argument('--uri')
options, other_args = parser.parse_known_args()

if options.uri:
TestPlugin.URI = options.uri
+ elif os.getenv('LSM_TEST_URI'):
+ TestPlugin.URI = os.getenv('LSM_TEST_URI')
+ else:
+ TestPlugin.URI = 'sim://'
+

if options.password:
TestPlugin.PASSWORD = options.password
+ elif os.getenv('LSM_TEST_PASSWORD'):
+ TestPlugin.PASSWORD = os.getenv('LSM_TEST_PASSWORD')

unittest.main(argv=sys.argv[:1] + other_args)
diff --git a/tools/lsmenv b/tools/lsmenv
index 0cedfa3..da14eed 100755
--- a/tools/lsmenv
+++ b/tools/lsmenv
@@ -105,6 +105,24 @@ sub lsm_env_setup() {
$ENV{LD_LIBRARY_PATH} .= ":$c_binding_dir";
}

+sub set_uri($) {
+ my $uri = shift;
+ $ENV{LSMCLI_URI} = $uri;
+ $ENV{LSM_TEST_URI} = $uri;
+}
+
+sub set_pass($) {
+ my $pass = shift;
+ if ( defined $pass ) {
+ $ENV{LSMCLI_PASSWORD} = $pass;
+ $ENV{LSM_TEST_PASSWORD} = $pass;
+ }
+ else {
+ delete $ENV{LSMCLI_PASSWORD};
+ delete $ENV{LSM_TEST_PASSWORD};
+ }
+}
+
sub call_out($) {

# take section name as $1 and global $cfg
@@ -116,26 +134,25 @@ sub call_out($) {
help();
}

+ my $uri;
+ my $pass = undef;
if ( is_in_array( [ keys( %{$REF_PRE_BUILD_URI} ) ], $dev_alias ) ) {
- $ENV{LSMCLI_URI} = $REF_PRE_BUILD_URI->{$dev_alias};
+ $uri = $REF_PRE_BUILD_URI->{$dev_alias};
}
else {
- my $uri = $URI_CFG->val( $dev_alias, 'uri' );
+ $uri = $URI_CFG->val( $dev_alias, 'uri' );
if ( $uri =~ /\n/m ) {
print "Duplicate settings for \"$dev_alias\"\n";
exit 1;
}
- $ENV{LSMCLI_URI} = $uri;
- unless ( $URI_CFG->val( $dev_alias, 'passwd' ) ) {
- delete $ENV{LSMCLI_PASSWORD};
- }
- else {
- $ENV{LSMCLI_PASSWORD} = $URI_CFG->val( $dev_alias, 'passwd' );
- }
+ $pass = $URI_CFG->val( $dev_alias, 'passwd' )
+ if $URI_CFG->val( $dev_alias, 'passwd' );
}

print "Device alias: $dev_alias\n";
- print "LSMCLI_URI: $ENV{LSMCLI_URI}\n";
+ print "URI: $uri\n";
+ set_uri($uri);
+ set_pass($pass);

my @cmd = @ARGV;
shift @cmd;
@@ -143,6 +160,9 @@ sub call_out($) {
if ( $cmd[0] eq "lsmcli" ) {
$cmd[0] = "$BASE_DIR/tools/lsmcli/lsmcli";
}
+ elsif ( $cmd[0] eq 'plugin_test' ) {
+ $cmd[0] = "$BASE_DIR/test/plugin_test.py";
+ }
system( "time", "-f", '\nTime: %E\n', @cmd );
my $rc = $? >> 8;
if ( $rc != 0 ) {
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:30 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Move dmtf.DMTF.OP_STATUS_XXX to dmtf.DMTF_OP_STATUS_XXX.
* Move dmtf.DMTF.dmtf_op_status_list_conv() to
dmtf.dmtf_op_status_list_conv()
* Move dmtf.DMTF.dmtf_op_status_to_str() to
dmtf._dmtf_op_status_to_str()
* Removed all dmtf.DMTF_STATUS_XXX constants as no method is
using it.
* Please use dmtf.DMTF_OP_STATUS_XXX instead if needed.
* Remove DMTF class as no __init__() or methods any more.
* All DMTF constants moved to dmtf.py file level.

Changes in V2:

* Remove 'DMTF_' prefix of constants in dmtf.py.
* Changed 'from dmtf import *' to 'import dmtf' in smis_xxx.py files.
* Renamed dmtf.dmtf_op_status_list_conv() to dmtf.op_status_list_conv()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/dmtf.py | 312 ++++++++++++++++++++-----------------------
plugin/smispy/smis.py | 42 +++---
plugin/smispy/smis_cap.py | 24 ++--
plugin/smispy/smis_common.py | 12 +-
plugin/smispy/smis_disk.py | 32 +++--
plugin/smispy/smis_pool.py | 32 ++---
plugin/smispy/smis_sys.py | 18 +--
7 files changed, 222 insertions(+), 250 deletions(-)

diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 8ebf06a..18a8a8f 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -18,191 +18,165 @@

# This class handle DMTF CIM constants and convert to LSM type.

-from lsm import (System, Pool, Disk)
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 ''
-
- @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)
-
-
- # 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['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)
-
- # DSP 1033 Profile Registration
- INTEROP_NAMESPACES = ['interop', 'root/interop', 'root/PG_Interop']
- DEFAULT_NAMESPACE = 'interop'
+# 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['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)
+
+# DSP 1033 Profile Registration
+INTEROP_NAMESPACES = ['interop', 'root/interop', 'root/PG_Interop']
+DEFAULT_NAMESPACE = 'interop'


# DMTF CIM 2.37.0 experimental CIM_StoragePool['Usage']
-DMTF_POOL_USAGE_UNRESTRICTED = 2
-DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM = 3
-DMTF_POOL_USAGE_DELTA = 4
-DMTF_POOL_USAGE_SPARE = 8
+POOL_USAGE_UNRESTRICTED = 2
+POOL_USAGE_RESERVED_FOR_SYSTEM = 3
+POOL_USAGE_DELTA = 4
+POOL_USAGE_SPARE = 8

# DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
# ['SupportedStorageElementFeatures']
-DMTF_SUPPORT_VOL_CREATE = 3
-DMTF_SUPPORT_ELEMENT_EXPAND = 12
-DMTF_SUPPORT_ELEMENT_REDUCE = 13
+SUPPORT_VOL_CREATE = 3
+SUPPORT_ELEMENT_EXPAND = 12
+SUPPORT_ELEMENT_REDUCE = 13

# DMTF CIM 2.37.0 experimental CIM_StorageConfigurationCapabilities
# ['SupportedStorageElementTypes']
-DMTF_ELEMENT_THICK_VOLUME = 2
-DMTF_ELEMENT_THIN_VOLUME = 5
+ELEMENT_THICK_VOLUME = 2
+ELEMENT_THIN_VOLUME = 5

# DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
# ['SupportedStoragePoolFeatures']
-DMTF_ST_POOL_FEATURE_INEXTS = 2
-DMTF_ST_POOL_FEATURE_SINGLE_INPOOL = 3
-DMTF_ST_POOL_FEATURE_MULTI_INPOOL = 4
+ST_POOL_FEATURE_INEXTS = 2
+ST_POOL_FEATURE_SINGLE_INPOOL = 3
+ST_POOL_FEATURE_MULTI_INPOOL = 4

# DMTF CIM 2.38.0+ CIM_StorageSetting['ThinProvisionedPoolType']
-DMTF_THINP_POOL_TYPE_ALLOCATED = Uint16(7)
+THINP_POOL_TYPE_ALLOCATED = Uint16(7)

# DMTF Disk Type
-DMTF_DISK_TYPE_UNKNOWN = 0
-DMTF_DISK_TYPE_OTHER = 1
-DMTF_DISK_TYPE_HDD = 2
-DMTF_DISK_TYPE_SSD = 3
-DMTF_DISK_TYPE_HYBRID = 4
-
-DMTF_STATUS_UNKNOWN = 0
-DMTF_STATUS_OTHER = 1
-DMTF_STATUS_OK = 2
-DMTF_STATUS_DEGRADED = 3
-DMTF_STATUS_STRESSED = 4
-DMTF_STATUS_PREDICTIVE_FAILURE = 5
-DMTF_STATUS_ERROR = 6
-DMTF_STATUS_NON_RECOVERABLE_ERROR = 7
-DMTF_STATUS_STARTING = 8
-DMTF_STATUS_STOPPING = 9
-DMTF_STATUS_STOPPED = 10
-DMTF_STATUS_IN_SERVICE = 11
-DMTF_STATUS_NO_CONTACT = 12
-DMTF_STATUS_LOST_COMMUNICATION = 13
-DMTF_STATUS_ABORTED = 14
-DMTF_STATUS_DORMANT = 15
-DMTF_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16
-DMTF_STATUS_COMPLETED = 17
-DMTF_STATUS_POWER_MODE = 18
+DISK_TYPE_UNKNOWN = 0
+DISK_TYPE_OTHER = 1
+DISK_TYPE_HDD = 2
+DISK_TYPE_SSD = 3
+DISK_TYPE_HYBRID = 4
+
+# 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",
+}
+
+def _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 _OP_STATUS_STR_CONV[dmtf_op_status]
+ except KeyError:
+ return ''
+
+def 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 _OP_STATUS_STR_CONV.keys():
+ status |= other_value
+ status_info_list.append(_op_status_to_str(dmtf_op_status))
+ continue
+ if status == 0:
+ status = unknown_value
+ return status, " ".join(status_info_list)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 351de57..2cee221 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -33,13 +33,13 @@ import smis_cap
import smis_sys
import smis_pool
import smis_disk
+import dmtf

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
JobStatus, md5, Volume, AccessGroup,
VERSION, TargetPort,
search_property)

-from dmtf import *
from utils import (merge_list, handle_cim_errors, hex_string_format)

from smis_common import SmisCommon
@@ -99,9 +99,9 @@ def _lsm_init_id_to_snia(lsm_init_id):

def _dmtf_init_type_to_lsm(cim_init):
if 'IDType' in cim_init:
- if cim_init['IDType'] == DMTF.ID_TYPE_WWPN:
+ if cim_init['IDType'] == dmtf.ID_TYPE_WWPN:
return AccessGroup.INIT_TYPE_WWPN
- elif cim_init['IDType'] == DMTF.ID_TYPE_ISCSI:
+ elif cim_init['IDType'] == dmtf.ID_TYPE_ISCSI:
return AccessGroup.INIT_TYPE_ISCSI_IQN
return AccessGroup.INIT_TYPE_UNKNOWN

@@ -115,19 +115,19 @@ def _lsm_tgt_port_type_of_cim_fc_tgt(cim_fc_tgt):
# for FCoE target port.
if 'PortDiscriminator' in cim_fc_tgt and \
cim_fc_tgt['PortDiscriminator'] and \
- DMTF.FC_PORT_PORT_DISCRIMINATOR_FCOE in cim_fc_tgt['PortDiscriminator']:
+ dmtf.FC_PORT_PORT_DISCRIMINATOR_FCOE in cim_fc_tgt['PortDiscriminator']:
return TargetPort.TYPE_FCOE
if 'LinkTechnology' in cim_fc_tgt and \
- cim_fc_tgt['LinkTechnology'] == DMTF.NET_PORT_LINK_TECH_ETHERNET:
+ cim_fc_tgt['LinkTechnology'] == dmtf.NET_PORT_LINK_TECH_ETHERNET:
return TargetPort.TYPE_FCOE
return TargetPort.TYPE_FC


def _lsm_init_type_to_dmtf(init_type):
if init_type == AccessGroup.INIT_TYPE_WWPN:
- return DMTF.ID_TYPE_WWPN
+ return dmtf.ID_TYPE_WWPN
if init_type == AccessGroup.INIT_TYPE_ISCSI_IQN:
- return DMTF.ID_TYPE_ISCSI
+ return dmtf.ID_TYPE_ISCSI
raise LsmError(ErrorNumber.NO_SUPPORT,
"Does not support provided init_type: %d" % init_type)

@@ -584,7 +584,7 @@ class Smis(IStorageAreaNetwork):
if not (nf and nn and name):
return None
# SNIA might have miss documented VPD83Type3(1), it should be
- # VOL_NAME_FORMAT_OTHER(1) based on DMTF.
+ # VOL_NAME_FORMAT_OTHER(1) based on dmtf.
# Will remove the Smis.VOL_NAME_FORMAT_OTHER condition if confirmed as
# SNIA document fault.
if (nf == VOL_NAME_FORMAT_NNA and
@@ -1204,7 +1204,7 @@ class Smis(IStorageAreaNetwork):
in_params = {
'GroupName': name,
'Members': [cim_vol_path],
- 'Type': DMTF.MASK_GROUP_TYPE_DEV}
+ 'Type': dmtf.MASK_GROUP_TYPE_DEV}

cim_dev_mg_path = None
try:
@@ -1238,7 +1238,7 @@ class Smis(IStorageAreaNetwork):

in_params = {
'GroupName': name,
- 'Type': DMTF.MASK_GROUP_TYPE_TGT}
+ 'Type': dmtf.MASK_GROUP_TYPE_TGT}

if init_type == AccessGroup.INIT_TYPE_WWPN:
cim_fc_tgts = self._cim_fc_tgt_of(cim_sys_path)
@@ -1443,14 +1443,14 @@ class Smis(IStorageAreaNetwork):

flag_empty_dev_in_spc = False

- if DMTF.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
+ if dmtf.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
cim_gmm_cap['SupportedDeviceGroupFeatures']:
flag_empty_dev_in_spc = True

if flag_empty_dev_in_spc is False:
- if ((DMTF.GMM_CAP_DELETE_SPC not in
+ if ((dmtf.GMM_CAP_DELETE_SPC not in
cim_gmm_cap['SupportedSynchronousActions']) and
- (DMTF.GMM_CAP_DELETE_SPC not in
+ (dmtf.GMM_CAP_DELETE_SPC not in
cim_gmm_cap['SupportedAsynchronousActions'])):
raise LsmError(
ErrorNumber.NO_SUPPORT,
@@ -2154,8 +2154,8 @@ class Smis(IStorageAreaNetwork):
Check CIM_FCPort['UsageRestriction'] for frontend port.
"""
dmtf_usage = cim_fc_tgt['UsageRestriction']
- if dmtf_usage == DMTF.TGT_PORT_USAGE_FRONTEND_ONLY or \
- dmtf_usage == DMTF.TGT_PORT_USAGE_UNRESTRICTED:
+ if dmtf_usage == dmtf.TGT_PORT_USAGE_FRONTEND_ONLY or \
+ dmtf_usage == dmtf.TGT_PORT_USAGE_UNRESTRICTED:
return True
return False

@@ -2223,7 +2223,7 @@ class Smis(IStorageAreaNetwork):
# EMC has vendor specific class which contain identical
# properties of SPC for iSCSI node.
continue
- if cim_spc['NameFormat'] == DMTF.SPC_NAME_FORMAT_ISCSI:
+ if cim_spc['NameFormat'] == dmtf.SPC_NAME_FORMAT_ISCSI:
cim_iscsi_nodes.extend([cim_spc])

if len(cim_iscsi_nodes) == 0:
@@ -2259,7 +2259,7 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_iSCSIProtocolEndpoint',
PropertyList=property_list)
for cim_iscsi_pg in cur_cim_iscsi_pgs:
- if cim_iscsi_pg['Role'] == DMTF.ISCSI_TGT_ROLE_TARGET:
+ if cim_iscsi_pg['Role'] == dmtf.ISCSI_TGT_ROLE_TARGET:
rc.extend([cim_iscsi_pg])
return rc

@@ -2325,9 +2325,9 @@ class Smis(IStorageAreaNetwork):
# Local Address.
if 'IPv6AddressType' in cim_ip and cim_ip['IPv6AddressType']:
ipv6_addr_type = cim_ip['IPv6AddressType']
- if ipv6_addr_type != DMTF.IPV6_ADDR_TYPE_GUA and \
- ipv6_addr_type != DMTF.IPV6_ADDR_TYPE_6TO4 and \
- ipv6_addr_type != DMTF.IPV6_ADDR_TYPE_ULA:
+ if ipv6_addr_type != dmtf.IPV6_ADDR_TYPE_GUA and \
+ ipv6_addr_type != dmtf.IPV6_ADDR_TYPE_6TO4 and \
+ ipv6_addr_type != dmtf.IPV6_ADDR_TYPE_ULA:
ipv6_addr = ''

# NetApp is using this kind of IPv6 address
@@ -2694,7 +2694,7 @@ class Smis(IStorageAreaNetwork):

in_params = {'GroupName': name,
'Members': [cim_init_path],
- 'Type': DMTF.MASK_GROUP_TYPE_INIT}
+ 'Type': dmtf.MASK_GROUP_TYPE_INIT}

cim_init_mg_pros = self._cim_init_mg_pros()

diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
index ae11460..0c9751d 100644
--- a/plugin/smispy/smis_cap.py
+++ b/plugin/smispy/smis_cap.py
@@ -16,7 +16,7 @@

from lsm import Capabilities, LsmError, ErrorNumber
from smis_constants import *
-from dmtf import *
+import dmtf
from smis_common import SmisCommon

MASK_TYPE_NO_SUPPORT = 0
@@ -133,19 +133,19 @@ def _bsp_cap_set(smis_common, cim_sys_path, cap):
if cim_scs_cap['SupportedAsynchronousActions']:
sup_actions.extend(cim_scs_cap['SupportedAsynchronousActions'])

- if DMTF.SCS_CAP_SUP_ST_VOLUME in element_types or \
- DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
+ if dmtf.SCS_CAP_SUP_ST_VOLUME in element_types or \
+ dmtf.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
cap.set(Capabilities.VOLUMES)
- if DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
+ if dmtf.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
cap.set(Capabilities.VOLUME_THIN)

- if DMTF.SCS_CAP_VOLUME_CREATE in sup_actions:
+ if dmtf.SCS_CAP_VOLUME_CREATE in sup_actions:
cap.set(Capabilities.VOLUME_CREATE)

- if DMTF.SCS_CAP_VOLUME_DELETE in sup_actions:
+ if dmtf.SCS_CAP_VOLUME_DELETE in sup_actions:
cap.set(Capabilities.VOLUME_DELETE)

- if DMTF.SCS_CAP_VOLUME_MODIFY in sup_actions:
+ if dmtf.SCS_CAP_VOLUME_MODIFY in sup_actions:
cap.set(Capabilities.VOLUME_RESIZE)

return
@@ -203,22 +203,22 @@ def _group_mask_map_cap_set(smis_common, cim_sys_path, cap):

# if empty dev group in spc is allowed, RemoveMembers() is enough
# to do volume_unmask(). RemoveMembers() is mandatory.
- if DMTF.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
+ if dmtf.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
cim_gmm_cap['SupportedDeviceGroupFeatures']:
cap.set(Capabilities.VOLUME_UNMASK)

# DeleteMaskingView() is optional, this is required by volume_unmask()
# when empty dev group in spc not allowed.
- elif ((DMTF.GMM_CAP_DELETE_SPC in
+ elif ((dmtf.GMM_CAP_DELETE_SPC in
cim_gmm_cap['SupportedSynchronousActions']) or
- (DMTF.GMM_CAP_DELETE_SPC in
+ (dmtf.GMM_CAP_DELETE_SPC in
cim_gmm_cap['SupportedAsynchronousActions'])):
cap.set(Capabilities.VOLUME_UNMASK)

# DeleteGroup is optional, this is required by access_group_delete()
- if ((DMTF.GMM_CAP_DELETE_GROUP in
+ if ((dmtf.GMM_CAP_DELETE_GROUP in
cim_gmm_cap['SupportedSynchronousActions']) or
- (DMTF.GMM_CAP_DELETE_GROUP in
+ (dmtf.GMM_CAP_DELETE_GROUP in
cim_gmm_cap['SupportedAsynchronousActions'])):
cap.set(Capabilities.ACCESS_GROUP_DELETE)
return None
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index d66286c..e497b29 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -25,7 +25,7 @@
from pywbem import Uint16, CIMError
import pywbem

-from dmtf import DMTF
+import dmtf
from lsm import LsmError, ErrorNumber
from utils import (merge_list)

@@ -45,7 +45,7 @@ def _profile_register_load(wbem_conn):
"""
profile_dict = {}
root_blk_cim_rp = None
- namespace_check_list = DMTF.INTEROP_NAMESPACES
+ namespace_check_list = dmtf.INTEROP_NAMESPACES

cim_rps = []
for namespace in namespace_check_list:
@@ -160,7 +160,7 @@ class SmisCommon(object):
_PRODUCT_NETAPP_E = 'NetApp-E'

def __init__(self, url, username, password,
- namespace=DMTF.DEFAULT_NAMESPACE,
+ namespace=dmtf.DEFAULT_NAMESPACE,
no_ssl_verify=False, debug=False, system_list=None):
self._wbem_conn = None
self._profile_dict = {}
@@ -169,7 +169,7 @@ class SmisCommon(object):
self.system_list = system_list

if namespace is None:
- namespace = DMTF.DEFAULT_NAMESPACE
+ namespace = dmtf.DEFAULT_NAMESPACE

self._wbem_conn = pywbem.WBEMConnection(
url, (username, password), namespace)
@@ -307,7 +307,7 @@ class SmisCommon(object):
"_vendor_namespace(): self.root_blk_cim_rp not set yet")

def EnumerateInstances(self, ClassName, namespace=None, **params):
- if self._wbem_conn.default_namespace in DMTF.INTEROP_NAMESPACES:
+ if self._wbem_conn.default_namespace in dmtf.INTEROP_NAMESPACES:
# We have to enumerate in vendor namespace
self._wbem_conn.default_namespace = self._vendor_namespace()
params['LocalOnly']=False
@@ -315,7 +315,7 @@ class SmisCommon(object):
ClassName, namespace, **params)

def EnumerateInstanceNames(self, ClassName, namespace=None, **params):
- if self._wbem_conn.default_namespace in DMTF.INTEROP_NAMESPACES:
+ if self._wbem_conn.default_namespace in dmtf.INTEROP_NAMESPACES:
# We have to enumerate in vendor namespace
self._wbem_conn.default_namespace = self._vendor_namespace()
params['LocalOnly']=False
diff --git a/plugin/smispy/smis_disk.py b/plugin/smispy/smis_disk.py
index 01de3db..11e5669 100644
--- a/plugin/smispy/smis_disk.py
+++ b/plugin/smispy/smis_disk.py
@@ -16,21 +16,19 @@
# Author: Gris Ge <***@redhat.com>

from lsm import Disk, md5, LsmError, ErrorNumber
-from dmtf import (
- DMTF, DMTF_DISK_TYPE_UNKNOWN, DMTF_DISK_TYPE_OTHER,
- DMTF_DISK_TYPE_HDD, DMTF_DISK_TYPE_SSD, DMTF_DISK_TYPE_HYBRID)
+import dmtf
from utils import merge_list


_LSM_DISK_OP_STATUS_CONV = {
- DMTF.OP_STATUS_UNKNOWN: Disk.STATUS_UNKNOWN,
- DMTF.OP_STATUS_OK: Disk.STATUS_OK,
- DMTF.OP_STATUS_PREDICTIVE_FAILURE: Disk.STATUS_PREDICTIVE_FAILURE,
- DMTF.OP_STATUS_ERROR: Disk.STATUS_ERROR,
- DMTF.OP_STATUS_NON_RECOVERABLE_ERROR: Disk.STATUS_ERROR,
- DMTF.OP_STATUS_STARTING: Disk.STATUS_STARTING,
- DMTF.OP_STATUS_STOPPING: Disk.STATUS_STOPPING,
- DMTF.OP_STATUS_STOPPED: Disk.STATUS_STOPPED,
+ dmtf.OP_STATUS_UNKNOWN: Disk.STATUS_UNKNOWN,
+ dmtf.OP_STATUS_OK: Disk.STATUS_OK,
+ dmtf.OP_STATUS_PREDICTIVE_FAILURE: Disk.STATUS_PREDICTIVE_FAILURE,
+ dmtf.OP_STATUS_ERROR: Disk.STATUS_ERROR,
+ dmtf.OP_STATUS_NON_RECOVERABLE_ERROR: Disk.STATUS_ERROR,
+ dmtf.OP_STATUS_STARTING: Disk.STATUS_STARTING,
+ dmtf.OP_STATUS_STOPPING: Disk.STATUS_STOPPING,
+ dmtf.OP_STATUS_STOPPED: Disk.STATUS_STOPPED,
}


@@ -42,17 +40,17 @@ def _disk_status_of_cim_disk(cim_disk):
if 'OperationalStatus' not in cim_disk:
return Disk.STATUS_UNKNOWN

- return DMTF.dmtf_op_status_list_conv(
+ return dmtf.op_status_list_conv(
_LSM_DISK_OP_STATUS_CONV, cim_disk['OperationalStatus'],
Disk.STATUS_UNKNOWN, Disk.STATUS_OTHER)[0]


_DMTF_DISK_TYPE_2_LSM = {
- DMTF_DISK_TYPE_UNKNOWN: Disk.TYPE_UNKNOWN,
- DMTF_DISK_TYPE_OTHER: Disk.TYPE_OTHER,
- DMTF_DISK_TYPE_HDD: Disk.TYPE_HDD,
- DMTF_DISK_TYPE_SSD: Disk.TYPE_SSD,
- DMTF_DISK_TYPE_HYBRID: Disk.TYPE_HYBRID,
+ dmtf.DISK_TYPE_UNKNOWN: Disk.TYPE_UNKNOWN,
+ dmtf.DISK_TYPE_OTHER: Disk.TYPE_OTHER,
+ dmtf.DISK_TYPE_HDD: Disk.TYPE_HDD,
+ dmtf.DISK_TYPE_SSD: Disk.TYPE_SSD,
+ dmtf.DISK_TYPE_HYBRID: Disk.TYPE_HYBRID,
}


diff --git a/plugin/smispy/smis_pool.py b/plugin/smispy/smis_pool.py
index e97b631..fba8931 100644
--- a/plugin/smispy/smis_pool.py
+++ b/plugin/smispy/smis_pool.py
@@ -16,7 +16,7 @@
# Author: Gris Ge <***@redhat.com>

from utils import merge_list
-from dmtf import *
+import dmtf
from lsm import LsmError, ErrorNumber, Pool
import json
from pywbem import CIMInstanceName
@@ -35,7 +35,7 @@ def cim_pools_of_cim_sys_path(smis_common, cim_sys_path, property_list=None):
checked by plugin_register(), we don't do any profile check here.
Primordial pool will be eliminated from return list.
These pools will be eliminated also:
- * Spare pool with CIM_StoragePool['Usage'] == DMTF_POOL_USAGE_SPARE
+ * Spare pool with CIM_StoragePool['Usage'] == dmtf.POOL_USAGE_SPARE
* IBM ArrayPool(IBMTSDS_ArrayPool)
* IBM ArraySitePool(IBMTSDS_ArraySitePool)
"""
@@ -56,7 +56,7 @@ def cim_pools_of_cim_sys_path(smis_common, cim_sys_path, property_list=None):
for cim_pool in cim_pools:
if 'Primordial' in cim_pool and cim_pool['Primordial']:
continue
- if 'Usage' in cim_pool and cim_pool['Usage'] == DMTF_POOL_USAGE_SPARE:
+ if 'Usage' in cim_pool and cim_pool['Usage'] == dmtf.POOL_USAGE_SPARE:
continue
# Skip IBM ArrayPool and ArraySitePool
# ArrayPool is holding RAID info.
@@ -143,11 +143,11 @@ def _pool_element_type(smis_common, cim_pool):
if 'SupportedStorageElementFeatures' in cim_scc:
supported_features = cim_scc['SupportedStorageElementFeatures']

- if DMTF_SUPPORT_VOL_CREATE in supported_features:
+ if dmtf.SUPPORT_VOL_CREATE in supported_features:
element_type |= Pool.ELEMENT_TYPE_VOLUME
- if DMTF_SUPPORT_ELEMENT_EXPAND not in supported_features:
+ if dmtf.SUPPORT_ELEMENT_EXPAND not in supported_features:
unsupported |= Pool.UNSUPPORTED_VOLUME_GROW
- if DMTF_SUPPORT_ELEMENT_REDUCE not in supported_features:
+ if dmtf.SUPPORT_ELEMENT_REDUCE not in supported_features:
unsupported |= Pool.UNSUPPORTED_VOLUME_SHRINK

else:
@@ -168,12 +168,12 @@ def _pool_element_type(smis_common, cim_pool):
if 'Usage' in cim_pool:
usage = cim_pool['Usage']

- if usage == DMTF_POOL_USAGE_UNRESTRICTED:
+ if usage == dmtf.POOL_USAGE_UNRESTRICTED:
element_type |= Pool.ELEMENT_TYPE_VOLUME
- if usage == DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM or \
- usage > DMTF_POOL_USAGE_DELTA:
+ if usage == dmtf.POOL_USAGE_RESERVED_FOR_SYSTEM or \
+ usage > dmtf.POOL_USAGE_DELTA:
element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
- if usage == DMTF_POOL_USAGE_DELTA:
+ if usage == dmtf.POOL_USAGE_DELTA:
# We blitz all the other elements types for this designation
element_type = Pool.ELEMENT_TYPE_DELTA

@@ -181,11 +181,11 @@ def _pool_element_type(smis_common, cim_pool):


_LSM_POOL_OP_STATUS_CONV = {
- DMTF.OP_STATUS_OK: Pool.STATUS_OK,
- DMTF.OP_STATUS_ERROR: Pool.STATUS_ERROR,
- DMTF.OP_STATUS_DEGRADED: Pool.STATUS_DEGRADED,
- DMTF.OP_STATUS_NON_RECOVERABLE_ERROR: Pool.STATUS_ERROR,
- DMTF.OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: Pool.STATUS_ERROR,
+ dmtf.OP_STATUS_OK: Pool.STATUS_OK,
+ dmtf.OP_STATUS_ERROR: Pool.STATUS_ERROR,
+ dmtf.OP_STATUS_DEGRADED: Pool.STATUS_DEGRADED,
+ dmtf.OP_STATUS_NON_RECOVERABLE_ERROR: Pool.STATUS_ERROR,
+ dmtf.OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: Pool.STATUS_ERROR,
}


@@ -193,7 +193,7 @@ def _pool_status_of_cim_pool(dmtf_op_status_list):
"""
Convert CIM_StoragePool['OperationalStatus'] to LSM
"""
- return DMTF.dmtf_op_status_list_conv(
+ return dmtf.op_status_list_conv(
_LSM_POOL_OP_STATUS_CONV, dmtf_op_status_list,
Pool.STATUS_UNKNOWN, Pool.STATUS_OTHER)

diff --git a/plugin/smispy/smis_sys.py b/plugin/smispy/smis_sys.py
index 683ae2b..64a9723 100644
--- a/plugin/smispy/smis_sys.py
+++ b/plugin/smispy/smis_sys.py
@@ -16,7 +16,7 @@
# Author: Gris Ge <***@redhat.com>

from utils import merge_list
-from dmtf import DMTF
+import dmtf
from lsm import System, LsmError, ErrorNumber


@@ -91,13 +91,13 @@ def cim_sys_pros():


_LSM_SYS_OP_STATUS_CONV = {
- DMTF.OP_STATUS_UNKNOWN: System.STATUS_UNKNOWN,
- DMTF.OP_STATUS_OK: System.STATUS_OK,
- DMTF.OP_STATUS_ERROR: System.STATUS_ERROR,
- DMTF.OP_STATUS_DEGRADED: System.STATUS_DEGRADED,
- DMTF.OP_STATUS_NON_RECOVERABLE_ERROR: System.STATUS_ERROR,
- DMTF.OP_STATUS_PREDICTIVE_FAILURE: System.STATUS_PREDICTIVE_FAILURE,
- DMTF.OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: System.STATUS_ERROR,
+ dmtf.OP_STATUS_UNKNOWN: System.STATUS_UNKNOWN,
+ dmtf.OP_STATUS_OK: System.STATUS_OK,
+ dmtf.OP_STATUS_ERROR: System.STATUS_ERROR,
+ dmtf.OP_STATUS_DEGRADED: System.STATUS_DEGRADED,
+ dmtf.OP_STATUS_NON_RECOVERABLE_ERROR: System.STATUS_ERROR,
+ dmtf.OP_STATUS_PREDICTIVE_FAILURE: System.STATUS_PREDICTIVE_FAILURE,
+ dmtf.OP_STATUS_SUPPORTING_ENTITY_IN_ERROR: System.STATUS_ERROR,
}


@@ -111,7 +111,7 @@ def _sys_status_of_cim_sys(cim_sys):
"sys_status_of_cim_sys(): Got a CIM_ComputerSystem with no "
"OperationalStatus: %s, %s" % (cim_sys.items(), cim_sys.path))

- return DMTF.dmtf_op_status_list_conv(
+ return dmtf.op_status_list_conv(
_LSM_SYS_OP_STATUS_CONV, cim_sys['OperationalStatus'],
System.STATUS_UNKNOWN, System.STATUS_OTHER)
--
1.8.2.1
Tony Asleson
2014-10-15 04:46:32 UTC
Permalink
From: Gris Ge <***@redhat.com>

Problem:
EMC VNX SMI-S provider will create a CIM_ConcreteJob when volume_create()
with exist volume name. It will mark CIM_ConcreteJob as failed for
volume confliction.

Root Cause:
Out SMI-S plugin only does error handling for duplicate volume name when
job creation for volume_create(), not after a job_creation.

Fix:
Run this duplication check in job_status() for volume_create:
self._check_for_dupe_vol(volume_name, sys.exc_info())

Detail Fix:
1. New constant SmisCommon.JOB_RETRIEVE_VOLUME_CREATE to indicate
a job is generated by volume_create().
2. Store method_data into job id:

self._job_id(cim_job, retrieve_data, method_data)
Smis._parse_job_id(job_id)
self._pi(msg, retrieve_data, method_data, rc, out)
# method_data could be used to store information(string) into job_id
# for error handling in job_status()
3. Run self._check_for_dupe_vol() in job_status() if cim_job failed.
4. Change self._check_for_dupe_vol() to allow setting original_exception
as None. In that case, it will not raise error when not NAME_CONFLICT.

Before fix:

$ lsmcli vc --name gris_test_10 \
--pool 'CLARiiON+FCN00122500421+U+Pool 0' --size 1B

PLUGIN_BUG(2): C:ERROR_CLASS_SOFTWARE F:ERROR_FAMILY_FAILED R:1000006 An
error from a sub-library call occurred : 2 : 20027 : "The specified LUN
name is already in use."

After fix:

$ lsmcli vc --name gris_test_10 \
--pool 'CLARiiON+FCN00122500421+U+Pool 0' --size 1B

NAME_CONFLICT(50): Volume with name 'gris_test_10' already exists!

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 53 +++++++++++++++++++++++++++++---------------
plugin/smispy/smis_common.py | 1 +
2 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 4b78a74..e57cb19 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -163,7 +163,7 @@ class Smis(IStorageAreaNetwork):
class_name, PropertyList=property_list)
org_requested_id = requested_id
if class_type == 'Job':
- (requested_id, ignore) = self._parse_job_id(requested_id)
+ (requested_id, ignore, ignore) = Smis._parse_job_id(requested_id)
for cim_xxx in cim_xxxs:
if self._id(class_type, cim_xxx) == requested_id:
return cim_xxx
@@ -174,20 +174,21 @@ class Smis(IStorageAreaNetwork):
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))

- def _pi(self, msg, retrieve_data, rc, out):
+ def _pi(self, msg, retrieve_data, method_data, rc, out):
"""
Handle the the process of invoking an operation.
"""
# Check to see if operation is done
if rc == SmisCommon.SNIA_INVOKE_OK:
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME:
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
+ retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
return None, self._new_vol_from_name(out)
else:
return None, None

elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
# We have an async operation
- job_id = self._job_id(out['Job'], retrieve_data)
+ job_id = self._job_id(out['Job'], retrieve_data, method_data)
return job_id, None
elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
raise LsmError(
@@ -325,6 +326,7 @@ class Smis(IStorageAreaNetwork):
cim_job = self._get_cim_instance_by_id('Job', job_id, cim_job_pros)

job_state = cim_job['JobState']
+ (ignore, retrieve_data, method_data) = self._parse_job_id(job_id)

if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
dmtf.JOB_STATE_RUNNING):
@@ -341,13 +343,15 @@ class Smis(IStorageAreaNetwork):
percent_complete = 100

if Smis._job_completed_ok(cim_job):
- (ignore, retrieve_data) = self._parse_job_id(job_id)
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME:
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
+ retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
completed_item = self._new_vol_from_job(cim_job)
else:
status = JobStatus.ERROR

else:
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
+ self._check_for_dupe_vol(method_data, None)
raise LsmError(ErrorNumber.PLUGIN_BUG,
str(cim_job['ErrorDescription']))

@@ -426,14 +430,17 @@ class Smis(IStorageAreaNetwork):
"""
return self._id('Volume', cim_vol)

- def _job_id(self, cim_job, retrieve_data):
+ def _job_id(self, cim_job, retrieve_data, method_data):
"""
Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
with '@%s' % retrieve_data
retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
SmisCommon.JOB_RETRIEVE_VOLUME or etc
+ method_data is any string a method would like store for error
+ handling by job_status().
"""
- return "%s@%d" % (self._id('Job', cim_job), int(retrieve_data))
+ return "%s@%d@%s" % (
+ self._id('Job', cim_job), int(retrieve_data), str(method_data))

def _init_id(self, cim_init):
"""
@@ -477,15 +484,18 @@ class Smis(IStorageAreaNetwork):
@staticmethod
def _parse_job_id(job_id):
"""
- job_id is assembled by a md5 string and retrieve_data
- This method will split it and return (md5_str, retrieve_data)
+ job_id is assembled by a md5 string, retrieve_data and method_data
+ This method will split it and return
+ (md5_str, retrieve_data, method_data)
"""
- tmp_list = job_id.split('@', 2)
+ tmp_list = job_id.split('@', 3)
md5_str = tmp_list[0]
retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
- if len(tmp_list) == 2:
+ method_data = None
+ if len(tmp_list) == 3:
retrieve_data = int(tmp_list[1])
- return (md5_str, retrieve_data)
+ method_data = tmp_list[2]
+ return (md5_str, retrieve_data, method_data)

@staticmethod
def _get_vol_other_id_info(cv):
@@ -824,6 +834,8 @@ class Smis(IStorageAreaNetwork):
:param volume_name: Volume to check for
:original_exception Info grabbed from sys.exec_info
:return:
+ if original_exception == None, will not raise any error if not
+ NAME_CONFLICT, just return None.
"""
report_original = True

@@ -844,6 +856,8 @@ class Smis(IStorageAreaNetwork):
pass

if report_original:
+ if original_exception is None:
+ return
raise original_exception[1], None, original_exception[2]
else:
raise LsmError(ErrorNumber.NAME_CONFLICT,
@@ -873,7 +887,8 @@ class Smis(IStorageAreaNetwork):

try:
return self._pi("volume_create",
- SmisCommon.JOB_RETRIEVE_VOLUME,
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
+ volume_name,
*(self._c.InvokeMethod(
'CreateOrModifyElementFromStoragePool',
scs.path, **in_params)))
@@ -905,6 +920,7 @@ class Smis(IStorageAreaNetwork):

job_id = self._pi("_detach",
SmisCommon.JOB_RETRIEVE_NONE,
+ None,
*(self._c.InvokeMethod(
'ModifySynchronization', scs.path,
**in_params)))[0]
@@ -922,7 +938,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}

- job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE,
+ job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE, None,
*(self._c.InvokeMethod(
'ModifyReplicaSynchronization', rs.path,
**in_params)))[0]
@@ -1031,6 +1047,7 @@ class Smis(IStorageAreaNetwork):

#Delete returns None or Job number
return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE,
+ None,
*(self._c.InvokeMethod('ReturnToStoragePool',
scs.path, **in_params)))[0]

@@ -1057,7 +1074,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'TheElement': lun.path}

# Delete returns None or Job number
- return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE,
+ return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE, None,
*(self._c.InvokeMethod('ReturnToStoragePool',
scs.path,
**in_params)))[0]
@@ -1075,7 +1092,7 @@ class Smis(IStorageAreaNetwork):
'TheElement': lun.path,
'Size': pywbem.Uint64(new_size_bytes)}

- return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME,
+ return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME, None,
*(self._c.InvokeMethod(
'CreateOrModifyElementFromStoragePool',
scs.path, **in_params)))
@@ -1192,7 +1209,7 @@ class Smis(IStorageAreaNetwork):
try:

return self._pi("volume_replicate",
- SmisCommon.JOB_RETRIEVE_VOLUME,
+ SmisCommon.JOB_RETRIEVE_VOLUME, None,
*(self._c.InvokeMethod(method,
rs.path, **in_params)))
except CIMError:
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index decbb51..4a303c3 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -172,6 +172,7 @@ class SmisCommon(object):

JOB_RETRIEVE_NONE = 0
JOB_RETRIEVE_VOLUME = 1
+ JOB_RETRIEVE_VOLUME_CREATE = 2

IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989
--
1.8.2.1
Tony Asleson
2014-10-15 04:48:28 UTC
Permalink
Forgot to mention. Patch series includes a squashed set for your latest
v3 series for reworking the constants (removing smis_constants.py).
Post by Tony Asleson
Gris,
Please take a look at this patch set. This is the pending patches I
"SMI-S Plugin: Check duplicate name in volume_replicate".
See updated patch for details.
If everything looks OK I want to commit. This patch series is looking
good in testing.
Thanks,
Tony
SMI-S plugin: Refactor, add smis_common.py, utils.py, dmtf.py files
SMI-S plugin: Refactor, remove eseries.py, smisproxy.py files
SMI-S Plugin: Refactor, add smis_sys.py
SMI-S Plugin: Refactor, add smis_pool.py file
SMI-S Plugin: Refactor, add smis_disk.py file.
SMI-S Plugin: Refactor dmtf.py
SMI-S Plugin: Refactor, remove smis_constants.py
SMI-S Plugin: Workaround for volume name duplication check after job
creation.
SMI-S Plugin: Check duplicate name in volume_replicate()
Plugin test: Fix incorrect NAME_CONFLICT check in
test_volume_replication()
lsmcli: new alias lt = lsmcli list --type target_ports
lsmenv: Integrate with plugin_test.py
SMI-S plugin: Refactor, add smis_cap.py, smis_constants.py files
simarray.py: Lock state file
Fix mem leaks in lsm_daemon.c, simc_lsmplugin.c
rpm spec: Use correct tmpfiles.d dir
rpm spec: Move command line python files to python package
rpm spec: udev files to /usr/lib dir instead of /lib
daemon/lsm_daemon.c | 6 +-
doc/man/lsmcli.1.in | 2 +
packaging/libstoragemgmt.spec.in | 39 +-
plugin/Makefile.am | 10 +-
plugin/sim/simarray.py | 22 +-
plugin/simc/simc_lsmplugin.c | 3 +
plugin/smispy/dmtf.py | 403 +++----
plugin/smispy/eseries.py | 164 ---
plugin/smispy/smis.py | 2141 ++++++++------------------------------
plugin/smispy/smis_cap.py | 384 +++++++
plugin/smispy/smis_common.py | 374 +++++++
plugin/smispy/smis_disk.py | 195 ++++
plugin/smispy/smis_pool.py | 285 +++++
plugin/smispy/smis_sys.py | 149 +++
plugin/smispy/smisproxy.py | 51 -
plugin/smispy/smispy_lsmplugin | 4 +-
plugin/smispy/utils.py | 68 ++
test/plugin_test.py | 17 +-
tools/lsmcli/cmdline.py | 1 +
tools/lsmenv | 40 +-
20 files changed, 2195 insertions(+), 2163 deletions(-)
delete mode 100644 plugin/smispy/eseries.py
create mode 100644 plugin/smispy/smis_cap.py
create mode 100644 plugin/smispy/smis_common.py
create mode 100644 plugin/smispy/smis_disk.py
create mode 100644 plugin/smispy/smis_pool.py
create mode 100644 plugin/smispy/smis_sys.py
delete mode 100644 plugin/smispy/smisproxy.py
create mode 100644 plugin/smispy/utils.py
Continue reading on narkive:
Loading...