Discussion:
[Libstoragemgmt-devel] [PATCH 0/7] SMIS plugin update for new pool_create()
Gris Ge
2014-03-11 13:02:04 UTC
Permalink
Generally:
1. Enable more interop support.
2. Some trivial fixes for LSI.
3. Rewrite of pool_create()

Please check each patch for details.

TODO:
* Capabilities() for pool_create()

Gris Ge (7):
smis.py: introduce _cim_sys_of_id() to support interop
smis.py: enable job_status() and job_free() for interop
smis.py: improve disk query
smis.py: fix volume-delete() on LSI
smis.py: sync to latest pool_create() and pool_delete() API changes
smis.py: Fix LSI pool member querying
smis.py: PEP8 clean up

lsm/lsm/smis.py | 1047 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 804 insertions(+), 243 deletions(-)
--
1.8.3.1
Gris Ge
2014-03-11 13:02:05 UTC
Permalink
* Introduced _cim_sys_of_id() to replace _get_cim_instance_by_id().
The latter use EnumerateInstances() which does not works in interop.
Will replace its functions eventually.
* This is just preparation for pool_create() and further changes.

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 54 +++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 45 insertions(+), 9 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index ae28ebc..090f64a 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -1496,7 +1496,7 @@ class Smis(IStorageAreaNetwork):

return System(cim_sys['Name'], cim_sys['ElementName'], status)

- def _cim_sys_pros(self):
+ def _new_sys_cim_sys_pros(self):
"""
Return a list of properties required to create a LSM System
"""
@@ -1504,23 +1504,59 @@ class Smis(IStorageAreaNetwork):
cim_sys_pros.extend(['ElementName', 'OperationalStatus'])
return cim_sys_pros

- @handle_cim_errors
- def systems(self, flags=0):
+
+ def _cim_syss(self, property_list=None):
"""
- Return the storage arrays accessible from this plug-in at this time
+ Return a list of root CIM_ComputerSystem.
+ If property_list is not defined, will contain not property.
"""
- cim_sys_pros = self._cim_sys_pros()
+ if property_list is None:
+ property_list = []
+
+ cim_syss = []
+
if self.fallback_mode:
- cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
+ cim_syss = self._get_cim_syss_fallback(property_list=property_list)
else:
cim_syss = self._get_cim_syss(
Smis.SNIA_BLK_ROOT_PROFILE,
Smis.SNIA_SMIS_SPEC_VER_1_4,
strict=False,
- property_list=cim_sys_pros)
+ property_list=property_list)
+ if cim_syss is None:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S %s profile version %s or later is not "
+ % (Smis.SNIA_BLK_ROOT_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4) +
+ "supported")
+ return cim_syss

- if cim_syss is None:
- return []
+ def _cim_sys_of_id(self, sys_id, property_list=None):
+ """
+ Return the CIMInstance-CIM_ComputerSystem for certain system ID.
+ """
+ if property_list is None:
+ property_list = self._property_list_of_id('System')
+ else:
+ for key in self._property_list_of_id('System'):
+ if key not in property_list:
+ property_list.extend([prop])
+
+ cim_syss = self._cim_syss(property_list)
+ for cim_sys in cim_syss:
+ if self._sys_id(cim_sys) == sys_id:
+ return cim_sys
+
+ raise LsmError(ErrorNumber.INVALID_SYSTEM,
+ "Invalid system: %s" % sys_id)
+
+ @handle_cim_errors
+ def systems(self, flags=0):
+ """
+ Return the storage arrays accessible from this plug-in at this time
+ """
+ cim_sys_pros = self._new_sys_cim_sys_pros()
+ cim_syss = self._cim_syss(cim_sys_pros)
return [Smis._cim_sys_2_lsm_sys(s) for s in cim_syss]

def _new_init(self, cim_st_hwid):
--
1.8.3.1
Tony Asleson
2014-05-19 18:10:50 UTC
Permalink
Post by Gris Ge
* Introduced _cim_sys_of_id() to replace _get_cim_instance_by_id().
The latter use EnumerateInstances() which does not works in interop.
Will replace its functions eventually.
* This is just preparation for pool_create() and further changes.
Gris,

I ran a unit test against an array that passes when specifying a
non-interop namespace that partially fails when I use interop. This is
to be the expected result correct?

Thanks,
Tony

Gris Ge
2014-03-11 13:02:06 UTC
Permalink
* By introducing _cim_job_of_id(), job_status() and job_free() now support
interop namespace.
* Renamed _get_cim_scs() to _cim_scs() to meet the name scheme of
_cim_xxxs().

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

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 090f64a..6aa9160 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -261,6 +261,7 @@ class Smis(IStorageAreaNetwork):
SNIA_BLK_SRVS_PROFILE = 'Block Services'
SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite'
SNIA_MULTI_SYS_PROFILE = 'Multiple Computer System'
+ SNIA_JOB_CTRL_PROFILE = 'Job Control'
SNIA_SMIS_SPEC_VER_1_4='1.4'
SNIA_SMIS_SPEC_VER_1_5='1.5'
SNIA_SMIS_SPEC_VER_1_6='1.6'
@@ -791,6 +792,52 @@ class Smis(IStorageAreaNetwork):

return rc

+ def _cim_job_of_id(self, job_id, property_list=None):
+ """
+ Find out the CIM_ConcreteJob from job ID.
+ Requireing 'Job Contorl' profile version 1.4+
+ """
+ if property_list is None:
+ property_list = self._property_list_of_id('Job')
+ else:
+ for key in self._property_list_of_id('Job'):
+ if key not in property_list:
+ property_list.extend([prop])
+
+
+ if not self.fallback_mode and \
+ not self._profile_is_supported(Smis.SNIA_JOB_CTRL_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False):
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target array does not support job control")
+
+ cim_syss = self._cim_syss()
+ for cim_sys in cim_syss:
+ cim_scs = self._cim_scs(cim_sys.path)
+ cim_jobs = []
+ try:
+ cim_jobs = self._c.Associators(
+ cim_scs.path,
+ AssocClass='CIM_OwningJobElement',
+ ResultClass='CIM_ConcreteJob',
+ PropertyList=property_list)
+ 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 array does not support job control")
+ else:
+ raise e
+
+ (ignore, retrieve_data) = self._parse_job_id(job_id)
+ for cim_job in cim_jobs:
+ if self._job_id(cim_job, retrieve_data) == job_id:
+ return cim_job
+
+ raise LsmError(ErrorNumber.INVALID_JOB,
+ "Invalid job ID: %s" % job_id)
+
@handle_cim_errors
def job_status(self, job_id, flags=0):
"""
@@ -803,8 +850,7 @@ class Smis(IStorageAreaNetwork):
cim_job_pros.extend(['JobState', 'PercentComplete',
'ErrorDescription', 'OperationalStatus'])

- cim_job = self._get_cim_instance_by_id('Job', job_id, False,
- cim_job_pros)
+ cim_job = self._cim_job_of_id(job_id, cim_job_pros)

job_state = cim_job['JobState']

@@ -2247,7 +2293,7 @@ class Smis(IStorageAreaNetwork):
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id)
+ cim_job = self._cim_job_of_id(job_id, ['DeleteOnCompletion'])

# See if we should delete the job
if not cim_job['DeleteOnCompletion']:
@@ -3066,7 +3112,7 @@ class Smis(IStorageAreaNetwork):
Delete a Pool via CIM_StorageConfigurationService.DeleteStoragePool
"""
cim_sys = self._get_cim_instance_by_id('System', pool.system_id, False)
- cim_scs = self._get_cim_scs(cim_sys.path, [])
+ cim_scs = self._cim_scs(cim_sys.path, [])

cim_pool = self._get_cim_instance_by_id('Pool', pool.id, False)
in_params = {'Pool': cim_pool.path}
@@ -3086,7 +3132,7 @@ class Smis(IStorageAreaNetwork):
CreateOrModifyStoragePool()
"""
cim_sys = self._get_cim_instance_by_id('System', system_id, False)
- cim_scs = self._get_cim_scs(cim_sys.path, [])
+ cim_scs = self._cim_scs(cim_sys.path, [])

# we does not support defining thinp_type yet.
# just using whatever provider set.
@@ -3416,7 +3462,7 @@ class Smis(IStorageAreaNetwork):
"type or add different RAID type tier")
return new_in_params

- def _get_cim_scs(self, cim_sys_path, property_list=None):
+ def _cim_scs(self, cim_sys_path, property_list=None):
"""
Usage:
Find out the CIM_StorageConfigurationService base on
--
1.8.3.1
Gris Ge
2014-03-11 13:02:07 UTC
Permalink
* Split disk type and disk total space codes out. Prepare for auto choosing
disk for pool_create().
* New _cim_disk() method to meet the name scheme of _cim_xxxs().
* New method of LSI disk type checking:
CIM_DiskDrive['MediaType'] then CIM_ProtocolEndpoint

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 151 +++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 110 insertions(+), 41 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 6aa9160..9174592 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -269,6 +269,10 @@ class Smis(IStorageAreaNetwork):
IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989

+ LSI_DISK_MEDIA_TYPE_HDD = 0
+ LSI_DISK_MEDIA_TYPE_SSD = 1
+ LSI_DISK_MEDIA_TYPE_SSD_FLASH = 2
+
class RepSvc(object):

class Action(object):
@@ -2379,21 +2383,15 @@ class Smis(IStorageAreaNetwork):
# Hence DiskDrive might not associated to top level
# CIM_ComputerSystem

+ cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
for cim_sys in cim_syss:
- cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
- cim_disks = self._c.Associators(cim_sys.path,
- AssocClass='CIM_SystemDevice',
- ResultClass='CIM_DiskDrive',
- PropertyList=cim_disk_pros)
+ cim_disks = self._cim_disks(cim_sys.path, cim_disk_pros)
if flag_multi_sys is not None:
# Checking Disks of sub level ComputerSystems.
cim_sub_syss_path = self._traverse_computer_sys(cim_sys.path)
for cim_sub_sys_path in cim_sub_syss_path:
- cim_sub_disks = self._c.Associators(
- cim_sub_sys_path,
- AssocClass='CIM_SystemDevice',
- ResultClass='CIM_DiskDrive',
- PropertyList=cim_disk_pros)
+ cim_sub_disks = self._cim_disks(
+ cim_sub_sys_path, cim_disk_pros)
if cim_sub_disks:
cim_disks.extend(cim_sub_disks)
# Clean up the duplicate as SNIA said DiskDrive can be
@@ -2414,6 +2412,38 @@ class Smis(IStorageAreaNetwork):
[self._new_disk(cim_disk, cim_ext, sys_id, flags)])
return rc

+ def _cim_disks(self, cim_sys_path, cim_disk_pros=None):
+ """
+ Usage:
+ Get all CIM_DiskDrive from this association:
+
+ CIM_ComputerSystem
+ |
+ | (CIM_SystemDevice)
+ |
+ v
+ CIM_DiskDrive
+ Return a list of CIMInstance-CIM_DiskDrive with
+ PropertyList from self._new_disk_cim_disk_pros()
+ Will not check fallback_mode and support status of
+ "Disk Drive Lite" profile, caller should do that.
+ Parameter:
+ cim_sys_path # CIMInstanceName-CIM_ComputerSystem
+ Returns:
+ cim_disks # a list of CIMInstance-CIM_DiskDrive
+ or
+ [] #
+ Exceptions:
+ N/A
+ """
+ if cim_disk_pros is None:
+ cim_disk_pros = []
+ return self._c.Associators(cim_sys_path,
+ AssocClass='CIM_SystemDevice',
+ ResultClass='CIM_DiskDrive',
+ PropertyList=cim_disk_pros)
+
+
def _traverse_computer_sys(self, cim_sys_path):
"""
Walk through the CIM_ComputerSystem based on SNIA SMI-S 1.6rev4
@@ -2456,7 +2486,7 @@ class Smis(IStorageAreaNetwork):
Return all CIM_DiskDrive Properties needed to create a Disk object.
"""
pros = ['OperationalStatus', 'Name', 'SystemName',
- 'Caption', 'InterconnectType', 'DiskType']
+ 'Caption', 'InterconnectType', 'DiskType', 'MediaType']
if flag == Disk.RETRIEVE_FULL_INFO:
pros.extend(['ErrorDescription', 'ErrorCleared'])
return pros
@@ -2506,6 +2536,74 @@ class Smis(IStorageAreaNetwork):
Smis._DMTF_STAUTS_TO_DISK_STATUS_INFO[dmtf_status])
return (status, status_info)

+ def _disk_type_of(self, cim_disk):
+ """
+ Usage:
+ Check disk type of CIMInstance-CIM_DiskDrive.
+ Requireing these properties:
+ 'InterconnectType', 'Caption', 'DiskType',
+ For LSI, we require these properties:
+ 'Type', 'MediaType'
+ Parameter:
+ cim_disk # CIMInstance-CIM_DiskDrive
+ Returns:
+ Disk.DISK_TYPE_XXX
+ Exceptions:
+ N/A
+ """
+ disk_type = Disk.DISK_TYPE_UNKNOWN
+ # LSI way for checking disk type
+ if cim_disk.classname == 'LSIESG_DiskDrive':
+ if cim_disk['MediaType'] == Smis.LSI_DISK_MEDIA_TYPE_SSD or \
+ cim_disk['MediaType'] == Smis.LSI_DISK_MEDIA_TYPE_SSD_FLASH:
+ return Disk.DISK_TYPE_SSD
+ elif cim_disk['MediaType'] == Smis.LSI_DISK_MEDIA_TYPE_HDD:
+ disk_type = Disk.DISK_TYPE_HDD
+
+ 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':
+ return Disk.DISK_TYPE_SATA
+ if ccn == 'LSIESG_TargetSASProtocolEndpoint':
+ return Disk.DISK_TYPE_SAS
+ return disk_type
+
+ # 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.DISK_TYPE_NL_SAS
+
+ if disk_type == Disk.DISK_TYPE_UNKNOWN and 'DiskType' in cim_disk:
+ disk_type = \
+ Smis.dmtf_disk_type_2_lsm_disk_type(cim_disk['DiskType'])
+
+ return disk_type
+
+ def _disk_total_space_of(self, cim_disk):
+ """
+ Use self._pri_cim_ext_of_cim_disk() to get Primordial
+ CIM_StorageExtent, then retrun
+ cim_ext['BlockSize'] * cim_ext['NumberOfBlocks']
+
+ Return 0 if failure.
+ """
+ cim_ext_pros = ['BlockSize', 'NumberOfBlocks']
+ cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path, cim_ext_pros)
+ if 'BlockSize' in cim_ext and 'NumberOfBlocks' in cim_ext:
+ return int(cim_ext['BlockSize'] * cim_ext['NumberOfBlocks'])
+ return 0
+
def _new_disk(self, cim_disk, cim_ext, sys_id, flag_full_info=0):
"""
Takes a CIM_DiskDrive and CIM_StorageExtent, returns a lsm Disk
@@ -2516,7 +2614,7 @@ class Smis(IStorageAreaNetwork):
name = ''
block_size = Disk.BLOCK_SIZE_NOT_FOUND
num_of_block = Disk.BLOCK_COUNT_NOT_FOUND
- disk_type = Disk.DISK_TYPE_UNKNOWN
+ disk_type = self._disk_type_of(cim_disk)
status_info = ''

# These are mandatory
@@ -2530,35 +2628,6 @@ class Smis(IStorageAreaNetwork):
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.DISK_TYPE_NL_SAS
-
- if disk_type == Disk.DISK_TYPE_UNKNOWN and 'DiskType' in cim_disk:
- disk_type = \
- Smis.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.DISK_TYPE_SATA
- if ccn == 'LSIESG_TargetSASProtocolEndpoint':
- disk_type = Disk.DISK_TYPE_SAS
-
optionals = OptionalData()
if flag_full_info == Disk.RETRIEVE_FULL_INFO:
opt_pro_dict = {
--
1.8.3.1
Gris Ge
2014-03-11 13:02:08 UTC
Permalink
* New LSI SMI-S provider(lsi_mr_hhr-00.50.0004-rhel6.x86_64)
will return pywbem.CIM_ERR_NOT_SUPPORTED for CIM_StorageSynchronized

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 9174592..4ad515c 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -1740,7 +1740,8 @@ class Smis(IStorageAreaNetwork):
ss = self._c.References(lun_path,
ResultClass='CIM_StorageSynchronized')
except pywbem.CIMError as e:
- if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
+ if e[0] == pywbem.CIM_ERR_INVALID_CLASS or \
+ e[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
return
else:
raise e
--
1.8.3.1
Gris Ge
2014-03-11 13:02:09 UTC
Permalink
* Almost rewrite pool_create(). Introduced many duplicate codes for LSI
vendor specific pool_create(), but that make work flow much clearer and
easier to maintain.

* As new pool_create() and pool_delete() required, returned Pool will contain
full optional_data.

* Interop supported. Tested on:
1. EMC VNX # Interop with ASYNC support
2. IBM XIV # Interop without ASYNC
3. LSI MegaRAID # No interop, no ASYNC

* Since SNIA does not have good way to handle 'Size' and 'InExtents' using
at the same, we add Smis._NEW_POOL_SIZE_OVERHAD for disk choosing.
(SNIA SMI-S 1.6.1 draft 2 introduced disk type in CIM_StorageSetting,
which will fix this problem, we will code it out once it released)

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 736 +++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 574 insertions(+), 162 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 4ad515c..4f8a9c6 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -23,7 +23,8 @@ import traceback
from pywbem import CIMError

from iplugin import IStorageAreaNetwork
-from common import Error, uri_parse, LsmError, ErrorNumber, JobStatus, md5
+from common import Error, uri_parse, LsmError, ErrorNumber, JobStatus, md5, \
+ size_human_2_size_bytes, size_bytes_2_size_human
from data import Pool, Initiator, Volume, AccessGroup, System, Capabilities,\
Disk, OptionalData, txt_a
from version import VERSION
@@ -273,6 +274,14 @@ class Smis(IStorageAreaNetwork):
LSI_DISK_MEDIA_TYPE_SSD = 1
LSI_DISK_MEDIA_TYPE_SSD_FLASH = 2

+ LSI_DEFAULT_RAID_TYPE = Pool.RAID_TYPE_RAID0
+ # this is define by us not LSI. We just want to make thing simple
+ # when user creating new pool without defining raid type
+
+ _NEW_POOL_SIZE_OVERHAD = size_human_2_size_bytes("100MiB")
+ # This constant is used by _auto_choose_disks(), check its comments for
+ # detail
+
class RepSvc(object):

class Action(object):
@@ -1239,13 +1248,17 @@ class Smis(IStorageAreaNetwork):
For SYNC CreateOrModifyElementFromStoragePool action.
The new CIM_StoragePool is stored in out['Pool']
"""
- pool_pros = self._new_pool_cim_pool_pros()
+ pool_pros = self._new_pool_cim_pool_pros(flag_full_info=True)

if 'Pool' in out:
cim_new_pool = self._c.GetInstance(
out['Pool'],
PropertyList=pool_pros)
- return self._new_pool(cim_new_pool)
+ pool = self._new_pool(cim_new_pool)
+ opt_pro_dict = self._pool_opt_data(cim_new_pool)
+ for key, value in opt_pro_dict.items():
+ pool.optional_data.set(key, value)
+ return pool
else:
raise LsmError(ErrorNumber.INTERNAL_ERROR,
"Got not new Pool from out of InvokeMethod" +
@@ -1286,12 +1299,16 @@ class Smis(IStorageAreaNetwork):
"""
Given a CIMInstance of CIM_ConcreteJob, return a LSM Pool
"""
- pool_pros = self._new_pool_cim_pool_pros()
+ pool_pros = self._new_pool_cim_pool_pros(flag_full_info=True)
cim_pools = self._c.Associators(cim_job.path,
AssocClass='CIM_AffectedJobElement',
ResultClass='CIM_StoragePool',
PropertyList=pool_pros)
- return self._new_pool(cim_pools[0])
+ pool = self._new_pool(cim_pools[0])
+ opt_pro_dict = self._pool_opt_data(cim_pools[0])
+ for key, value in opt_pro_dict.items():
+ pool.optional_data.set(key, value)
+ return pool

@handle_cim_errors
def volumes(self, flags=0):
@@ -1326,7 +1343,7 @@ class Smis(IStorageAreaNetwork):
for cim_sys in cim_syss:
sys_id = self._sys_id(cim_sys)
pool_pros = self._property_list_of_id('Pool')
- for cim_pool in self._pools(cim_sys, pool_pros):
+ for cim_pool in self._cim_pools(cim_sys.path, pool_pros):
pool_id = self._pool_id(cim_pool)
cim_vols = self._c.Associators(
cim_pool.path,
@@ -1390,7 +1407,7 @@ class Smis(IStorageAreaNetwork):
else:
return cim_syss

- def _pools(self, cim_sys, property_list=None):
+ def _cim_pools(self, cim_sys_path, property_list=None):
pros = []
if property_list is None:
pros = ['Primordial']
@@ -1399,13 +1416,29 @@ class Smis(IStorageAreaNetwork):
if 'Primordial' not in pros:
pros.extend(['Primordial'])

- cim_pools = self._c.Associators(cim_sys.path,
+ cim_pools = self._c.Associators(cim_sys_path,
AssocClass='CIM_HostedStoragePool',
ResultClass='CIM_StoragePool',
PropertyList=pros)

return [p for p in cim_pools if not p["Primordial"]]

+ def _cim_pool_of_id(self, cim_sys_path, pool_id, property_list=None):
+ if property_list is None:
+ property_list = self._property_list_of_id("Pool")
+ else:
+ for key in self._property_list_of_id("Pool"):
+ if key not in property_list:
+ property_list.extend([prop])
+
+ cim_pools = self._cim_pools(cim_sys_path, property_list)
+ for cim_pool in cim_pools:
+ if self._pool_id(cim_pool) == pool_id:
+ return cim_pool
+
+ raise LsmError(ErrorNumber.INVALID_POOL,
+ "Invalid pool: %s" % pool_id)
+
def _new_pool_cim_pool_pros(self, flag_full_info=False):
"""
Return a list of properties for creating new pool.
@@ -1448,7 +1481,7 @@ class Smis(IStorageAreaNetwork):

for cim_sys in cim_syss:
system_id = self._sys_id(cim_sys)
- for cim_pool in self._pools(cim_sys, cim_pool_pros):
+ for cim_pool in self._cim_pools(cim_sys.path, cim_pool_pros):
# Skip spare storage pool.
if 'Usage' in cim_pool and \
cim_pool['Usage'] == Smis.DMTF_POOL_USAGE_SPARE:
@@ -3181,10 +3214,10 @@ class Smis(IStorageAreaNetwork):
"""
Delete a Pool via CIM_StorageConfigurationService.DeleteStoragePool
"""
- cim_sys = self._get_cim_instance_by_id('System', pool.system_id, False)
+ cim_sys = self._cim_sys_of_id(pool.system_id)
cim_scs = self._cim_scs(cim_sys.path, [])
+ cim_pool = self._cim_pool_of_id(cim_sys.path, pool.id)

- cim_pool = self._get_cim_instance_by_id('Pool', pool.id, False)
in_params = {'Pool': cim_pool.path}

return self._pi("pool_delete", Smis.JOB_RETRIEVE_NONE,
@@ -3192,70 +3225,184 @@ class Smis(IStorageAreaNetwork):
cim_scs.path,
**in_params)))[0]

- @handle_cim_errors
- def pool_create(self, system_id, pool_name, raid_type, member_type,
- member_ids, member_count, size_bytes, thinp_type, flags=0):
+ def _pool_create_lsi(self, cim_sys, pool_name, size_bytes,
+ raid_type=Pool.RAID_TYPE_UNKNOWN,
+ member_type=Pool.MEMBER_TYPE_UNKNOWN, flags=0):
"""
- Creating pool via
- CIM_StorageConfigurationService.CreateOrModifyStoragePool()
- TODO: Each vendor are needing different parameters for
- CreateOrModifyStoragePool()
+ LSI Vendor specific way of pool creation.
"""
- cim_sys = self._get_cim_instance_by_id('System', system_id, False)
+ if raid_type == Pool.RAID_TYPE_UNKNOWN:
+ # LSI does not allow InExtents to be NULL.
+ # We have to chose disks for LSI.
+ # To make thing simple, we only check 1 raid type for
+ # possible disk combination
+ raid_type =Smis.LSI_DEFAULT_RAID_TYPE
+
cim_scs = self._cim_scs(cim_sys.path, [])

# we does not support defining thinp_type yet.
# just using whatever provider set.

in_params = {}
- if pool_name:
- in_params['ElementName'] = pool_name
-
- in_cim_exts_path = []
- if member_type == Pool.MEMBER_TYPE_DISK:
- if member_ids and len(member_ids) >= 1:
- cim_exts = self._pri_cim_ext_of_disk_ids(member_ids)
- system_id = None
- for cim_ext in cim_exts:
- tmp_system_id = self._sys_id_child(cim_ext)
- if not system_id:
- system_id = tmp_system_id
- elif system_id != tmp_system_id:
- raise LsmError(ErrorNumber.INVALID_DISK,
- "Specified member are belong to " +
- "two or more system: %s %s" %
- (system_id, tmp_system_id))
- if cim_exts:
- in_cim_exts_path = [x.path for x in cim_exts]
- in_params['InExtents'] = in_cim_exts_path
-
- elif member_type == Pool.MEMBER_TYPE_POOL:
- cim_member_pools_path = []
- for member_id in member_ids:
- cim_member_pools_path.extend(
- [self._get_cim_instance_by_id('Pool', member_id,
- False, None).path])
- in_params['InPools'] = cim_member_pools_path
-
- elif member_type == Pool.MEMBER_TYPE_VOLUME:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Creating Pool against another Volume is not " +
- "supported by SMIS plugin")
- # TODO: support member_count
- if member_count and member_count > 0:
+ in_params['ElementName'] = pool_name
+ in_params['Size'] = pywbem.Uint64(1)
+ # LSI require InExtents define, so the 'Size' just set to 1 bytes
+ # would be OK.
+
+ raise_error = True
+
+ if member_type == Pool.MEMBER_TYPE_UNKNOWN:
+ raise_error = True # We only support disk pool, so raise error
+ # anyway.
+
+ if member_type != Pool.MEMBER_TYPE_UNKNOWN and \
+ not Pool.member_type_is_disk(member_type):
raise LsmError(ErrorNumber.NO_SUPPORT,
- "member_count is not supported by " +
- "SMI-S plugin yet.")
+ "Creating new pool with member type %s(%d) "
+ % (Pool.member_type_to_str(member_type),
+ member_type) + "is not supported")
+
+ # Find CIM_StorageSetting for 'Goal' parameter
+ cim_st_set = self._find_preset_st_set(cim_sys.path, raid_type)
+
+ if cim_st_set:
+ in_params['Goal'] = cim_st_set.path
+
+
+ disk_type = Disk.DISK_TYPE_UNKNOWN
+ if Pool.member_type_is_disk(member_type):
+ disk_type = Pool.member_type_to_disk_type(member_type)
+
+ cim_disks = self._auto_choose_disks(cim_sys.path, size_bytes,
+ raid_type, disk_type, raise_error)
+ if len(cim_disks) > 1:
+ in_params['InExtents'] = []
+ for cim_disk in cim_disks:
+ cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path, None)
+ if cim_ext:
+ in_params['InExtents'].extend([cim_ext.path])
+ else:
+ return (None, None)
+
+ return self._pi("pool_create", Smis.JOB_RETRIEVE_POOL,
+ *(self._c.InvokeMethod(
+ 'CreateOrModifyStoragePool',
+ cim_scs.path, **in_params)))
+
+ @handle_cim_errors
+ def pool_create(self, system_id, pool_name, size_bytes,
+ raid_type=Pool.RAID_TYPE_UNKNOWN,
+ member_type=Pool.MEMBER_TYPE_UNKNOWN, flags=0):
+ """
+ Using SNIA SMI-S 1.4 or later 'Block Service Packpage' profile:
+
+ CIM_StorageConfigurationService.CreateOrModifyStoragePool(
+ InPools = [CIMInstanceName of CIM_StoragePool,],
+ InExtents = [
+ CIMInstanceName of CIM_StorageExtent or CIM_StoragePool, ],
+ Size = Uint64 size,
+ Goal = CIMInstanceName of CIM_StorageSetting,
+ )
+
+ Only support disk pool for now.
+ Basic procedure:
+ 1. If vendor specific procedure available, use vendor specific
+ way only.
+ 2. Use SNIA general procedure (based on Gris's understanding)
+ to setup parameters for CreateOrModifyStoragePool()
+ 3. Use CIM_StorageConfigurationCapabilities to check capability
+ before callout.
+ 4. Call CreateOrModifyStoragePool()
+
+ SNIA general procedure:
+ 1. If raid_type defined, we set 'Goal' by finding predefined
+ CIM_StorageSetting. If not, we leave 'Goal' as undefine.
+ 2. If member_type defeind, we find certain type of disks to setup
+ 'InExtents'. If not, we leave 'InExtents' as undefine.
+ 3. When 'InExtents' was set, we set 'Size' to 1B just in case
+ the requested size exceed the 'InExtents' capable size.
+ 4. In SNIA 1.6.1 draft, allowing Goal defined disk type via
+ properties: InterconnectType, RPM, and etc. I see no
+ vendor support it yet.
+
+ TODO: Check CIM_StoragePool.GetSupportedSizeRange() before
+ execute pool creation call.
+ """
+ cim_sys = self._cim_sys_of_id(system_id)
+
+ if cim_sys.classname == 'LSIESG_MegaRAIDHBA':
+ return self._pool_create_lsi(cim_sys, pool_name, size_bytes,
+ raid_type, member_type, flags)
+
+ cim_scs = self._cim_scs(cim_sys.path, [])
+
+ # we does not support defining thinp_type yet.
+ # just using whatever provider set.
+
+ in_params = {}
+ in_params['ElementName'] = pool_name
+ in_params['Size'] = pywbem.Uint64(size_bytes)

- if size_bytes > 0:
- in_params['Size'] = pywbem.Uint64(size_bytes)
+ raise_error = True

- if raid_type != Pool.RAID_TYPE_UNKNOWN and \
- raid_type != Pool.RAID_TYPE_NOT_APPLICABLE:
- in_params['Goal'] = self._cim_st_set_for_goal(
- raid_type, thinp_type, cim_sys.path)
+ if member_type == Pool.MEMBER_TYPE_UNKNOWN:
+ raise_error = True # We only support disk pool, so raise error
+ # anyway.
+
+ if member_type == Pool.MEMBER_TYPE_UNKNOWN:
+ if raid_type == Pool.RAID_TYPE_UNKNOWN:
+ # 'Size' and 'ElementName' is enough.
+ pass
+ else:
+ # Need use 'Goal' to define RAID type
+ cim_st_set = self._find_preset_st_set(cim_sys.path, raid_type)
+ if cim_st_set is None:
+ if raise_error:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "RAID type %s(%d) is not supported "
+ % (Pool.raid_type_to_str(raid_type),
+ raid_type) +
+ "by target array")
+ else:
+ return (None, None)
+ in_params['Goal'] = cim_st_set.path
+
+ elif Pool.member_type_is_disk(member_type):
+ if raid_type != Pool.RAID_TYPE_UNKNOWN:
+ # Need to set 'Goal' parameter for RAID type
+ cim_st_set = self._find_preset_st_set(cim_sys.path, raid_type)
+ if cim_st_set is None:
+ if raise_error:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "RAID type %s(%d) is not supported "
+ % (Pool.raid_type_to_str(raid_type),
+ raid_type) +
+ "by target array")
+ else:
+ return (None, None)
+ in_params['Goal'] = cim_st_set.path
+
+ disk_type = Pool.member_type_to_disk_type(member_type)
+ if disk_type != Disk.DISK_TYPE_UNKNOWN:
+ # Need to set 'InExtents' parameter for disks
+ cim_disks = self._auto_choose_disks(
+ cim_sys.path, size_bytes, raid_type, disk_type,
+ raise_error)
+ if len(cim_disks) > 1:
+ in_params['InExtents'] = []
+ for cim_disk in cim_disks:
+ cim_ext = self._pri_cim_ext_of_cim_disk(
+ cim_disk.path, None)
+ in_params['InExtents'].extend([cim_ext.path])
+ in_params['Size'] = pywbem.Uint64(1)
+ else:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Creating new pool with member type %s(%d) "
+ % (Pool.member_type_to_str(member_type),
+ member_type) + "is not supported")

in_params = self._pool_chg_paras_check(in_params, cim_sys.path)
+
return self._pi("pool_create", Smis.JOB_RETRIEVE_POOL,
*(self._c.InvokeMethod(
'CreateOrModifyStoragePool',
@@ -3346,11 +3493,30 @@ class Smis(IStorageAreaNetwork):
cim_disk_path)

@handle_cim_errors
- def _find_preset_st_set(self, cim_cap_path, raid_type, thinp_type):
+ def _find_preset_st_set(self, cim_sys_path , raid_type):
"""
Usage:
Find first proper CIM_StorageSetting under speficied
CIM_StorageCapabilities by giving raid_type and thinp_type.
+ Using this associations:
+ CIM_ComputerSystem
+ |
+ | CIM_HostedStoragePool
+ |
+ v
+ CIM_StoragePool (Primordial)
+ |
+ | CIM_ElementCapabilities
+ |
+ CIM_StorageCapabilities
+ |
+ | CIM_StorageSettingsAssociatedToCapabilities
+ |
+ v
+ CIM_StorageSetting (Predefined)
+
+ TODO: Support SPEC 1.6.1 for disk type in CIM_StorageSetting
+ But no vendor support that yet.
Parameter:
cim_cap_path # CIMInstanceName of CIM_StorageCapabilities
raid_type # Pool.RAID_TYPE_XXX
@@ -3360,15 +3526,31 @@ class Smis(IStorageAreaNetwork):
or
None # No match found
"""
- DMTF_CHANGEABLE_TYPE_FIX = 0
- cim_fix_st_sets = self._c.Associators(
- cim_cap_path,
- AssocClass='CIM_StorageSettingsAssociatedToCapabilities',
- ResultClass='CIM_StorageSetting',
- PropertyList=['ElementName',
- 'ThinProvisionedPoolType'])
- if not cim_fix_st_sets:
- return None
+ all_cim_st_sets = []
+ # get Primordial StoragePool
+ cim_pools = self._c.Associators(
+ cim_sys_path,
+ AssocClass='CIM_HostedStoragePool',
+ ResultClass='CIM_StoragePool',
+ PropertyList=['Primordial'])
+
+ for cim_pool in cim_pools:
+ if not cim_pool['Primordial']:
+ continue
+ cim_caps_path = self._c.AssociatorNames(
+ cim_pool.path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_StorageCapabilities')
+
+ for cim_cap_path in cim_caps_path:
+ tmp_cim_st_sets = self._c.Associators(
+ cim_cap_path,
+ AssocClass='CIM_StorageSettingsAssociatedToCapabilities',
+ ResultClass='CIM_StorageSetting',
+ PropertyList=['ElementName', 'ThinProvisionedPoolType'])
+ all_cim_st_sets.extend(tmp_cim_st_sets)
+
+
raid_type_str = Pool.raid_type_to_str(raid_type)
# According to SNIA suggest, RAID6 can also be writen as RAID5DP
# and etc.
@@ -3378,96 +3560,21 @@ class Smis(IStorageAreaNetwork):
elif raid_type_str == 'RAID10':
possible_element_names.extend(['RAID1+0'])

- if thinp_type != Pool.THINP_TYPE_UNKNOWN:
- if thinp_type == Pool.THINP_TYPE_THIN:
- # searching for a thin CIM_StorageSetting
- dmtf_thinp_type = self._lsm_thinp_type_to_dmtf(thinp_type)
-
- for cim_st_set in cim_fix_st_sets:
- if 'ElementName' in cim_st_set \
- and cim_st_set['ElementName'] \
- in possible_element_names \
- and cim_st_set['ThinProvisionedPoolType'] \
- == dmtf_thinp_type:
- return cim_st_set.path
- else: # searching for a Thick CIM_StorageSetting
- for cim_st_set in cim_fix_st_sets:
- if 'ElementName' not in cim_st_set or \
- cim_st_set['ElementName'] not in possible_element_names:
- continue
- if 'ThinProvisionedPoolType' not in cim_st_set:
- return cim_st_set.path
- # EMC define Thick pools with ThinProvisionedPoolType
- # value.
- elif cim_st_set.classname == 'Clar_StoragePoolSetting' \
- and cim_st_set['ThinProvisionedPoolType'] \
- == Smis.EMC_THINP_POOL_TYPE_THICK:
- return cim_st_set.path
- else: # Searching a CIM_StorageSetting regardless Thin or Thick.
- for cim_st_set in cim_fix_st_sets:
- if 'ElementName' in cim_st_set and \
- cim_st_set['ElementName'] in possible_element_names:
- return cim_st_set.path
- return None
+ chose_cim_st_sets = []
+ for cim_st_set in all_cim_st_sets:
+ if cim_st_set['ElementName'] in possible_element_names:
+ chose_cim_st_sets.extend([cim_st_set])

- def _cim_st_set_for_goal(self, raid_type, thinp_type, cim_sys_path):
- """
- Usage:
- Find out the array pre-defined CIM_StorageSetting for certain RAID
- Level. Only check CIM_StorageSetting['ElementName'] for RAID type,
- and CIM_StorageSetting['ThinProvisionedPoolType'] for Thin
- Provision setting.
- Even SNIA defined a way to create new setting, but we find out
- that not a good way to follow.
- Parameter:
- raid_type # Tier.RAID_TYPE_XXX
- disk_count # how many disks will this RAID group hold.
- cim_sys_path # CIMInstanceName of CIM_ComputerSystem.
- Returns:
- cim_st_set_path # Found or created CIMInstanceName of
- # CIM_StorageSetting
- Exceptions:
- LsmError
- ErrorNumber.NO_SUPPORT # Failed to find out
- # suitable CIM_StorageSetting
- """
- cim_chose_st_set_path = None
- # We will try to find the existing CIM_StorageSetting
- # with ElementName equal to raid_type_str
- # potted(pre-defined) CIM_StorageSetting
- cim_pool_path = None
- cim_pools = self._c.Associators(cim_sys_path,
- ResultClass='CIM_StoragePool',
- PropertyList=['Primordial'])
- # Base on SNIA commanded, each array should provide a
- # Primordial pool.
- for cim_tmp_pool in cim_pools:
- if cim_tmp_pool['Primordial']:
- cim_pool_path = cim_tmp_pool.path
- break
- if not cim_pool_path:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Target storage array does not have "
- "Primordial CIM_StoragePool")
- cim_caps = self._c.Associators(
- cim_pool_path,
- ResultClass='CIM_StorageCapabilities',
- PropertyList=['ElementType'])
- for cim_cap in cim_caps:
- cim_tmp_st_set = self._find_preset_st_set(
- cim_cap.path,
- raid_type,
- thinp_type)
- if cim_tmp_st_set:
- cim_chose_st_set_path = cim_tmp_st_set
- break
- if not cim_chose_st_set_path:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Current array does not support RAID type: " +
- "%s and thinp_type %s" %
- (Pool.raid_type_to_str(raid_type),
- Pool.thinp_type_to_str(thinp_type)))
- return cim_chose_st_set_path
+ # we prefer thin provisioning CIM_StorageSetting
+ for cim_st_set in chose_cim_st_sets:
+ if ('ThinProvisionedPoolType' in cim_st_set and \
+ cim_st_set['ThinProvisionedPoolType'] == \
+ Smis.DMTF_THINP_POOL_TYPE_ALLOCATED):
+ return cim_st_set
+
+ if len(chose_cim_st_sets) > 0:
+ return chose_cim_st_sets[0]
+ return None

def _pool_chg_paras_check(self, in_params, cim_sys_path):
"""
@@ -3731,7 +3838,7 @@ class Smis(IStorageAreaNetwork):
Returns:
cim_syss # A list of CIMInstanceName of CIM_ComputerSystem
or
- None
+ []
"""
sys_id_pros = self._property_list_of_id('System')
flag_full_info = False
@@ -3795,3 +3902,308 @@ class Smis(IStorageAreaNetwork):
return needed_cim_syss
else:
return cim_syss
+
+ def _free_disks_list(self, cim_sys_path, disk_type=Disk.DISK_TYPE_UNKNOWN):
+ """
+ Usage:
+ Return a list of cim_disk which is free.
+ Using two ways to check free disks:
+ A. CIM_StoragePool.GetAvailableExtents(
+ Goal=CIMInstanceName of CIM_StorageSetting)
+ B. Check for those disks not used by any pool.
+
+ Method A) is optional SNIA SMI-S Block Service Package
+ (SPEC 1.4 to 1.6)
+
+ Since even LSI support method A(without profile registering),
+ we skip method B)
+
+ When disk_type define, will only contain defined type of disk
+ in return list.
+ The cim_disk will only contain properties defined in
+ Smis._new_disk_cim_ext_pros()
+ TODO: Need tests again IBM SVC which use remote volume as pool
+ member.
+ Parameter:
+ cim_sys_path # CIMInstanceName of CIM_ComputerSystem
+ disk_type # Disk.DISK_TYPE_XXX
+ Returns:
+ [cim_disk, ] # a list of items.
+ or
+ [] # Nothing found
+ Exceptions:
+ LsmError
+ ErrorNumber.INTERNAL_ERROR
+ * When no Primordial StoragePool found.
+ N/A
+ """
+ rc = []
+
+ if self._profile_is_supported(Smis.SNIA_BLK_SRVS_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False) and \
+ not self._profile_is_supported(Smis.SNIA_DISK_LITE_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False):
+ # Support 'Disk Drive Lite' 1.4+ is prerequisite.
+ return []
+
+ # get Primordial StoragePool
+ cim_pools = self._c.Associators(
+ cim_sys_path,
+ AssocClass='CIM_HostedStoragePool',
+ ResultClass='CIM_StoragePool',
+ PropertyList=['Primordial'])
+
+ cim_pools = [p for p in cim_pools if p["Primordial"]]
+ if len(cim_pools) == 0:
+ raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ "No Primordial CIM_StoragePool found for "
+ "system %s, might be a provider's bug"
+ % cim_sys_path)
+ cim_disk_pros = self._new_disk_cim_disk_pros()
+ # LSI has more than 1 Primordial StoragePool :(
+ for cim_pool in cim_pools:
+ return_code = 0
+ out = dict()
+ # TODO: Use Goal parameter of
+ # CIM_StoragePool.GetAvailableExtents() to filter
+ # CIM_StorageExtent
+ try:
+ (return_code, out) = self._c.InvokeMethod(
+ 'GetAvailableExtents',
+ cim_pool.path)
+ except CIMError as e:
+ if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
+ e[0] == pywbem.CIM_ERR_NOT_FOUND:
+ break
+ else:
+ raise e
+
+ if return_code == Smis.INVOKE_OK and \
+ 'AvailableExtents' in out and \
+ out['AvailableExtents']:
+ for cim_pri_ext_path in out['AvailableExtents']:
+ rc.extend(
+ self._c.Associators(
+ cim_pri_ext_path,
+ AssocClass='CIM_MediaPresent',
+ ResultClass='CIM_DiskDrive',
+ PropertyList=cim_disk_pros))
+ if disk_type != Disk.DISK_TYPE_UNKNOWN:
+ cleanup_rc = []
+ for cim_disk in rc:
+ if self._disk_type_of(cim_disk) == disk_type:
+ cleanup_rc.extend([cim_disk])
+
+ rc = cleanup_rc
+ return rc
+
+ def _free_disks(self, cim_sys_path, disk_type=Disk.DISK_TYPE_UNKNOWN):
+ """
+ Usage:
+ Return a structure like this:
+ {
+ Disk.disk_type = {
+ Disk.total_space = [ cim_disk, ],
+ },
+ }
+ When disk_type define, will only contain defined type of disk
+ in return structure.
+ The cim_disk will only contain properties defined in
+ Smis._new_disk_cim_ext_pros()
+ Parameter:
+ cim_sys_path # CIMInstanceName of CIM_ComputerSystem
+ disk_type # Disk.DISK_TYPE_XXX
+ Returns:
+ free_disk_t # Check above
+ or
+ dcit() # Nothing found
+ Exceptions:
+ N/A
+ """
+ rc = dict()
+ free_cim_disks = self._free_disks_list(cim_sys_path, disk_type)
+ if len(free_cim_disks) == 0:
+ return rc
+
+ for cim_disk in free_cim_disks:
+ disk_type = self._disk_type_of(cim_disk)
+ disk_size = self._disk_total_space_of(cim_disk)
+ if disk_size == 0 or disk_type == Disk.DISK_TYPE_UNKNOWN:
+ continue
+ if disk_type not in rc.keys():
+ rc[disk_type] = dict()
+
+ if disk_size not in rc[disk_type].keys():
+ rc[disk_type][disk_size] = []
+ rc[disk_type][disk_size].extend([cim_disk])
+
+ return rc
+
+ def _size_of_disk_raid(self, cim_disks, raid_type):
+ member_sizes = []
+ for cim_disk in cim_disks:
+ disk_size = self._disk_total_space_of(cim_disk)
+ if disk_size > 1:
+ member_sizes.extend([disk_size])
+
+ if len(member_sizes) == 0:
+ return 0
+
+ all_size = 0
+ member_count = len(member_sizes)
+ for member_size in member_sizes:
+ all_size += member_size
+
+ # assuming all raid member is in the same size which was already
+ # checked by caller. (JBOD and NOT_APPLICABLE does not require that)
+ member_size = member_sizes[0]
+
+ if raid_type == Pool.RAID_TYPE_JBOD or \
+ raid_type == Pool.RAID_TYPE_NOT_APPLICABLE or \
+ raid_type == Pool.RAID_TYPE_RAID0:
+ return int(all_size)
+ elif (raid_type == Pool.RAID_TYPE_RAID1 or
+ raid_type == Pool.RAID_TYPE_RAID10):
+ if member_count % 2 == 1:
+ return 0
+ return int(all_size/2)
+ elif (raid_type == Pool.RAID_TYPE_RAID3 or
+ raid_type == Pool.RAID_TYPE_RAID4 or
+ raid_type == Pool.RAID_TYPE_RAID5):
+ if member_count < 3:
+ return 0
+ return int(all_size - member_size)
+ elif raid_type == Pool.RAID_TYPE_RAID50:
+ if member_count < 6 or member_count % 2 == 1:
+ return 0
+ return int(all_size - member_size*2)
+ elif raid_type == Pool.RAID_TYPE_RAID6:
+ if member_count < 4:
+ return 0
+ return int(all_size - member_size * 2)
+ elif raid_type == Pool.RAID_TYPE_RAID60:
+ if member_count < 8 or member_count % 2 == 1:
+ return 0
+ return int(all_size - member_size*4)
+ elif raid_type == Pool.RAID_TYPE_RAID51:
+ if member_count < 6 or member_count % 2 == 1:
+ return 0
+ return int(all_size/2 - member_size)
+ elif raid_type == Pool.RAID_TYPE_RAID61:
+ if member_count < 8 or member_count % 2 == 1:
+ return 0
+ return int(all_size/2 - member_size*2)
+ raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ "_size_of_raid() got invalid raid type: " +
+ "%s(%d)" % (Pool.raid_type_to_str(raid_type),
+ raid_type))
+
+ def _auto_choose_disks(self, cim_sys_path, size_bytes, raid_type,
+ disk_type, raise_error=False):
+ """
+ Usage:
+ Automatically choose the correct disks to assemble defined
+ RAID.
+ Considering the pool/raid overhead, size_bytes will increase
+ Smis._NEW_POOL_SIZE_OVERHAD
+ Raise LsmError if nothing found when raise_error is True.
+ Return [] if nothing found when raise_error is False.
+ Parameter:
+ cim_sys_path # CIMInstanceName of CIM_ComputerSystem
+ size_bytes # int, requested size for new RAID.
+ raid_type # Pool.RAID_TYPE_XXX
+ disk_type # Disk.DISK_TYPE_XXX
+ raise_error # True or False, raise on error or not.
+ Returns:
+ [cim_disk, ] # a list of cim_disk
+ or
+ [] # Nothing found if raise_error is False
+ Exceptions:
+ LsmError
+ ErrorNumber.DISK_BUSY
+ # No free disks
+ ErrorNumber.SIZE_INSUFFICIENT_SPACE
+ # No enough disks or size meet request
+ """
+ new_size_bytes = size_bytes + Smis._NEW_POOL_SIZE_OVERHAD
+
+ disk_type_str = "disk"
+ if disk_type != Disk.DISK_TYPE_UNKNOWN:
+ disk_type_str = "disk(type: %s)" % Disk.disk_type_to_str(disk_type)
+
+ if raid_type == Pool.RAID_TYPE_NOT_APPLICABLE:
+ # NOT_APPLICABLE means pool will only contain one disk.
+ cim_disks = self._free_disks_list(cim_sys_path, disk_type)
+ if len(cim_disks) == 0:
+ if raise_error:
+ raise LsmError(ErrorNumber.DISK_BUSY,
+ "No free %s found" % disk_type_str)
+ else:
+ return []
+
+ for cim_disk in cim_disks:
+ if self._disk_total_space_of(cim_disk) >= new_size_bytes:
+ return [cim_disk]
+ if raise_error:
+ raise LsmError(ErrorNumber.SIZE_INSUFFICIENT_SPACE,
+ "No %s is bigger than " % disk_type_str +
+ "expected size: %s(%d)" %
+ (size_bytes_2_size_human(size_bytes),
+ size_bytes))
+ else:
+ return []
+
+ if raid_type == Pool.RAID_TYPE_JBOD:
+ # JBOD does not require all disks in the same size or the same type.
+ cim_disks = self._free_disks_list(cim_sys_path, disk_type)
+ if len(cim_disks) == 0:
+ if raise_error:
+ raise LsmError(ErrorNumber.DISK_BUSY,
+ "No free %s found" % disk_type_str)
+ else:
+ return []
+
+ chose_cim_disks = []
+ all_free_size = 0
+ for cim_disk in cim_disks:
+ chose_cim_disks.extend([cim_disk])
+ all_free_size += self._disk_total_space_of(cim_disk)
+ if all_free_size >= new_size_bytes:
+ return chose_cim_disks
+ if raise_error:
+ raise LsmError(ErrorNumber.SIZE_INSUFFICIENT_SPACE,
+ "No enough %s to provide size %s(%d)" %
+ (disk_type_str,
+ size_bytes_2_size_human(size_bytes),
+ size_bytes))
+ else:
+ return []
+
+ # All rest RAID type require member are in the same size and same
+ # type.
+ cim_disks_struct = self._free_disks(cim_sys_path, disk_type)
+ for cur_disk_type in cim_disks_struct.keys():
+ for cur_disk_size in cim_disks_struct[cur_disk_type].keys():
+ cur_cim_disks = cim_disks_struct[cur_disk_type][cur_disk_size]
+ if len(cur_cim_disks) == 0:
+ continue
+ chose_cim_disks = []
+ for member_count in range(1, len(cur_cim_disks) + 1):
+ partial_cim_disks = cur_cim_disks[0:member_count]
+ raid_actual_size = self._size_of_disk_raid(
+ partial_cim_disks, raid_type)
+ if new_size_bytes <= raid_actual_size:
+ return partial_cim_disks
+
+ if raise_error:
+ raise LsmError(ErrorNumber.SIZE_INSUFFICIENT_SPACE,
+ "No enough %s " % disk_type_str +
+ "to create %s providing size: %s(%d)" %
+ (Pool.raid_type_to_str(raid_type),
+ size_bytes_2_size_human(size_bytes),
+ size_bytes))
+ else:
+ return []
+
--
1.8.3.1
Gris Ge
2014-03-11 13:02:11 UTC
Permalink
* Just PEP8 clean up. Checked by python-pep8-1.4.6-2.el7.noarch (EPEL7).

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 65 ++++++++++++++++++++++++++-------------------------------
1 file changed, 30 insertions(+), 35 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 303f986..c69acf4 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -263,9 +263,9 @@ class Smis(IStorageAreaNetwork):
SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite'
SNIA_MULTI_SYS_PROFILE = 'Multiple Computer System'
SNIA_JOB_CTRL_PROFILE = 'Job Control'
- SNIA_SMIS_SPEC_VER_1_4='1.4'
- SNIA_SMIS_SPEC_VER_1_5='1.5'
- SNIA_SMIS_SPEC_VER_1_6='1.6'
+ SNIA_SMIS_SPEC_VER_1_4 = '1.4'
+ SNIA_SMIS_SPEC_VER_1_5 = '1.5'
+ SNIA_SMIS_SPEC_VER_1_6 = '1.6'

IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989
@@ -557,7 +557,7 @@ class Smis(IStorageAreaNetwork):
# Checking profile registration support status
namespace_check_list = Smis.DMTF_INTEROP_NAMESPACES
if 'namespace' in u['parameters'] and \
- u['parameters']['namespace'] not in namespace_check_list:
+ u['parameters']['namespace'] not in namespace_check_list:
namespace_check_list.extend([u['parameters']['namespace']])

try:
@@ -581,7 +581,7 @@ class Smis(IStorageAreaNetwork):
if cim_reg_profile['RegisteredName'] == \
Smis.SNIA_BLK_ROOT_PROFILE:
ver = cim_reg_profile['RegisteredVersion']
- self.cim_root_profile_dict[ver]= cim_reg_profile
+ self.cim_root_profile_dict[ver] = cim_reg_profile
if len(self.cim_root_profile_dict) == 0:
raise LsmError(ErrorNumber.NO_SUPPORT,
"SMI-S provider does not support 'Array'"
@@ -817,7 +817,6 @@ class Smis(IStorageAreaNetwork):
if key not in property_list:
property_list.extend([prop])

-
if not self.fallback_mode and \
not self._profile_is_supported(Smis.SNIA_JOB_CTRL_PROFILE,
Smis.SNIA_SMIS_SPEC_VER_1_4,
@@ -1335,10 +1334,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_BLK_SRVS_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=cim_sys_pros)
+ Smis.SNIA_BLK_SRVS_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=cim_sys_pros)
cim_vol_pros = self._new_vol_cim_vol_pros()
for cim_sys in cim_syss:
sys_id = self._sys_id(cim_sys)
@@ -1474,10 +1473,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_BLK_SRVS_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=cim_sys_pros)
+ Smis.SNIA_BLK_SRVS_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=cim_sys_pros)

for cim_sys in cim_syss:
system_id = self._sys_id(cim_sys)
@@ -1570,9 +1569,10 @@ class Smis(IStorageAreaNetwork):
status |= System.STATUS_OK
elif os == Smis.SystemOperationalStatus.DEGRADED:
status |= System.STATUS_DEGRADED
- elif os == Smis.SystemOperationalStatus.ERROR or \
- os == Smis.SystemOperationalStatus.STRESSED or \
- os == Smis.SystemOperationalStatus.NON_RECOVERABLE_ERROR:
+ elif (os == Smis.SystemOperationalStatus.ERROR or
+ os == Smis.SystemOperationalStatus.STRESSED or
+ os ==
+ Smis.SystemOperationalStatus.NON_RECOVERABLE_ERROR):
status |= System.STATUS_ERROR
elif os == Smis.SystemOperationalStatus.PREDICTIVE_FAILURE:
status |= System.STATUS_PREDICTIVE_FAILURE
@@ -1587,7 +1587,6 @@ class Smis(IStorageAreaNetwork):
cim_sys_pros.extend(['ElementName', 'OperationalStatus'])
return cim_sys_pros

-
def _cim_syss(self, property_list=None):
"""
Return a list of root CIM_ComputerSystem.
@@ -1602,10 +1601,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=property_list)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_BLK_ROOT_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=property_list)
+ Smis.SNIA_BLK_ROOT_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=property_list)
if cim_syss is None:
raise LsmError(ErrorNumber.NO_SUPPORT,
"SMI-S %s profile version %s or later is not "
@@ -2394,10 +2393,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_DISK_LITE_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=cim_sys_pros)
+ Smis.SNIA_DISK_LITE_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=cim_sys_pros)

flag_multi_sys = None
if not self.fallback_mode:
@@ -2477,7 +2476,6 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_DiskDrive',
PropertyList=cim_disk_pros)

-
def _traverse_computer_sys(self, cim_sys_path):
"""
Walk through the CIM_ComputerSystem based on SNIA SMI-S 1.6rev4
@@ -3238,7 +3236,7 @@ class Smis(IStorageAreaNetwork):
# We have to chose disks for LSI.
# To make thing simple, we only check 1 raid type for
# possible disk combination
- raid_type =Smis.LSI_DEFAULT_RAID_TYPE
+ raid_type = Smis.LSI_DEFAULT_RAID_TYPE

cim_scs = self._cim_scs(cim_sys.path, [])

@@ -3270,7 +3268,6 @@ class Smis(IStorageAreaNetwork):
if cim_st_set:
in_params['Goal'] = cim_st_set.path

-
disk_type = Disk.DISK_TYPE_UNKNOWN
if Pool.member_type_is_disk(member_type):
disk_type = Pool.member_type_to_disk_type(member_type)
@@ -3495,7 +3492,7 @@ class Smis(IStorageAreaNetwork):
cim_disk_path)

@handle_cim_errors
- def _find_preset_st_set(self, cim_sys_path , raid_type):
+ def _find_preset_st_set(self, cim_sys_path, raid_type):
"""
Usage:
Find first proper CIM_StorageSetting under speficied
@@ -3552,7 +3549,6 @@ class Smis(IStorageAreaNetwork):
PropertyList=['ElementName', 'ThinProvisionedPoolType'])
all_cim_st_sets.extend(tmp_cim_st_sets)

-
raid_type_str = Pool.raid_type_to_str(raid_type)
# According to SNIA suggest, RAID6 can also be writen as RAID5DP
# and etc.
@@ -3569,8 +3565,8 @@ class Smis(IStorageAreaNetwork):

# we prefer thin provisioning CIM_StorageSetting
for cim_st_set in chose_cim_st_sets:
- if ('ThinProvisionedPoolType' in cim_st_set and \
- cim_st_set['ThinProvisionedPoolType'] == \
+ if ('ThinProvisionedPoolType' in cim_st_set and
+ cim_st_set['ThinProvisionedPoolType'] ==
Smis.DMTF_THINP_POOL_TYPE_ALLOCATED):
return cim_st_set

@@ -3858,7 +3854,7 @@ class Smis(IStorageAreaNetwork):
# XIV will return NOTHING, so use EnumerateInstanceNames()
# when you need nothing but the CIMInstanceName
cim_scss_path = self._c.EnumerateInstanceNames(
- 'CIM_StorageConfigurationService')
+ 'CIM_StorageConfigurationService')
except CIMError as e:
# If array does not support CIM_StorageConfigurationService
# we use CIM_ComputerSystem which is mandatory.
@@ -4208,4 +4204,3 @@ class Smis(IStorageAreaNetwork):
size_bytes))
else:
return []
-
--
1.8.3.1
Gris Ge
2014-03-11 13:02:10 UTC
Permalink
* LSI is associating their vendor specific
LSIESG_FreeExtent(Primordial CIM_StorageExtent) to CIM_CompositeExtent.
This should be purged out from pool member checking.

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

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 4f8a9c6..303f986 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -2936,6 +2936,8 @@ class Smis(IStorageAreaNetwork):
PropertyList=pros_list)
cim_pri_exts = []
for cim_sub_ext in cim_sub_exts:
+ if cim_sub_ext.classname == 'LSIESG_FreeExtent':
+ continue
if cim_sub_ext['Primordial']:
cim_pri_exts.extend([cim_sub_ext])
else:
--
1.8.3.1
Gris Ge
2014-03-18 01:51:24 UTC
Permalink
Generally:
1. Enable more interop support.
2. Some trivial fixes for LSI.
3. Rewrite of pool_create()

Changes since V1:
* Trivial fix for these lines:
if key not in property_list:
property_list.extend([prop])
# ^^^^, should be [key]

TODO:
* Capabilities() entries for pool creation.

Gris Ge (7):
smis.py: introduce _cim_sys_of_id() to support interop
smis.py: enable job_status() and job_free() for interop
smis.py: improve disk query
smis.py: fix volume-delete() on LSI
smis.py: sync to latest pool_create() and pool_delete()
smis.py: Fix LSI pool member querying
smis.py: PEP8 clean up

lsm/lsm/smis.py | 1047 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 804 insertions(+), 243 deletions(-)
--
1.8.3.1
Gris Ge
2014-03-18 01:51:25 UTC
Permalink
* Introduced _cim_sys_of_id() to replace _get_cim_instance_by_id().
The latter use EnumerateInstances() which does not works in interop.
Will replace its functions eventually.
* This is just preparation for pool_create() and further changes.

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 54 +++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 45 insertions(+), 9 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index ae28ebc..3374013 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -1496,7 +1496,7 @@ class Smis(IStorageAreaNetwork):

return System(cim_sys['Name'], cim_sys['ElementName'], status)

- def _cim_sys_pros(self):
+ def _new_sys_cim_sys_pros(self):
"""
Return a list of properties required to create a LSM System
"""
@@ -1504,23 +1504,59 @@ class Smis(IStorageAreaNetwork):
cim_sys_pros.extend(['ElementName', 'OperationalStatus'])
return cim_sys_pros

- @handle_cim_errors
- def systems(self, flags=0):
+
+ def _cim_syss(self, property_list=None):
"""
- Return the storage arrays accessible from this plug-in at this time
+ Return a list of root CIM_ComputerSystem.
+ If property_list is not defined, will contain not property.
"""
- cim_sys_pros = self._cim_sys_pros()
+ if property_list is None:
+ property_list = []
+
+ cim_syss = []
+
if self.fallback_mode:
- cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
+ cim_syss = self._get_cim_syss_fallback(property_list=property_list)
else:
cim_syss = self._get_cim_syss(
Smis.SNIA_BLK_ROOT_PROFILE,
Smis.SNIA_SMIS_SPEC_VER_1_4,
strict=False,
- property_list=cim_sys_pros)
+ property_list=property_list)
+ if cim_syss is None:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S %s profile version %s or later is not "
+ % (Smis.SNIA_BLK_ROOT_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4) +
+ "supported")
+ return cim_syss

- if cim_syss is None:
- return []
+ def _cim_sys_of_id(self, sys_id, property_list=None):
+ """
+ Return the CIMInstance-CIM_ComputerSystem for certain system ID.
+ """
+ if property_list is None:
+ property_list = self._property_list_of_id('System')
+ else:
+ for key in self._property_list_of_id('System'):
+ if key not in property_list:
+ property_list.extend([key])
+
+ cim_syss = self._cim_syss(property_list)
+ for cim_sys in cim_syss:
+ if self._sys_id(cim_sys) == sys_id:
+ return cim_sys
+
+ raise LsmError(ErrorNumber.INVALID_SYSTEM,
+ "Invalid system: %s" % sys_id)
+
+ @handle_cim_errors
+ def systems(self, flags=0):
+ """
+ Return the storage arrays accessible from this plug-in at this time
+ """
+ cim_sys_pros = self._new_sys_cim_sys_pros()
+ cim_syss = self._cim_syss(cim_sys_pros)
return [Smis._cim_sys_2_lsm_sys(s) for s in cim_syss]

def _new_init(self, cim_st_hwid):
--
1.8.3.1
Gris Ge
2014-03-18 01:51:26 UTC
Permalink
* By introducing _cim_job_of_id(), job_status() and job_free() now support
interop namespace.
* Renamed _get_cim_scs() to _cim_scs() to meet the name scheme of
_cim_xxxs().

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

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 3374013..37a454c 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -261,6 +261,7 @@ class Smis(IStorageAreaNetwork):
SNIA_BLK_SRVS_PROFILE = 'Block Services'
SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite'
SNIA_MULTI_SYS_PROFILE = 'Multiple Computer System'
+ SNIA_JOB_CTRL_PROFILE = 'Job Control'
SNIA_SMIS_SPEC_VER_1_4='1.4'
SNIA_SMIS_SPEC_VER_1_5='1.5'
SNIA_SMIS_SPEC_VER_1_6='1.6'
@@ -791,6 +792,52 @@ class Smis(IStorageAreaNetwork):

return rc

+ def _cim_job_of_id(self, job_id, property_list=None):
+ """
+ Find out the CIM_ConcreteJob from job ID.
+ Requireing 'Job Contorl' profile version 1.4+
+ """
+ if property_list is None:
+ property_list = self._property_list_of_id('Job')
+ else:
+ for key in self._property_list_of_id('Job'):
+ if key not in property_list:
+ property_list.extend([key])
+
+
+ if not self.fallback_mode and \
+ not self._profile_is_supported(Smis.SNIA_JOB_CTRL_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False):
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target array does not support job control")
+
+ cim_syss = self._cim_syss()
+ for cim_sys in cim_syss:
+ cim_scs = self._cim_scs(cim_sys.path)
+ cim_jobs = []
+ try:
+ cim_jobs = self._c.Associators(
+ cim_scs.path,
+ AssocClass='CIM_OwningJobElement',
+ ResultClass='CIM_ConcreteJob',
+ PropertyList=property_list)
+ 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 array does not support job control")
+ else:
+ raise e
+
+ (ignore, retrieve_data) = self._parse_job_id(job_id)
+ for cim_job in cim_jobs:
+ if self._job_id(cim_job, retrieve_data) == job_id:
+ return cim_job
+
+ raise LsmError(ErrorNumber.INVALID_JOB,
+ "Invalid job ID: %s" % job_id)
+
@handle_cim_errors
def job_status(self, job_id, flags=0):
"""
@@ -803,8 +850,7 @@ class Smis(IStorageAreaNetwork):
cim_job_pros.extend(['JobState', 'PercentComplete',
'ErrorDescription', 'OperationalStatus'])

- cim_job = self._get_cim_instance_by_id('Job', job_id, False,
- cim_job_pros)
+ cim_job = self._cim_job_of_id(job_id, cim_job_pros)

job_state = cim_job['JobState']

@@ -2247,7 +2293,7 @@ class Smis(IStorageAreaNetwork):
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id)
+ cim_job = self._cim_job_of_id(job_id, ['DeleteOnCompletion'])

# See if we should delete the job
if not cim_job['DeleteOnCompletion']:
@@ -3066,7 +3112,7 @@ class Smis(IStorageAreaNetwork):
Delete a Pool via CIM_StorageConfigurationService.DeleteStoragePool
"""
cim_sys = self._get_cim_instance_by_id('System', pool.system_id, False)
- cim_scs = self._get_cim_scs(cim_sys.path, [])
+ cim_scs = self._cim_scs(cim_sys.path, [])

cim_pool = self._get_cim_instance_by_id('Pool', pool.id, False)
in_params = {'Pool': cim_pool.path}
@@ -3086,7 +3132,7 @@ class Smis(IStorageAreaNetwork):
CreateOrModifyStoragePool()
"""
cim_sys = self._get_cim_instance_by_id('System', system_id, False)
- cim_scs = self._get_cim_scs(cim_sys.path, [])
+ cim_scs = self._cim_scs(cim_sys.path, [])

# we does not support defining thinp_type yet.
# just using whatever provider set.
@@ -3416,7 +3462,7 @@ class Smis(IStorageAreaNetwork):
"type or add different RAID type tier")
return new_in_params

- def _get_cim_scs(self, cim_sys_path, property_list=None):
+ def _cim_scs(self, cim_sys_path, property_list=None):
"""
Usage:
Find out the CIM_StorageConfigurationService base on
--
1.8.3.1
Gris Ge
2014-03-18 01:51:27 UTC
Permalink
* Split disk type and disk total space codes out. Prepare for auto choosing
disk for pool_create().
* New _cim_disk() method to meet the name scheme of _cim_xxxs().
* New method of LSI disk type checking:
CIM_DiskDrive['MediaType'] then CIM_ProtocolEndpoint

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 151 +++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 110 insertions(+), 41 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 37a454c..db58e39 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -269,6 +269,10 @@ class Smis(IStorageAreaNetwork):
IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989

+ LSI_DISK_MEDIA_TYPE_HDD = 0
+ LSI_DISK_MEDIA_TYPE_SSD = 1
+ LSI_DISK_MEDIA_TYPE_SSD_FLASH = 2
+
class RepSvc(object):

class Action(object):
@@ -2379,21 +2383,15 @@ class Smis(IStorageAreaNetwork):
# Hence DiskDrive might not associated to top level
# CIM_ComputerSystem

+ cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
for cim_sys in cim_syss:
- cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
- cim_disks = self._c.Associators(cim_sys.path,
- AssocClass='CIM_SystemDevice',
- ResultClass='CIM_DiskDrive',
- PropertyList=cim_disk_pros)
+ cim_disks = self._cim_disks(cim_sys.path, cim_disk_pros)
if flag_multi_sys is not None:
# Checking Disks of sub level ComputerSystems.
cim_sub_syss_path = self._traverse_computer_sys(cim_sys.path)
for cim_sub_sys_path in cim_sub_syss_path:
- cim_sub_disks = self._c.Associators(
- cim_sub_sys_path,
- AssocClass='CIM_SystemDevice',
- ResultClass='CIM_DiskDrive',
- PropertyList=cim_disk_pros)
+ cim_sub_disks = self._cim_disks(
+ cim_sub_sys_path, cim_disk_pros)
if cim_sub_disks:
cim_disks.extend(cim_sub_disks)
# Clean up the duplicate as SNIA said DiskDrive can be
@@ -2414,6 +2412,38 @@ class Smis(IStorageAreaNetwork):
[self._new_disk(cim_disk, cim_ext, sys_id, flags)])
return rc

+ def _cim_disks(self, cim_sys_path, cim_disk_pros=None):
+ """
+ Usage:
+ Get all CIM_DiskDrive from this association:
+
+ CIM_ComputerSystem
+ |
+ | (CIM_SystemDevice)
+ |
+ v
+ CIM_DiskDrive
+ Return a list of CIMInstance-CIM_DiskDrive with
+ PropertyList from self._new_disk_cim_disk_pros()
+ Will not check fallback_mode and support status of
+ "Disk Drive Lite" profile, caller should do that.
+ Parameter:
+ cim_sys_path # CIMInstanceName-CIM_ComputerSystem
+ Returns:
+ cim_disks # a list of CIMInstance-CIM_DiskDrive
+ or
+ [] #
+ Exceptions:
+ N/A
+ """
+ if cim_disk_pros is None:
+ cim_disk_pros = []
+ return self._c.Associators(cim_sys_path,
+ AssocClass='CIM_SystemDevice',
+ ResultClass='CIM_DiskDrive',
+ PropertyList=cim_disk_pros)
+
+
def _traverse_computer_sys(self, cim_sys_path):
"""
Walk through the CIM_ComputerSystem based on SNIA SMI-S 1.6rev4
@@ -2456,7 +2486,7 @@ class Smis(IStorageAreaNetwork):
Return all CIM_DiskDrive Properties needed to create a Disk object.
"""
pros = ['OperationalStatus', 'Name', 'SystemName',
- 'Caption', 'InterconnectType', 'DiskType']
+ 'Caption', 'InterconnectType', 'DiskType', 'MediaType']
if flag == Disk.RETRIEVE_FULL_INFO:
pros.extend(['ErrorDescription', 'ErrorCleared'])
return pros
@@ -2506,6 +2536,74 @@ class Smis(IStorageAreaNetwork):
Smis._DMTF_STAUTS_TO_DISK_STATUS_INFO[dmtf_status])
return (status, status_info)

+ def _disk_type_of(self, cim_disk):
+ """
+ Usage:
+ Check disk type of CIMInstance-CIM_DiskDrive.
+ Requireing these properties:
+ 'InterconnectType', 'Caption', 'DiskType',
+ For LSI, we require these properties:
+ 'Type', 'MediaType'
+ Parameter:
+ cim_disk # CIMInstance-CIM_DiskDrive
+ Returns:
+ Disk.DISK_TYPE_XXX
+ Exceptions:
+ N/A
+ """
+ disk_type = Disk.DISK_TYPE_UNKNOWN
+ # LSI way for checking disk type
+ if cim_disk.classname == 'LSIESG_DiskDrive':
+ if cim_disk['MediaType'] == Smis.LSI_DISK_MEDIA_TYPE_SSD or \
+ cim_disk['MediaType'] == Smis.LSI_DISK_MEDIA_TYPE_SSD_FLASH:
+ return Disk.DISK_TYPE_SSD
+ elif cim_disk['MediaType'] == Smis.LSI_DISK_MEDIA_TYPE_HDD:
+ disk_type = Disk.DISK_TYPE_HDD
+
+ 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':
+ return Disk.DISK_TYPE_SATA
+ if ccn == 'LSIESG_TargetSASProtocolEndpoint':
+ return Disk.DISK_TYPE_SAS
+ return disk_type
+
+ # 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.DISK_TYPE_NL_SAS
+
+ if disk_type == Disk.DISK_TYPE_UNKNOWN and 'DiskType' in cim_disk:
+ disk_type = \
+ Smis.dmtf_disk_type_2_lsm_disk_type(cim_disk['DiskType'])
+
+ return disk_type
+
+ def _disk_total_space_of(self, cim_disk):
+ """
+ Use self._pri_cim_ext_of_cim_disk() to get Primordial
+ CIM_StorageExtent, then retrun
+ cim_ext['BlockSize'] * cim_ext['NumberOfBlocks']
+
+ Return 0 if failure.
+ """
+ cim_ext_pros = ['BlockSize', 'NumberOfBlocks']
+ cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path, cim_ext_pros)
+ if 'BlockSize' in cim_ext and 'NumberOfBlocks' in cim_ext:
+ return int(cim_ext['BlockSize'] * cim_ext['NumberOfBlocks'])
+ return 0
+
def _new_disk(self, cim_disk, cim_ext, sys_id, flag_full_info=0):
"""
Takes a CIM_DiskDrive and CIM_StorageExtent, returns a lsm Disk
@@ -2516,7 +2614,7 @@ class Smis(IStorageAreaNetwork):
name = ''
block_size = Disk.BLOCK_SIZE_NOT_FOUND
num_of_block = Disk.BLOCK_COUNT_NOT_FOUND
- disk_type = Disk.DISK_TYPE_UNKNOWN
+ disk_type = self._disk_type_of(cim_disk)
status_info = ''

# These are mandatory
@@ -2530,35 +2628,6 @@ class Smis(IStorageAreaNetwork):
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.DISK_TYPE_NL_SAS
-
- if disk_type == Disk.DISK_TYPE_UNKNOWN and 'DiskType' in cim_disk:
- disk_type = \
- Smis.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.DISK_TYPE_SATA
- if ccn == 'LSIESG_TargetSASProtocolEndpoint':
- disk_type = Disk.DISK_TYPE_SAS
-
optionals = OptionalData()
if flag_full_info == Disk.RETRIEVE_FULL_INFO:
opt_pro_dict = {
--
1.8.3.1
Gris Ge
2014-03-18 01:51:28 UTC
Permalink
* New LSI SMI-S provider(lsi_mr_hhr-00.50.0004-rhel6.x86_64)
will return pywbem.CIM_ERR_NOT_SUPPORTED for CIM_StorageSynchronized

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index db58e39..c074ede 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -1740,7 +1740,8 @@ class Smis(IStorageAreaNetwork):
ss = self._c.References(lun_path,
ResultClass='CIM_StorageSynchronized')
except pywbem.CIMError as e:
- if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
+ if e[0] == pywbem.CIM_ERR_INVALID_CLASS or \
+ e[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
return
else:
raise e
--
1.8.3.1
Gris Ge
2014-03-18 01:51:29 UTC
Permalink
* Almost rewrite pool_create(). Introduced many duplicate codes for LSI
vendor specific pool_create(), but that make work flow much clearer and
easier to maintain.

* As new pool_create() and pool_delete() required, returned Pool will contain
full optional_data.

* Interop supported. Tested on:
1. EMC VNX # Interop with ASYNC support
2. IBM XIV # Interop without ASYNC
3. LSI MegaRAID # No interop, no ASYNC

* Since SNIA does not have good way to handle 'Size' and 'InExtents' using
at the same, we add Smis._NEW_POOL_SIZE_OVERHAD for disk choosing.
(SNIA SMI-S 1.6.1 draft 2 introduced disk type in CIM_StorageSetting,
which will fix this problem, we will code it out once it released)

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 736 +++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 574 insertions(+), 162 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index c074ede..b8b4113 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -23,7 +23,8 @@ import traceback
from pywbem import CIMError

from iplugin import IStorageAreaNetwork
-from common import Error, uri_parse, LsmError, ErrorNumber, JobStatus, md5
+from common import Error, uri_parse, LsmError, ErrorNumber, JobStatus, md5, \
+ size_human_2_size_bytes, size_bytes_2_size_human
from data import Pool, Initiator, Volume, AccessGroup, System, Capabilities,\
Disk, OptionalData, txt_a
from version import VERSION
@@ -273,6 +274,14 @@ class Smis(IStorageAreaNetwork):
LSI_DISK_MEDIA_TYPE_SSD = 1
LSI_DISK_MEDIA_TYPE_SSD_FLASH = 2

+ LSI_DEFAULT_RAID_TYPE = Pool.RAID_TYPE_RAID0
+ # this is define by us not LSI. We just want to make thing simple
+ # when user creating new pool without defining raid type
+
+ _NEW_POOL_SIZE_OVERHAD = size_human_2_size_bytes("100MiB")
+ # This constant is used by _auto_choose_disks(), check its comments for
+ # detail
+
class RepSvc(object):

class Action(object):
@@ -1239,13 +1248,17 @@ class Smis(IStorageAreaNetwork):
For SYNC CreateOrModifyElementFromStoragePool action.
The new CIM_StoragePool is stored in out['Pool']
"""
- pool_pros = self._new_pool_cim_pool_pros()
+ pool_pros = self._new_pool_cim_pool_pros(flag_full_info=True)

if 'Pool' in out:
cim_new_pool = self._c.GetInstance(
out['Pool'],
PropertyList=pool_pros)
- return self._new_pool(cim_new_pool)
+ pool = self._new_pool(cim_new_pool)
+ opt_pro_dict = self._pool_opt_data(cim_new_pool)
+ for key, value in opt_pro_dict.items():
+ pool.optional_data.set(key, value)
+ return pool
else:
raise LsmError(ErrorNumber.INTERNAL_ERROR,
"Got not new Pool from out of InvokeMethod" +
@@ -1286,12 +1299,16 @@ class Smis(IStorageAreaNetwork):
"""
Given a CIMInstance of CIM_ConcreteJob, return a LSM Pool
"""
- pool_pros = self._new_pool_cim_pool_pros()
+ pool_pros = self._new_pool_cim_pool_pros(flag_full_info=True)
cim_pools = self._c.Associators(cim_job.path,
AssocClass='CIM_AffectedJobElement',
ResultClass='CIM_StoragePool',
PropertyList=pool_pros)
- return self._new_pool(cim_pools[0])
+ pool = self._new_pool(cim_pools[0])
+ opt_pro_dict = self._pool_opt_data(cim_pools[0])
+ for key, value in opt_pro_dict.items():
+ pool.optional_data.set(key, value)
+ return pool

@handle_cim_errors
def volumes(self, flags=0):
@@ -1326,7 +1343,7 @@ class Smis(IStorageAreaNetwork):
for cim_sys in cim_syss:
sys_id = self._sys_id(cim_sys)
pool_pros = self._property_list_of_id('Pool')
- for cim_pool in self._pools(cim_sys, pool_pros):
+ for cim_pool in self._cim_pools(cim_sys.path, pool_pros):
pool_id = self._pool_id(cim_pool)
cim_vols = self._c.Associators(
cim_pool.path,
@@ -1390,7 +1407,7 @@ class Smis(IStorageAreaNetwork):
else:
return cim_syss

- def _pools(self, cim_sys, property_list=None):
+ def _cim_pools(self, cim_sys_path, property_list=None):
pros = []
if property_list is None:
pros = ['Primordial']
@@ -1399,13 +1416,29 @@ class Smis(IStorageAreaNetwork):
if 'Primordial' not in pros:
pros.extend(['Primordial'])

- cim_pools = self._c.Associators(cim_sys.path,
+ cim_pools = self._c.Associators(cim_sys_path,
AssocClass='CIM_HostedStoragePool',
ResultClass='CIM_StoragePool',
PropertyList=pros)

return [p for p in cim_pools if not p["Primordial"]]

+ def _cim_pool_of_id(self, cim_sys_path, pool_id, property_list=None):
+ if property_list is None:
+ property_list = self._property_list_of_id("Pool")
+ else:
+ for key in self._property_list_of_id("Pool"):
+ if key not in property_list:
+ property_list.extend([key])
+
+ cim_pools = self._cim_pools(cim_sys_path, property_list)
+ for cim_pool in cim_pools:
+ if self._pool_id(cim_pool) == pool_id:
+ return cim_pool
+
+ raise LsmError(ErrorNumber.INVALID_POOL,
+ "Invalid pool: %s" % pool_id)
+
def _new_pool_cim_pool_pros(self, flag_full_info=False):
"""
Return a list of properties for creating new pool.
@@ -1448,7 +1481,7 @@ class Smis(IStorageAreaNetwork):

for cim_sys in cim_syss:
system_id = self._sys_id(cim_sys)
- for cim_pool in self._pools(cim_sys, cim_pool_pros):
+ for cim_pool in self._cim_pools(cim_sys.path, cim_pool_pros):
# Skip spare storage pool.
if 'Usage' in cim_pool and \
cim_pool['Usage'] == Smis.DMTF_POOL_USAGE_SPARE:
@@ -3181,10 +3214,10 @@ class Smis(IStorageAreaNetwork):
"""
Delete a Pool via CIM_StorageConfigurationService.DeleteStoragePool
"""
- cim_sys = self._get_cim_instance_by_id('System', pool.system_id, False)
+ cim_sys = self._cim_sys_of_id(pool.system_id)
cim_scs = self._cim_scs(cim_sys.path, [])
+ cim_pool = self._cim_pool_of_id(cim_sys.path, pool.id)

- cim_pool = self._get_cim_instance_by_id('Pool', pool.id, False)
in_params = {'Pool': cim_pool.path}

return self._pi("pool_delete", Smis.JOB_RETRIEVE_NONE,
@@ -3192,70 +3225,184 @@ class Smis(IStorageAreaNetwork):
cim_scs.path,
**in_params)))[0]

- @handle_cim_errors
- def pool_create(self, system_id, pool_name, raid_type, member_type,
- member_ids, member_count, size_bytes, thinp_type, flags=0):
+ def _pool_create_lsi(self, cim_sys, pool_name, size_bytes,
+ raid_type=Pool.RAID_TYPE_UNKNOWN,
+ member_type=Pool.MEMBER_TYPE_UNKNOWN, flags=0):
"""
- Creating pool via
- CIM_StorageConfigurationService.CreateOrModifyStoragePool()
- TODO: Each vendor are needing different parameters for
- CreateOrModifyStoragePool()
+ LSI Vendor specific way of pool creation.
"""
- cim_sys = self._get_cim_instance_by_id('System', system_id, False)
+ if raid_type == Pool.RAID_TYPE_UNKNOWN:
+ # LSI does not allow InExtents to be NULL.
+ # We have to chose disks for LSI.
+ # To make thing simple, we only check 1 raid type for
+ # possible disk combination
+ raid_type =Smis.LSI_DEFAULT_RAID_TYPE
+
cim_scs = self._cim_scs(cim_sys.path, [])

# we does not support defining thinp_type yet.
# just using whatever provider set.

in_params = {}
- if pool_name:
- in_params['ElementName'] = pool_name
-
- in_cim_exts_path = []
- if member_type == Pool.MEMBER_TYPE_DISK:
- if member_ids and len(member_ids) >= 1:
- cim_exts = self._pri_cim_ext_of_disk_ids(member_ids)
- system_id = None
- for cim_ext in cim_exts:
- tmp_system_id = self._sys_id_child(cim_ext)
- if not system_id:
- system_id = tmp_system_id
- elif system_id != tmp_system_id:
- raise LsmError(ErrorNumber.INVALID_DISK,
- "Specified member are belong to " +
- "two or more system: %s %s" %
- (system_id, tmp_system_id))
- if cim_exts:
- in_cim_exts_path = [x.path for x in cim_exts]
- in_params['InExtents'] = in_cim_exts_path
-
- elif member_type == Pool.MEMBER_TYPE_POOL:
- cim_member_pools_path = []
- for member_id in member_ids:
- cim_member_pools_path.extend(
- [self._get_cim_instance_by_id('Pool', member_id,
- False, None).path])
- in_params['InPools'] = cim_member_pools_path
-
- elif member_type == Pool.MEMBER_TYPE_VOLUME:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Creating Pool against another Volume is not " +
- "supported by SMIS plugin")
- # TODO: support member_count
- if member_count and member_count > 0:
+ in_params['ElementName'] = pool_name
+ in_params['Size'] = pywbem.Uint64(1)
+ # LSI require InExtents define, so the 'Size' just set to 1 bytes
+ # would be OK.
+
+ raise_error = True
+
+ if member_type == Pool.MEMBER_TYPE_UNKNOWN:
+ raise_error = True # We only support disk pool, so raise error
+ # anyway.
+
+ if member_type != Pool.MEMBER_TYPE_UNKNOWN and \
+ not Pool.member_type_is_disk(member_type):
raise LsmError(ErrorNumber.NO_SUPPORT,
- "member_count is not supported by " +
- "SMI-S plugin yet.")
+ "Creating new pool with member type %s(%d) "
+ % (Pool.member_type_to_str(member_type),
+ member_type) + "is not supported")
+
+ # Find CIM_StorageSetting for 'Goal' parameter
+ cim_st_set = self._find_preset_st_set(cim_sys.path, raid_type)
+
+ if cim_st_set:
+ in_params['Goal'] = cim_st_set.path
+
+
+ disk_type = Disk.DISK_TYPE_UNKNOWN
+ if Pool.member_type_is_disk(member_type):
+ disk_type = Pool.member_type_to_disk_type(member_type)
+
+ cim_disks = self._auto_choose_disks(cim_sys.path, size_bytes,
+ raid_type, disk_type, raise_error)
+ if len(cim_disks) > 1:
+ in_params['InExtents'] = []
+ for cim_disk in cim_disks:
+ cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path, None)
+ if cim_ext:
+ in_params['InExtents'].extend([cim_ext.path])
+ else:
+ return (None, None)
+
+ return self._pi("pool_create", Smis.JOB_RETRIEVE_POOL,
+ *(self._c.InvokeMethod(
+ 'CreateOrModifyStoragePool',
+ cim_scs.path, **in_params)))
+
+ @handle_cim_errors
+ def pool_create(self, system_id, pool_name, size_bytes,
+ raid_type=Pool.RAID_TYPE_UNKNOWN,
+ member_type=Pool.MEMBER_TYPE_UNKNOWN, flags=0):
+ """
+ Using SNIA SMI-S 1.4 or later 'Block Service Packpage' profile:
+
+ CIM_StorageConfigurationService.CreateOrModifyStoragePool(
+ InPools = [CIMInstanceName of CIM_StoragePool,],
+ InExtents = [
+ CIMInstanceName of CIM_StorageExtent or CIM_StoragePool, ],
+ Size = Uint64 size,
+ Goal = CIMInstanceName of CIM_StorageSetting,
+ )
+
+ Only support disk pool for now.
+ Basic procedure:
+ 1. If vendor specific procedure available, use vendor specific
+ way only.
+ 2. Use SNIA general procedure (based on Gris's understanding)
+ to setup parameters for CreateOrModifyStoragePool()
+ 3. Use CIM_StorageConfigurationCapabilities to check capability
+ before callout.
+ 4. Call CreateOrModifyStoragePool()
+
+ SNIA general procedure:
+ 1. If raid_type defined, we set 'Goal' by finding predefined
+ CIM_StorageSetting. If not, we leave 'Goal' as undefine.
+ 2. If member_type defeind, we find certain type of disks to setup
+ 'InExtents'. If not, we leave 'InExtents' as undefine.
+ 3. When 'InExtents' was set, we set 'Size' to 1B just in case
+ the requested size exceed the 'InExtents' capable size.
+ 4. In SNIA 1.6.1 draft, allowing Goal defined disk type via
+ properties: InterconnectType, RPM, and etc. I see no
+ vendor support it yet.
+
+ TODO: Check CIM_StoragePool.GetSupportedSizeRange() before
+ execute pool creation call.
+ """
+ cim_sys = self._cim_sys_of_id(system_id)
+
+ if cim_sys.classname == 'LSIESG_MegaRAIDHBA':
+ return self._pool_create_lsi(cim_sys, pool_name, size_bytes,
+ raid_type, member_type, flags)
+
+ cim_scs = self._cim_scs(cim_sys.path, [])
+
+ # we does not support defining thinp_type yet.
+ # just using whatever provider set.
+
+ in_params = {}
+ in_params['ElementName'] = pool_name
+ in_params['Size'] = pywbem.Uint64(size_bytes)

- if size_bytes > 0:
- in_params['Size'] = pywbem.Uint64(size_bytes)
+ raise_error = True

- if raid_type != Pool.RAID_TYPE_UNKNOWN and \
- raid_type != Pool.RAID_TYPE_NOT_APPLICABLE:
- in_params['Goal'] = self._cim_st_set_for_goal(
- raid_type, thinp_type, cim_sys.path)
+ if member_type == Pool.MEMBER_TYPE_UNKNOWN:
+ raise_error = True # We only support disk pool, so raise error
+ # anyway.
+
+ if member_type == Pool.MEMBER_TYPE_UNKNOWN:
+ if raid_type == Pool.RAID_TYPE_UNKNOWN:
+ # 'Size' and 'ElementName' is enough.
+ pass
+ else:
+ # Need use 'Goal' to define RAID type
+ cim_st_set = self._find_preset_st_set(cim_sys.path, raid_type)
+ if cim_st_set is None:
+ if raise_error:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "RAID type %s(%d) is not supported "
+ % (Pool.raid_type_to_str(raid_type),
+ raid_type) +
+ "by target array")
+ else:
+ return (None, None)
+ in_params['Goal'] = cim_st_set.path
+
+ elif Pool.member_type_is_disk(member_type):
+ if raid_type != Pool.RAID_TYPE_UNKNOWN:
+ # Need to set 'Goal' parameter for RAID type
+ cim_st_set = self._find_preset_st_set(cim_sys.path, raid_type)
+ if cim_st_set is None:
+ if raise_error:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "RAID type %s(%d) is not supported "
+ % (Pool.raid_type_to_str(raid_type),
+ raid_type) +
+ "by target array")
+ else:
+ return (None, None)
+ in_params['Goal'] = cim_st_set.path
+
+ disk_type = Pool.member_type_to_disk_type(member_type)
+ if disk_type != Disk.DISK_TYPE_UNKNOWN:
+ # Need to set 'InExtents' parameter for disks
+ cim_disks = self._auto_choose_disks(
+ cim_sys.path, size_bytes, raid_type, disk_type,
+ raise_error)
+ if len(cim_disks) > 1:
+ in_params['InExtents'] = []
+ for cim_disk in cim_disks:
+ cim_ext = self._pri_cim_ext_of_cim_disk(
+ cim_disk.path, None)
+ in_params['InExtents'].extend([cim_ext.path])
+ in_params['Size'] = pywbem.Uint64(1)
+ else:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Creating new pool with member type %s(%d) "
+ % (Pool.member_type_to_str(member_type),
+ member_type) + "is not supported")

in_params = self._pool_chg_paras_check(in_params, cim_sys.path)
+
return self._pi("pool_create", Smis.JOB_RETRIEVE_POOL,
*(self._c.InvokeMethod(
'CreateOrModifyStoragePool',
@@ -3346,11 +3493,30 @@ class Smis(IStorageAreaNetwork):
cim_disk_path)

@handle_cim_errors
- def _find_preset_st_set(self, cim_cap_path, raid_type, thinp_type):
+ def _find_preset_st_set(self, cim_sys_path , raid_type):
"""
Usage:
Find first proper CIM_StorageSetting under speficied
CIM_StorageCapabilities by giving raid_type and thinp_type.
+ Using this associations:
+ CIM_ComputerSystem
+ |
+ | CIM_HostedStoragePool
+ |
+ v
+ CIM_StoragePool (Primordial)
+ |
+ | CIM_ElementCapabilities
+ |
+ CIM_StorageCapabilities
+ |
+ | CIM_StorageSettingsAssociatedToCapabilities
+ |
+ v
+ CIM_StorageSetting (Predefined)
+
+ TODO: Support SPEC 1.6.1 for disk type in CIM_StorageSetting
+ But no vendor support that yet.
Parameter:
cim_cap_path # CIMInstanceName of CIM_StorageCapabilities
raid_type # Pool.RAID_TYPE_XXX
@@ -3360,15 +3526,31 @@ class Smis(IStorageAreaNetwork):
or
None # No match found
"""
- DMTF_CHANGEABLE_TYPE_FIX = 0
- cim_fix_st_sets = self._c.Associators(
- cim_cap_path,
- AssocClass='CIM_StorageSettingsAssociatedToCapabilities',
- ResultClass='CIM_StorageSetting',
- PropertyList=['ElementName',
- 'ThinProvisionedPoolType'])
- if not cim_fix_st_sets:
- return None
+ all_cim_st_sets = []
+ # get Primordial StoragePool
+ cim_pools = self._c.Associators(
+ cim_sys_path,
+ AssocClass='CIM_HostedStoragePool',
+ ResultClass='CIM_StoragePool',
+ PropertyList=['Primordial'])
+
+ for cim_pool in cim_pools:
+ if not cim_pool['Primordial']:
+ continue
+ cim_caps_path = self._c.AssociatorNames(
+ cim_pool.path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_StorageCapabilities')
+
+ for cim_cap_path in cim_caps_path:
+ tmp_cim_st_sets = self._c.Associators(
+ cim_cap_path,
+ AssocClass='CIM_StorageSettingsAssociatedToCapabilities',
+ ResultClass='CIM_StorageSetting',
+ PropertyList=['ElementName', 'ThinProvisionedPoolType'])
+ all_cim_st_sets.extend(tmp_cim_st_sets)
+
+
raid_type_str = Pool.raid_type_to_str(raid_type)
# According to SNIA suggest, RAID6 can also be writen as RAID5DP
# and etc.
@@ -3378,96 +3560,21 @@ class Smis(IStorageAreaNetwork):
elif raid_type_str == 'RAID10':
possible_element_names.extend(['RAID1+0'])

- if thinp_type != Pool.THINP_TYPE_UNKNOWN:
- if thinp_type == Pool.THINP_TYPE_THIN:
- # searching for a thin CIM_StorageSetting
- dmtf_thinp_type = self._lsm_thinp_type_to_dmtf(thinp_type)
-
- for cim_st_set in cim_fix_st_sets:
- if 'ElementName' in cim_st_set \
- and cim_st_set['ElementName'] \
- in possible_element_names \
- and cim_st_set['ThinProvisionedPoolType'] \
- == dmtf_thinp_type:
- return cim_st_set.path
- else: # searching for a Thick CIM_StorageSetting
- for cim_st_set in cim_fix_st_sets:
- if 'ElementName' not in cim_st_set or \
- cim_st_set['ElementName'] not in possible_element_names:
- continue
- if 'ThinProvisionedPoolType' not in cim_st_set:
- return cim_st_set.path
- # EMC define Thick pools with ThinProvisionedPoolType
- # value.
- elif cim_st_set.classname == 'Clar_StoragePoolSetting' \
- and cim_st_set['ThinProvisionedPoolType'] \
- == Smis.EMC_THINP_POOL_TYPE_THICK:
- return cim_st_set.path
- else: # Searching a CIM_StorageSetting regardless Thin or Thick.
- for cim_st_set in cim_fix_st_sets:
- if 'ElementName' in cim_st_set and \
- cim_st_set['ElementName'] in possible_element_names:
- return cim_st_set.path
- return None
+ chose_cim_st_sets = []
+ for cim_st_set in all_cim_st_sets:
+ if cim_st_set['ElementName'] in possible_element_names:
+ chose_cim_st_sets.extend([cim_st_set])

- def _cim_st_set_for_goal(self, raid_type, thinp_type, cim_sys_path):
- """
- Usage:
- Find out the array pre-defined CIM_StorageSetting for certain RAID
- Level. Only check CIM_StorageSetting['ElementName'] for RAID type,
- and CIM_StorageSetting['ThinProvisionedPoolType'] for Thin
- Provision setting.
- Even SNIA defined a way to create new setting, but we find out
- that not a good way to follow.
- Parameter:
- raid_type # Tier.RAID_TYPE_XXX
- disk_count # how many disks will this RAID group hold.
- cim_sys_path # CIMInstanceName of CIM_ComputerSystem.
- Returns:
- cim_st_set_path # Found or created CIMInstanceName of
- # CIM_StorageSetting
- Exceptions:
- LsmError
- ErrorNumber.NO_SUPPORT # Failed to find out
- # suitable CIM_StorageSetting
- """
- cim_chose_st_set_path = None
- # We will try to find the existing CIM_StorageSetting
- # with ElementName equal to raid_type_str
- # potted(pre-defined) CIM_StorageSetting
- cim_pool_path = None
- cim_pools = self._c.Associators(cim_sys_path,
- ResultClass='CIM_StoragePool',
- PropertyList=['Primordial'])
- # Base on SNIA commanded, each array should provide a
- # Primordial pool.
- for cim_tmp_pool in cim_pools:
- if cim_tmp_pool['Primordial']:
- cim_pool_path = cim_tmp_pool.path
- break
- if not cim_pool_path:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Target storage array does not have "
- "Primordial CIM_StoragePool")
- cim_caps = self._c.Associators(
- cim_pool_path,
- ResultClass='CIM_StorageCapabilities',
- PropertyList=['ElementType'])
- for cim_cap in cim_caps:
- cim_tmp_st_set = self._find_preset_st_set(
- cim_cap.path,
- raid_type,
- thinp_type)
- if cim_tmp_st_set:
- cim_chose_st_set_path = cim_tmp_st_set
- break
- if not cim_chose_st_set_path:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Current array does not support RAID type: " +
- "%s and thinp_type %s" %
- (Pool.raid_type_to_str(raid_type),
- Pool.thinp_type_to_str(thinp_type)))
- return cim_chose_st_set_path
+ # we prefer thin provisioning CIM_StorageSetting
+ for cim_st_set in chose_cim_st_sets:
+ if ('ThinProvisionedPoolType' in cim_st_set and \
+ cim_st_set['ThinProvisionedPoolType'] == \
+ Smis.DMTF_THINP_POOL_TYPE_ALLOCATED):
+ return cim_st_set
+
+ if len(chose_cim_st_sets) > 0:
+ return chose_cim_st_sets[0]
+ return None

def _pool_chg_paras_check(self, in_params, cim_sys_path):
"""
@@ -3731,7 +3838,7 @@ class Smis(IStorageAreaNetwork):
Returns:
cim_syss # A list of CIMInstanceName of CIM_ComputerSystem
or
- None
+ []
"""
sys_id_pros = self._property_list_of_id('System')
flag_full_info = False
@@ -3795,3 +3902,308 @@ class Smis(IStorageAreaNetwork):
return needed_cim_syss
else:
return cim_syss
+
+ def _free_disks_list(self, cim_sys_path, disk_type=Disk.DISK_TYPE_UNKNOWN):
+ """
+ Usage:
+ Return a list of cim_disk which is free.
+ Using two ways to check free disks:
+ A. CIM_StoragePool.GetAvailableExtents(
+ Goal=CIMInstanceName of CIM_StorageSetting)
+ B. Check for those disks not used by any pool.
+
+ Method A) is optional SNIA SMI-S Block Service Package
+ (SPEC 1.4 to 1.6)
+
+ Since even LSI support method A(without profile registering),
+ we skip method B)
+
+ When disk_type define, will only contain defined type of disk
+ in return list.
+ The cim_disk will only contain properties defined in
+ Smis._new_disk_cim_ext_pros()
+ TODO: Need tests again IBM SVC which use remote volume as pool
+ member.
+ Parameter:
+ cim_sys_path # CIMInstanceName of CIM_ComputerSystem
+ disk_type # Disk.DISK_TYPE_XXX
+ Returns:
+ [cim_disk, ] # a list of items.
+ or
+ [] # Nothing found
+ Exceptions:
+ LsmError
+ ErrorNumber.INTERNAL_ERROR
+ * When no Primordial StoragePool found.
+ N/A
+ """
+ rc = []
+
+ if self._profile_is_supported(Smis.SNIA_BLK_SRVS_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False) and \
+ not self._profile_is_supported(Smis.SNIA_DISK_LITE_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False):
+ # Support 'Disk Drive Lite' 1.4+ is prerequisite.
+ return []
+
+ # get Primordial StoragePool
+ cim_pools = self._c.Associators(
+ cim_sys_path,
+ AssocClass='CIM_HostedStoragePool',
+ ResultClass='CIM_StoragePool',
+ PropertyList=['Primordial'])
+
+ cim_pools = [p for p in cim_pools if p["Primordial"]]
+ if len(cim_pools) == 0:
+ raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ "No Primordial CIM_StoragePool found for "
+ "system %s, might be a provider's bug"
+ % cim_sys_path)
+ cim_disk_pros = self._new_disk_cim_disk_pros()
+ # LSI has more than 1 Primordial StoragePool :(
+ for cim_pool in cim_pools:
+ return_code = 0
+ out = dict()
+ # TODO: Use Goal parameter of
+ # CIM_StoragePool.GetAvailableExtents() to filter
+ # CIM_StorageExtent
+ try:
+ (return_code, out) = self._c.InvokeMethod(
+ 'GetAvailableExtents',
+ cim_pool.path)
+ except CIMError as e:
+ if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
+ e[0] == pywbem.CIM_ERR_NOT_FOUND:
+ break
+ else:
+ raise e
+
+ if return_code == Smis.INVOKE_OK and \
+ 'AvailableExtents' in out and \
+ out['AvailableExtents']:
+ for cim_pri_ext_path in out['AvailableExtents']:
+ rc.extend(
+ self._c.Associators(
+ cim_pri_ext_path,
+ AssocClass='CIM_MediaPresent',
+ ResultClass='CIM_DiskDrive',
+ PropertyList=cim_disk_pros))
+ if disk_type != Disk.DISK_TYPE_UNKNOWN:
+ cleanup_rc = []
+ for cim_disk in rc:
+ if self._disk_type_of(cim_disk) == disk_type:
+ cleanup_rc.extend([cim_disk])
+
+ rc = cleanup_rc
+ return rc
+
+ def _free_disks(self, cim_sys_path, disk_type=Disk.DISK_TYPE_UNKNOWN):
+ """
+ Usage:
+ Return a structure like this:
+ {
+ Disk.disk_type = {
+ Disk.total_space = [ cim_disk, ],
+ },
+ }
+ When disk_type define, will only contain defined type of disk
+ in return structure.
+ The cim_disk will only contain properties defined in
+ Smis._new_disk_cim_ext_pros()
+ Parameter:
+ cim_sys_path # CIMInstanceName of CIM_ComputerSystem
+ disk_type # Disk.DISK_TYPE_XXX
+ Returns:
+ free_disk_t # Check above
+ or
+ dcit() # Nothing found
+ Exceptions:
+ N/A
+ """
+ rc = dict()
+ free_cim_disks = self._free_disks_list(cim_sys_path, disk_type)
+ if len(free_cim_disks) == 0:
+ return rc
+
+ for cim_disk in free_cim_disks:
+ disk_type = self._disk_type_of(cim_disk)
+ disk_size = self._disk_total_space_of(cim_disk)
+ if disk_size == 0 or disk_type == Disk.DISK_TYPE_UNKNOWN:
+ continue
+ if disk_type not in rc.keys():
+ rc[disk_type] = dict()
+
+ if disk_size not in rc[disk_type].keys():
+ rc[disk_type][disk_size] = []
+ rc[disk_type][disk_size].extend([cim_disk])
+
+ return rc
+
+ def _size_of_disk_raid(self, cim_disks, raid_type):
+ member_sizes = []
+ for cim_disk in cim_disks:
+ disk_size = self._disk_total_space_of(cim_disk)
+ if disk_size > 1:
+ member_sizes.extend([disk_size])
+
+ if len(member_sizes) == 0:
+ return 0
+
+ all_size = 0
+ member_count = len(member_sizes)
+ for member_size in member_sizes:
+ all_size += member_size
+
+ # assuming all raid member is in the same size which was already
+ # checked by caller. (JBOD and NOT_APPLICABLE does not require that)
+ member_size = member_sizes[0]
+
+ if raid_type == Pool.RAID_TYPE_JBOD or \
+ raid_type == Pool.RAID_TYPE_NOT_APPLICABLE or \
+ raid_type == Pool.RAID_TYPE_RAID0:
+ return int(all_size)
+ elif (raid_type == Pool.RAID_TYPE_RAID1 or
+ raid_type == Pool.RAID_TYPE_RAID10):
+ if member_count % 2 == 1:
+ return 0
+ return int(all_size/2)
+ elif (raid_type == Pool.RAID_TYPE_RAID3 or
+ raid_type == Pool.RAID_TYPE_RAID4 or
+ raid_type == Pool.RAID_TYPE_RAID5):
+ if member_count < 3:
+ return 0
+ return int(all_size - member_size)
+ elif raid_type == Pool.RAID_TYPE_RAID50:
+ if member_count < 6 or member_count % 2 == 1:
+ return 0
+ return int(all_size - member_size*2)
+ elif raid_type == Pool.RAID_TYPE_RAID6:
+ if member_count < 4:
+ return 0
+ return int(all_size - member_size * 2)
+ elif raid_type == Pool.RAID_TYPE_RAID60:
+ if member_count < 8 or member_count % 2 == 1:
+ return 0
+ return int(all_size - member_size*4)
+ elif raid_type == Pool.RAID_TYPE_RAID51:
+ if member_count < 6 or member_count % 2 == 1:
+ return 0
+ return int(all_size/2 - member_size)
+ elif raid_type == Pool.RAID_TYPE_RAID61:
+ if member_count < 8 or member_count % 2 == 1:
+ return 0
+ return int(all_size/2 - member_size*2)
+ raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ "_size_of_raid() got invalid raid type: " +
+ "%s(%d)" % (Pool.raid_type_to_str(raid_type),
+ raid_type))
+
+ def _auto_choose_disks(self, cim_sys_path, size_bytes, raid_type,
+ disk_type, raise_error=False):
+ """
+ Usage:
+ Automatically choose the correct disks to assemble defined
+ RAID.
+ Considering the pool/raid overhead, size_bytes will increase
+ Smis._NEW_POOL_SIZE_OVERHAD
+ Raise LsmError if nothing found when raise_error is True.
+ Return [] if nothing found when raise_error is False.
+ Parameter:
+ cim_sys_path # CIMInstanceName of CIM_ComputerSystem
+ size_bytes # int, requested size for new RAID.
+ raid_type # Pool.RAID_TYPE_XXX
+ disk_type # Disk.DISK_TYPE_XXX
+ raise_error # True or False, raise on error or not.
+ Returns:
+ [cim_disk, ] # a list of cim_disk
+ or
+ [] # Nothing found if raise_error is False
+ Exceptions:
+ LsmError
+ ErrorNumber.DISK_BUSY
+ # No free disks
+ ErrorNumber.SIZE_INSUFFICIENT_SPACE
+ # No enough disks or size meet request
+ """
+ new_size_bytes = size_bytes + Smis._NEW_POOL_SIZE_OVERHAD
+
+ disk_type_str = "disk"
+ if disk_type != Disk.DISK_TYPE_UNKNOWN:
+ disk_type_str = "disk(type: %s)" % Disk.disk_type_to_str(disk_type)
+
+ if raid_type == Pool.RAID_TYPE_NOT_APPLICABLE:
+ # NOT_APPLICABLE means pool will only contain one disk.
+ cim_disks = self._free_disks_list(cim_sys_path, disk_type)
+ if len(cim_disks) == 0:
+ if raise_error:
+ raise LsmError(ErrorNumber.DISK_BUSY,
+ "No free %s found" % disk_type_str)
+ else:
+ return []
+
+ for cim_disk in cim_disks:
+ if self._disk_total_space_of(cim_disk) >= new_size_bytes:
+ return [cim_disk]
+ if raise_error:
+ raise LsmError(ErrorNumber.SIZE_INSUFFICIENT_SPACE,
+ "No %s is bigger than " % disk_type_str +
+ "expected size: %s(%d)" %
+ (size_bytes_2_size_human(size_bytes),
+ size_bytes))
+ else:
+ return []
+
+ if raid_type == Pool.RAID_TYPE_JBOD:
+ # JBOD does not require all disks in the same size or the same type.
+ cim_disks = self._free_disks_list(cim_sys_path, disk_type)
+ if len(cim_disks) == 0:
+ if raise_error:
+ raise LsmError(ErrorNumber.DISK_BUSY,
+ "No free %s found" % disk_type_str)
+ else:
+ return []
+
+ chose_cim_disks = []
+ all_free_size = 0
+ for cim_disk in cim_disks:
+ chose_cim_disks.extend([cim_disk])
+ all_free_size += self._disk_total_space_of(cim_disk)
+ if all_free_size >= new_size_bytes:
+ return chose_cim_disks
+ if raise_error:
+ raise LsmError(ErrorNumber.SIZE_INSUFFICIENT_SPACE,
+ "No enough %s to provide size %s(%d)" %
+ (disk_type_str,
+ size_bytes_2_size_human(size_bytes),
+ size_bytes))
+ else:
+ return []
+
+ # All rest RAID type require member are in the same size and same
+ # type.
+ cim_disks_struct = self._free_disks(cim_sys_path, disk_type)
+ for cur_disk_type in cim_disks_struct.keys():
+ for cur_disk_size in cim_disks_struct[cur_disk_type].keys():
+ cur_cim_disks = cim_disks_struct[cur_disk_type][cur_disk_size]
+ if len(cur_cim_disks) == 0:
+ continue
+ chose_cim_disks = []
+ for member_count in range(1, len(cur_cim_disks) + 1):
+ partial_cim_disks = cur_cim_disks[0:member_count]
+ raid_actual_size = self._size_of_disk_raid(
+ partial_cim_disks, raid_type)
+ if new_size_bytes <= raid_actual_size:
+ return partial_cim_disks
+
+ if raise_error:
+ raise LsmError(ErrorNumber.SIZE_INSUFFICIENT_SPACE,
+ "No enough %s " % disk_type_str +
+ "to create %s providing size: %s(%d)" %
+ (Pool.raid_type_to_str(raid_type),
+ size_bytes_2_size_human(size_bytes),
+ size_bytes))
+ else:
+ return []
+
--
1.8.3.1
Gris Ge
2014-03-18 01:51:30 UTC
Permalink
* LSI is associating their vendor specific
LSIESG_FreeExtent(Primordial CIM_StorageExtent) to CIM_CompositeExtent.
This should be purged out from pool member checking.

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

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index b8b4113..141cfbc 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -2936,6 +2936,8 @@ class Smis(IStorageAreaNetwork):
PropertyList=pros_list)
cim_pri_exts = []
for cim_sub_ext in cim_sub_exts:
+ if cim_sub_ext.classname == 'LSIESG_FreeExtent':
+ continue
if cim_sub_ext['Primordial']:
cim_pri_exts.extend([cim_sub_ext])
else:
--
1.8.3.1
Gris Ge
2014-03-18 01:51:31 UTC
Permalink
* Just PEP8 clean up. Checked by python-pep8-1.4.6-2.el7.noarch (EPEL7).

Signed-off-by: Gris Ge <***@redhat.com>
---
lsm/lsm/smis.py | 65 ++++++++++++++++++++++++++-------------------------------
1 file changed, 30 insertions(+), 35 deletions(-)

diff --git a/lsm/lsm/smis.py b/lsm/lsm/smis.py
index 141cfbc..8b1a892 100644
--- a/lsm/lsm/smis.py
+++ b/lsm/lsm/smis.py
@@ -263,9 +263,9 @@ class Smis(IStorageAreaNetwork):
SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite'
SNIA_MULTI_SYS_PROFILE = 'Multiple Computer System'
SNIA_JOB_CTRL_PROFILE = 'Job Control'
- SNIA_SMIS_SPEC_VER_1_4='1.4'
- SNIA_SMIS_SPEC_VER_1_5='1.5'
- SNIA_SMIS_SPEC_VER_1_6='1.6'
+ SNIA_SMIS_SPEC_VER_1_4 = '1.4'
+ SNIA_SMIS_SPEC_VER_1_5 = '1.5'
+ SNIA_SMIS_SPEC_VER_1_6 = '1.6'

IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989
@@ -557,7 +557,7 @@ class Smis(IStorageAreaNetwork):
# Checking profile registration support status
namespace_check_list = Smis.DMTF_INTEROP_NAMESPACES
if 'namespace' in u['parameters'] and \
- u['parameters']['namespace'] not in namespace_check_list:
+ u['parameters']['namespace'] not in namespace_check_list:
namespace_check_list.extend([u['parameters']['namespace']])

try:
@@ -581,7 +581,7 @@ class Smis(IStorageAreaNetwork):
if cim_reg_profile['RegisteredName'] == \
Smis.SNIA_BLK_ROOT_PROFILE:
ver = cim_reg_profile['RegisteredVersion']
- self.cim_root_profile_dict[ver]= cim_reg_profile
+ self.cim_root_profile_dict[ver] = cim_reg_profile
if len(self.cim_root_profile_dict) == 0:
raise LsmError(ErrorNumber.NO_SUPPORT,
"SMI-S provider does not support 'Array'"
@@ -817,7 +817,6 @@ class Smis(IStorageAreaNetwork):
if key not in property_list:
property_list.extend([key])

-
if not self.fallback_mode and \
not self._profile_is_supported(Smis.SNIA_JOB_CTRL_PROFILE,
Smis.SNIA_SMIS_SPEC_VER_1_4,
@@ -1335,10 +1334,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_BLK_SRVS_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=cim_sys_pros)
+ Smis.SNIA_BLK_SRVS_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=cim_sys_pros)
cim_vol_pros = self._new_vol_cim_vol_pros()
for cim_sys in cim_syss:
sys_id = self._sys_id(cim_sys)
@@ -1474,10 +1473,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_BLK_SRVS_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=cim_sys_pros)
+ Smis.SNIA_BLK_SRVS_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=cim_sys_pros)

for cim_sys in cim_syss:
system_id = self._sys_id(cim_sys)
@@ -1570,9 +1569,10 @@ class Smis(IStorageAreaNetwork):
status |= System.STATUS_OK
elif os == Smis.SystemOperationalStatus.DEGRADED:
status |= System.STATUS_DEGRADED
- elif os == Smis.SystemOperationalStatus.ERROR or \
- os == Smis.SystemOperationalStatus.STRESSED or \
- os == Smis.SystemOperationalStatus.NON_RECOVERABLE_ERROR:
+ elif (os == Smis.SystemOperationalStatus.ERROR or
+ os == Smis.SystemOperationalStatus.STRESSED or
+ os ==
+ Smis.SystemOperationalStatus.NON_RECOVERABLE_ERROR):
status |= System.STATUS_ERROR
elif os == Smis.SystemOperationalStatus.PREDICTIVE_FAILURE:
status |= System.STATUS_PREDICTIVE_FAILURE
@@ -1587,7 +1587,6 @@ class Smis(IStorageAreaNetwork):
cim_sys_pros.extend(['ElementName', 'OperationalStatus'])
return cim_sys_pros

-
def _cim_syss(self, property_list=None):
"""
Return a list of root CIM_ComputerSystem.
@@ -1602,10 +1601,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=property_list)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_BLK_ROOT_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=property_list)
+ Smis.SNIA_BLK_ROOT_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=property_list)
if cim_syss is None:
raise LsmError(ErrorNumber.NO_SUPPORT,
"SMI-S %s profile version %s or later is not "
@@ -2394,10 +2393,10 @@ class Smis(IStorageAreaNetwork):
cim_syss = self._get_cim_syss_fallback(property_list=cim_sys_pros)
else:
cim_syss = self._get_cim_syss(
- Smis.SNIA_DISK_LITE_PROFILE,
- Smis.SNIA_SMIS_SPEC_VER_1_4,
- strict=False,
- property_list=cim_sys_pros)
+ Smis.SNIA_DISK_LITE_PROFILE,
+ Smis.SNIA_SMIS_SPEC_VER_1_4,
+ strict=False,
+ property_list=cim_sys_pros)

flag_multi_sys = None
if not self.fallback_mode:
@@ -2477,7 +2476,6 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_DiskDrive',
PropertyList=cim_disk_pros)

-
def _traverse_computer_sys(self, cim_sys_path):
"""
Walk through the CIM_ComputerSystem based on SNIA SMI-S 1.6rev4
@@ -3238,7 +3236,7 @@ class Smis(IStorageAreaNetwork):
# We have to chose disks for LSI.
# To make thing simple, we only check 1 raid type for
# possible disk combination
- raid_type =Smis.LSI_DEFAULT_RAID_TYPE
+ raid_type = Smis.LSI_DEFAULT_RAID_TYPE

cim_scs = self._cim_scs(cim_sys.path, [])

@@ -3270,7 +3268,6 @@ class Smis(IStorageAreaNetwork):
if cim_st_set:
in_params['Goal'] = cim_st_set.path

-
disk_type = Disk.DISK_TYPE_UNKNOWN
if Pool.member_type_is_disk(member_type):
disk_type = Pool.member_type_to_disk_type(member_type)
@@ -3495,7 +3492,7 @@ class Smis(IStorageAreaNetwork):
cim_disk_path)

@handle_cim_errors
- def _find_preset_st_set(self, cim_sys_path , raid_type):
+ def _find_preset_st_set(self, cim_sys_path, raid_type):
"""
Usage:
Find first proper CIM_StorageSetting under speficied
@@ -3552,7 +3549,6 @@ class Smis(IStorageAreaNetwork):
PropertyList=['ElementName', 'ThinProvisionedPoolType'])
all_cim_st_sets.extend(tmp_cim_st_sets)

-
raid_type_str = Pool.raid_type_to_str(raid_type)
# According to SNIA suggest, RAID6 can also be writen as RAID5DP
# and etc.
@@ -3569,8 +3565,8 @@ class Smis(IStorageAreaNetwork):

# we prefer thin provisioning CIM_StorageSetting
for cim_st_set in chose_cim_st_sets:
- if ('ThinProvisionedPoolType' in cim_st_set and \
- cim_st_set['ThinProvisionedPoolType'] == \
+ if ('ThinProvisionedPoolType' in cim_st_set and
+ cim_st_set['ThinProvisionedPoolType'] ==
Smis.DMTF_THINP_POOL_TYPE_ALLOCATED):
return cim_st_set

@@ -3858,7 +3854,7 @@ class Smis(IStorageAreaNetwork):
# XIV will return NOTHING, so use EnumerateInstanceNames()
# when you need nothing but the CIMInstanceName
cim_scss_path = self._c.EnumerateInstanceNames(
- 'CIM_StorageConfigurationService')
+ 'CIM_StorageConfigurationService')
except CIMError as e:
# If array does not support CIM_StorageConfigurationService
# we use CIM_ComputerSystem which is mandatory.
@@ -4208,4 +4204,3 @@ class Smis(IStorageAreaNetwork):
size_bytes))
else:
return []
-
--
1.8.3.1
Tony Asleson
2014-03-18 19:59:24 UTC
Permalink
Post by Gris Ge
1. Enable more interop support.
2. Some trivial fixes for LSI.
3. Rewrite of pool_create()
property_list.extend([prop])
# ^^^^, should be [key]
* Capabilities() entries for pool creation.
smis.py: introduce _cim_sys_of_id() to support interop
smis.py: enable job_status() and job_free() for interop
smis.py: improve disk query
smis.py: fix volume-delete() on LSI
smis.py: sync to latest pool_create() and pool_delete()
This patch does not apply.
Post by Gris Ge
smis.py: Fix LSI pool member querying
smis.py: PEP8 clean up
This patch does not apply.

Please do a re-base and resubmit.

Thanks,
Tony
Loading...