Discussion:
[Libstoragemgmt-devel] [PATCH 00/12] Split smis_ag and smis_vol out.
Gris Ge
2014-11-07 11:43:59 UTC
Permalink
* The volume mask/unmask require both smis_ag and smis_vol, hence I
use one big patch set instead of two patch sets.

* Tested via plugin_test.py with all PASS on:
* EMC VMAX
* EMC VNX
* HP 3PAR

Gris Ge (12):
SMI-S Plugin: Add smis_vol.py file.
SMI-S Plugin: Move Volume.id generator to smis_vol.py
SMI-S Plugin: Move _cim_vol_pros() to smis_vol.py
SMI-S Plugin: Move cim_vol converter to smis_vol.py
SMI-S Plugin: Move CIMInstanceName converter to utils.py
SMI-S Plugin: Move job handling to SmisCommon
SMI-S Plugin: Store cim_vol_path in Volume.plugin_date
SMI-S Plugin: Move service retriever to smis_common.py
SMI-S Plugin: Add smis_ag.py file.
SMI-S Plugin: Move lsm.AccessGroup converter to smis_ag.py
SMI-S Plugin: Store cim_xxx_path in lsm.AccessGroup.plugin_data
SMI-S Plugin: Move CIM_InitiatorMaskingGroup property list to
smis_ag.py

packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 4 +-
plugin/smispy/dmtf.py | 2 +
plugin/smispy/smis.py | 1095 +++++++++++---------------------------
plugin/smispy/smis_ag.py | 195 +++++++
plugin/smispy/smis_cap.py | 46 +-
plugin/smispy/smis_common.py | 277 +++++++---
plugin/smispy/smis_pool.py | 28 +-
plugin/smispy/smis_sys.py | 10 +
plugin/smispy/smis_vol.py | 228 ++++++++
plugin/smispy/utils.py | 23 +-
11 files changed, 1014 insertions(+), 896 deletions(-)
create mode 100644 plugin/smispy/smis_ag.py
create mode 100644 plugin/smispy/smis_vol.py
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:00 UTC
Permalink
* Add empty smis_vol.py file with license only.
* Makefile and RPM SPEC file updated.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 3 ++-
plugin/smispy/smis_vol.py | 16 ++++++++++++++++
3 files changed, 19 insertions(+), 1 deletion(-)
create mode 100644 plugin/smispy/smis_vol.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 0ef7c16..4fef3a4 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -478,6 +478,7 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
%{python_sitelib}/lsm/plugin/smispy/smis_disk.*
+%{python_sitelib}/lsm/plugin/smispy/smis_vol.*
%{_bindir}/smispy_lsmplugin

%files -n %{libstoragemgmt}-netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index c3084c9..19da66a 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -31,7 +31,8 @@ smispy_PYTHON = \
smispy/smis_cap.py \
smispy/smis_sys.py \
smispy/smis_pool.py \
- smispy/smis_disk.py
+ smispy/smis_disk.py \
+ smispy/smis_vol.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
new file mode 100644
index 0000000..e1f46a5
--- /dev/null
+++ b/plugin/smispy/smis_vol.py
@@ -0,0 +1,16 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author: Gris Ge <***@redhat.com>
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:01 UTC
Permalink
* Replaces smis.Smis._vol_id() with smis_vol.vol_id_of_cim_vol()
* Replaces smis.Smis._property_list_of_id('Volume') with
smis_vol.cim_vol_id_pros()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 26 +++++++++++---------------
plugin/smispy/smis_vol.py | 21 +++++++++++++++++++++
2 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a571d9d..0e07136 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -32,6 +32,7 @@ import smis_cap
import smis_sys
import smis_pool
import smis_disk
+import smis_vol
import dmtf

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
@@ -423,13 +424,6 @@ class Smis(IStorageAreaNetwork):
"""
return self._id('SystemChild', cim_xxx)

- def _vol_id(self, cim_vol):
- """
- Return the MD5 hash of CIM_StorageVolume['SystemName'] and
- ['DeviceID']
- """
- return self._id('Volume', cim_vol)
-
def _job_id(self, cim_job, retrieve_data, method_data):
"""
Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
@@ -524,8 +518,8 @@ class Smis(IStorageAreaNetwork):
'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
'OtherNameFormat', 'OtherNameNamespace']
- cim_vol_pros = self._property_list_of_id("Volume", props)
- return cim_vol_pros
+ props.extend(smis_vol.cim_vol_id_pros())
+ return props

def _new_vol(self, cv, pool_id=None, sys_id=None):
"""
@@ -562,8 +556,10 @@ class Smis(IStorageAreaNetwork):

admin_state = Volume.ADMIN_STATE_ENABLED

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

@staticmethod
def _vpd83_in_cv_name(cv):
@@ -1370,14 +1366,14 @@ class Smis(IStorageAreaNetwork):
# many tgt_mg. It's seldom use, but possible.
for cim_spc_path in cim_spcs_path:
# Check whether already masked
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
for cur_cim_vol in cim_vols:
- if self._vol_id(cur_cim_vol) == volume.id:
+ if smis_vol.vol_id_of_cim_vol(cur_cim_vol) == volume.id:
# Masked.
return None

@@ -2632,14 +2628,14 @@ class Smis(IStorageAreaNetwork):
break
if cim_dev_mg:
# Check whether cim_vol included.
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_dev_mg.path,
AssocClass='CIM_OrderedMemberOfCollection',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
for cim_vol in cim_vols:
- if self._vol_id(cim_vol) == vol_id:
+ if smis_vol.vol_id_of_cim_vol(cim_vol) == vol_id:
return cim_dev_mg.path

# We should add this volume to found DeviceMaskingGroup
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
index e1f46a5..0d2fb10 100644
--- a/plugin/smispy/smis_vol.py
+++ b/plugin/smispy/smis_vol.py
@@ -14,3 +14,24 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Author: Gris Ge <***@redhat.com>
+
+from lsm import md5
+
+
+def cim_vol_id_pros():
+ """
+ Return the property of CIM_StorageVolume required to gernarate
+ lsm.Volume.id
+ """
+ return ['SystemName', 'DeviceID']
+
+
+def vol_id_of_cim_vol(cim_vol):
+ if 'SystemName' not in cim_vol or 'DeviceID' not in cim_vol:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "vol_id_of_cim_vol(): Got cim_vol with no "
+ "SystemName or DeviceID property: %s, %s" %
+ (cim_vol.path, cim_vol.items()))
+
+ return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
--
1.8.3.1


------------------------------------------------------------------------------
Tony Asleson
2014-11-08 00:56:54 UTC
Permalink
Post by Gris Ge
* Replaces smis.Smis._vol_id() with smis_vol.vol_id_of_cim_vol()
* Replaces smis.Smis._property_list_of_id('Volume') with
smis_vol.cim_vol_id_pros()
---
plugin/smispy/smis.py | 26 +++++++++++---------------
plugin/smispy/smis_vol.py | 21 +++++++++++++++++++++
2 files changed, 32 insertions(+), 15 deletions(-)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a571d9d..0e07136 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -32,6 +32,7 @@ import smis_cap
import smis_sys
import smis_pool
import smis_disk
+import smis_vol
import dmtf
from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
"""
return self._id('SystemChild', cim_xxx)
- """
- Return the MD5 hash of CIM_StorageVolume['SystemName'] and
- ['DeviceID']
- """
- return self._id('Volume', cim_vol)
-
"""
Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
'OtherNameFormat', 'OtherNameNamespace']
- cim_vol_pros = self._property_list_of_id("Volume", props)
- return cim_vol_pros
+ props.extend(smis_vol.cim_vol_id_pros())
+ return props
"""
admin_state = Volume.ADMIN_STATE_ENABLED
- return Volume(self._vol_id(cv), user_name, vpd_83, cv["BlockSize"],
- cv["NumberOfBlocks"], admin_state, sys_id, pool_id)
+ return Volume(
+ smis_vol.vol_id_of_cim_vol(cv), user_name, vpd_83,
+ cv["BlockSize"], cv["NumberOfBlocks"], admin_state, sys_id,
+ pool_id)
@staticmethod
# many tgt_mg. It's seldom use, but possible.
# Check whether already masked
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
# Masked.
return None
break
# Check whether cim_vol included.
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_dev_mg.path,
AssocClass='CIM_OrderedMemberOfCollection',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
return cim_dev_mg.path
# We should add this volume to found DeviceMaskingGroup
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
index e1f46a5..0d2fb10 100644
--- a/plugin/smispy/smis_vol.py
+++ b/plugin/smispy/smis_vol.py
@@ -14,3 +14,24 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
+
+from lsm import md5
+
+
+ """
+ Return the property of CIM_StorageVolume required to gernarate
^^^^^^^^^
Typo: generate
Post by Gris Ge
+ lsm.Volume.id
+ """
+ return ['SystemName', 'DeviceID']
+
+
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "vol_id_of_cim_vol(): Got cim_vol with no "
+ "SystemName or DeviceID property: %s, %s" %
+ (cim_vol.path, cim_vol.items()))
+
+ return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:02 UTC
Permalink
* Replace smis.Smis._cim_vol_pros() with smis_vol.cim_vol_pros()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 15 ++-------------
plugin/smispy/smis_vol.py | 12 ++++++++++++
2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 0e07136..6b346c3 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -510,17 +510,6 @@ class Smis(IStorageAreaNetwork):

return other_id

- def _cim_vol_pros(self):
- """
- Return the PropertyList required for creating new LSM Volume.
- """
- props = ['ElementName', 'NameFormat',
- 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
- 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
- 'OtherNameFormat', 'OtherNameNamespace']
- props.extend(smis_vol.cim_vol_id_pros())
- return props
-
def _new_vol(self, cv, pool_id=None, sys_id=None):
"""
Takes a CIMInstance that represents a volume and returns a lsm Volume
@@ -722,7 +711,7 @@ class Smis(IStorageAreaNetwork):
rc = []
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()
for cim_sys in cim_syss:
sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
pool_pros = smis_pool.cim_pool_id_pros()
@@ -1736,7 +1725,7 @@ class Smis(IStorageAreaNetwork):
def volumes_accessible_by_access_group(self, access_group, flags=0):
mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vols = []
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
index 0d2fb10..a373c9d 100644
--- a/plugin/smispy/smis_vol.py
+++ b/plugin/smispy/smis_vol.py
@@ -35,3 +35,15 @@ def vol_id_of_cim_vol(cim_vol):
(cim_vol.path, cim_vol.items()))

return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
+
+
+def cim_vol_pros():
+ """
+ Return the PropertyList required for creating new lsm.Volume.
+ """
+ props = ['ElementName', 'NameFormat',
+ 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
+ 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
+ 'OtherNameFormat', 'OtherNameNamespace']
+ props.extend(cim_vol_id_pros())
+ return props
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:03 UTC
Permalink
* Replace smis.Smis._new_vol() with smis_pool.cim_vol_to_lsm_vol()

* Moved _vpd83_xxx method into smis_pool.py as it's private used by
smis_pool.cim_vol_to_lsm_vol()

* The smis_pool.cim_vol_to_lsm_vol() require caller to provide pool_id and
systemd_id as they should handled by smis_pool.py and smis_sys.py.
smis_sys.sys_id_of_cim_vol() is added for this seek.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/dmtf.py | 2 +
plugin/smispy/smis.py | 179 ++++++++++------------------------------------
plugin/smispy/smis_sys.py | 10 +++
plugin/smispy/smis_vol.py | 132 +++++++++++++++++++++++++++++++++-
4 files changed, 179 insertions(+), 144 deletions(-)

diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 576c72e..c44db2f 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -242,3 +242,5 @@ ST_SYNC_STATE_SYNCHRONIZED = 6
CTRL_CONF_SRV_DA_RW = Uint16(2)

VOL_OTHER_INFO_NAA_VPD83_TYPE3H = 'NAA;VPD83Type3'
+
+VOL_USAGE_SYS_RESERVED = Uint16(3)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 6b346c3..fa89e64 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -491,138 +491,26 @@ class Smis(IStorageAreaNetwork):
method_data = tmp_list[2]
return (md5_str, retrieve_data, method_data)

- @staticmethod
- def _get_vol_other_id_info(cv):
- other_id = None
-
- if 'OtherIdentifyingInfo' in cv \
- and cv["OtherIdentifyingInfo"] is not None \
- and len(cv["OtherIdentifyingInfo"]) > 0:
-
- other_id = cv["OtherIdentifyingInfo"]
-
- if isinstance(other_id, list):
- other_id = other_id[0]
-
- # This is not what we are looking for if the field has this value
- if other_id is not None and other_id == "VPD83Type3":
- other_id = None
-
- return other_id
-
- def _new_vol(self, cv, pool_id=None, sys_id=None):
- """
- Takes a CIMInstance that represents a volume and returns a lsm Volume
- """
-
- # This is optional (User friendly name)
- if 'ElementName' in cv:
- user_name = cv["ElementName"]
- else:
- #Better fallback value?
- user_name = cv['DeviceID']
-
- vpd_83 = Smis._vpd83_in_cv_name(cv)
- if vpd_83 is None:
- vpd_83 = Smis._vpd83_in_cv_otherinfo(cv)
- if vpd_83 is None:
- vpd_83 = Smis._vpd83_in_cv_otherinfo_netapp(cv)
-
- if vpd_83 and re.match('^[a-fA-F0-9]{32}$', vpd_83) and \
- vpd_83[0] == '6':
- vpd_83 = vpd_83.lower()
- else:
- vpd_83 = ''
-
- #This is a fairly expensive operation, so it's in our best interest
- #to not call this very often.
- if pool_id is None:
- #Go an retrieve the pool id
- pool_id = smis_pool.pool_id_of_cim_vol(self._c, cv.path)
-
- if sys_id is None:
- sys_id = cv['SystemName']
-
- admin_state = Volume.ADMIN_STATE_ENABLED
-
- return Volume(
- smis_vol.vol_id_of_cim_vol(cv), user_name, vpd_83,
- cv["BlockSize"], cv["NumberOfBlocks"], admin_state, sys_id,
- pool_id)
-
- @staticmethod
- def _vpd83_in_cv_name(cv):
- """
- We require NAA Type 3 VPD83 address:
- Only this is allowed when storing VPD83 in cv["Name"]:
- * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
- """
- if not ('NameFormat' in cv and
- 'NameNamespace' in cv and
- 'Name' in cv):
- return None
- nf = cv['NameFormat']
- nn = cv['NameNamespace']
- name = cv['Name']
- if not (nf and nn and name):
- return None
-
- if nf == dmtf.VOL_NAME_FORMAT_NNA and \
- nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE3:
- return name
-
- @staticmethod
- def _vpd83_in_cv_otherinfo(cv):
- """
- IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
- Will return the vpd_83 value if found
- """
- if not ("IdentifyingDescriptions" in cv and
- "OtherIdentifyingInfo" in cv):
- return None
-
- id_des = cv["IdentifyingDescriptions"]
- other_info = cv["OtherIdentifyingInfo"]
- if not (isinstance(cv["IdentifyingDescriptions"], list) and
- isinstance(cv["OtherIdentifyingInfo"], list)):
- return None
-
- index = 0
- len_id_des = len(id_des)
- len_other_info = len(other_info)
- while index < min(len_id_des, len_other_info):
- if dmtf.VOL_OTHER_INFO_NAA_VPD83_TYPE3H == id_des[index]:
- return other_info[index]
- index += 1
- return None
-
- @staticmethod
- def _vpd83_in_cv_otherinfo_netapp(cv):
- # workaround for NetApp, they use OtherNameNamespace and
- # OtherNameFormat.
- if 'OtherNameFormat' in cv and \
- cv['OtherNameFormat'] == 'NAA' and \
- 'OtherNameNamespace' in cv and \
- cv['OtherNameNamespace'] == 'VPD83Type3' and \
- 'OtherIdentifyingInfo' in cv and \
- isinstance(cv["OtherIdentifyingInfo"], list) and \
- len(cv['OtherIdentifyingInfo']) == 1:
- return cv['OtherIdentifyingInfo'][0]
-
def _new_vol_from_name(self, out):
"""
Given a volume by CIMInstanceName, return a lsm Volume object
"""
- instance = None
+ cim_vol = None
+ cim_vol_pros = smis_pool.cim_vol_pros()

if 'TheElement' in out:
- instance = self._c.GetInstance(out['TheElement'],
- LocalOnly=False)
+ cim_vol = self._c.GetInstance(
+ out['TheElement'],
+ PropertyList=cim_vol_pros)
elif 'TargetElement' in out:
- instance = self._c.GetInstance(out['TargetElement'],
- LocalOnly=False)
+ cim_vol = self._c.GetInstance(
+ out['TargetElement'],
+ PropertyList=cim_vol_pros)

- return self._new_vol(instance)
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+
+ return smis_vol.cim_vol_to_lsm_vol(self._c, cim_vol, pool_id, sys_id)

def _cim_spc_pros(self):
"""
@@ -681,10 +569,17 @@ class Smis(IStorageAreaNetwork):
"""
Given a concrete job instance, return referenced volume as lsm volume
"""
- for a in self._c.Associators(job.path,
- AssocClass='CIM_AffectedJobElement',
- ResultClass='CIM_StorageVolume'):
- return self._new_vol(self._c.GetInstance(a.path, LocalOnly=False))
+ cim_vol_pros = smis_vol.cim_vol_pros()
+ cim_vols = self._c.Associators(
+ job.path,
+ AssocClass='CIM_AffectedJobElement',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=cim_vol_pros)
+ for cim_vol in cim_vols:
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ return smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id)
return None

@handle_cim_errors
@@ -719,20 +614,12 @@ class Smis(IStorageAreaNetwork):
self._c, cim_sys.path, pool_pros)
for cim_pool in cim_pools:
pool_id = smis_pool.pool_id_of_cim_pool(cim_pool)
- cim_vols = self._c.Associators(
- cim_pool.path,
- AssocClass='CIM_AllocatedFromStoragePool',
- ResultClass='CIM_StorageVolume',
- PropertyList=cim_vol_pros)
+ cim_vols = smis_vol.cim_vol_of_cim_pool_path(
+ self._c, cim_pool.path, cim_vol_pros)
for cim_vol in cim_vols:
- # Exclude those volumes which are reserved for system
- if 'Usage' in cim_vol:
- if cim_vol['Usage'] != 3:
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
- else:
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id))
return search_property(rc, search_key, search_value)

@handle_cim_errors
@@ -1757,8 +1644,14 @@ class Smis(IStorageAreaNetwork):
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
-
- return [self._new_vol(v) for v in cim_vols]
+ rc = []
+ for cim_vol in cim_vols:
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id))
+ return rc

@handle_cim_errors
def access_groups_granted_to_volume(self, volume, flags=0):
diff --git a/plugin/smispy/smis_sys.py b/plugin/smispy/smis_sys.py
index 64a9723..4101137 100644
--- a/plugin/smispy/smis_sys.py
+++ b/plugin/smispy/smis_sys.py
@@ -38,6 +38,16 @@ def sys_id_of_cim_sys(cim_sys):
"'Name' property: %s, %s" % (cim_sys.items(), cim_sys.path))


+def sys_id_of_cim_vol(cim_vol):
+ if 'SystemName' in cim_vol:
+ return cim_vol['SystemName']
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_id_of_cim_vol(): Got a CIM_StorageVolume does not have "
+ "'SystemName' property: %s, %s" % (cim_vol.items(), cim_vol.path))
+
+
def root_cim_sys(smis_common, property_list=None):
"""
Use this association to find out the root CIM_ComputerSystem:
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
index a373c9d..e928b26 100644
--- a/plugin/smispy/smis_vol.py
+++ b/plugin/smispy/smis_vol.py
@@ -15,7 +15,11 @@
#
# Author: Gris Ge <***@redhat.com>

-from lsm import md5
+import re
+
+from lsm import md5, Volume
+from utils import merge_list
+import dmtf


def cim_vol_id_pros():
@@ -47,3 +51,129 @@ def cim_vol_pros():
'OtherNameFormat', 'OtherNameNamespace']
props.extend(cim_vol_id_pros())
return props
+
+
+def cim_vol_of_cim_pool_path(smis_common, cim_pool_path, property_list=None):
+ """
+ Use this association to get a list of CIM_StorageVolume:
+ CIM_StoragePool
+ |
+ | CIM_AllocatedFromStoragePool
+ |
+ v
+ CIM_StorageVolume
+ CIM_StorageVolume['Usage'] == dmtf.VOL_USAGE_SYS_RESERVED will be filtered
+ out.
+ Return a list of CIM_StorageVolume.
+ """
+ if property_list is None:
+ property_list = ['Usage']
+ else:
+ property_list = merge_list(property_list, ['Usage'])
+
+ cim_vols = smis_common.Associators(
+ cim_pool_path,
+ AssocClass='CIM_AllocatedFromStoragePool',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=property_list)
+
+ rc = []
+ for cim_vol in cim_vols:
+ if 'Usage' not in cim_vol or \
+ cim_vol['Usage'] != dmtf.VOL_USAGE_SYS_RESERVED:
+ rc.append(cim_vol)
+ return rc
+
+
+def _vpd83_in_cim_vol_name(cim_vol):
+ """
+ We require NAA Type 3 VPD83 address:
+ Only this is allowed when storing VPD83 in cim_vol["Name"]:
+ * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
+ """
+ if not ('NameFormat' in cim_vol and
+ 'NameNamespace' in cim_vol and
+ 'Name' in cim_vol):
+ return None
+ nf = cim_vol['NameFormat']
+ nn = cim_vol['NameNamespace']
+ name = cim_vol['Name']
+ if not (nf and nn and name):
+ return None
+
+ if nf == dmtf.VOL_NAME_FORMAT_NNA and \
+ nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE3:
+ return name
+
+
+def _vpd83_in_cim_vol_otherinfo(cim_vol):
+ """
+ IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
+ Will return the vpd_83 value if found
+ """
+ if not ("IdentifyingDescriptions" in cim_vol and
+ "OtherIdentifyingInfo" in cim_vol):
+ return None
+
+ id_des = cim_vol["IdentifyingDescriptions"]
+ other_info = cim_vol["OtherIdentifyingInfo"]
+ if not (isinstance(cim_vol["IdentifyingDescriptions"], list) and
+ isinstance(cim_vol["OtherIdentifyingInfo"], list)):
+ return None
+
+ index = 0
+ len_id_des = len(id_des)
+ len_other_info = len(other_info)
+ while index < min(len_id_des, len_other_info):
+ if dmtf.VOL_OTHER_INFO_NAA_VPD83_TYPE3H == id_des[index]:
+ return other_info[index]
+ index += 1
+ return None
+
+
+def _vpd83_in_cim_vol_otherinfo_netapp(cim_vol):
+ # workaround for NetApp, they use OtherNameNamespace and
+ # OtherNameFormat.
+ if 'OtherNameFormat' in cim_vol and \
+ cim_vol['OtherNameFormat'] == 'NAA' and \
+ 'OtherNameNamespace' in cim_vol and \
+ cim_vol['OtherNameNamespace'] == 'VPD83Type3' and \
+ 'OtherIdentifyingInfo' in cim_vol and \
+ isinstance(cim_vol["OtherIdentifyingInfo"], list) and \
+ len(cim_vol['OtherIdentifyingInfo']) == 1:
+ return cim_vol['OtherIdentifyingInfo'][0]
+
+
+def _vpd83_of_cim_vol(cim_vol):
+ vpd_83 = _vpd83_in_cim_vol_name(cim_vol)
+ if vpd_83 is None:
+ vpd_83 = _vpd83_in_cim_vol_otherinfo(cim_vol)
+ if vpd_83 is None:
+ vpd_83 = _vpd83_in_cim_vol_otherinfo_netapp(cim_vol)
+
+ if vpd_83 and re.match('^6[a-fA-F0-9]{31}$', vpd_83):
+ return vpd_83.lower()
+ else:
+ return ''
+
+
+def cim_vol_to_lsm_vol(smis_common, cim_vol, pool_id, sys_id):
+ """
+ Takes a CIMInstance that represents a volume and returns a lsm Volume
+ """
+
+ # This is optional (User friendly name)
+ if 'ElementName' in cim_vol:
+ user_name = cim_vol["ElementName"]
+ else:
+ #Better fallback value?
+ user_name = cim_vol['DeviceID']
+
+ vpd_83 = _vpd83_of_cim_vol(cim_vol)
+
+ admin_state = Volume.ADMIN_STATE_ENABLED
+
+ return Volume(
+ vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
+ cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
+ pool_id)
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:04 UTC
Permalink
* As these two methods will be commonly used across smis_xxx.py,
move them into utils.py file:
smis_pool._cim_path_to_path_str()
-> utils.cim_path_to_path_str()
smis_pool._path_str_to_cim_path()
- utils.path_str_to_cim_path()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis_pool.py | 28 +++-------------------------
plugin/smispy/utils.py | 23 ++++++++++++++++++++++-
2 files changed, 25 insertions(+), 26 deletions(-)

diff --git a/plugin/smispy/smis_pool.py b/plugin/smispy/smis_pool.py
index ca0999e..c9f4345 100644
--- a/plugin/smispy/smis_pool.py
+++ b/plugin/smispy/smis_pool.py
@@ -15,11 +15,9 @@
#
# Author: Gris Ge <***@redhat.com>

-from utils import merge_list
+from utils import merge_list, path_str_to_cim_path, cim_path_to_path_str
import dmtf
from lsm import LsmError, ErrorNumber, Pool
-import json
-from pywbem import CIMInstanceName


def cim_pools_of_cim_sys_path(smis_common, cim_sys_path, property_list=None):
@@ -226,7 +224,7 @@ def cim_pool_to_lsm_pool(smis_common, cim_pool, system_id):

element_type, unsupported = _pool_element_type(smis_common, cim_pool)

- plugin_data = _cim_path_to_path_str(cim_pool.path)
+ plugin_data = cim_path_to_path_str(cim_pool.path)

return Pool(pool_id, name, element_type, unsupported,
total_space, free_space,
@@ -248,27 +246,7 @@ def lsm_pool_to_cim_pool_path(smis_common, lsm_pool):
ErrorNumber.NOT_FOUND_SYSTEM,
"System filtered in URI")

- return _path_str_to_cim_path(lsm_pool.plugin_data)
-
-
-def _cim_path_to_path_str(cim_path):
- """
- Convert CIMInstanceName to a string which could save in plugin_data
- """
- return json.dumps({
- 'classname': cim_path.classname,
- 'keybindings': dict(cim_path.keybindings),
- 'host': cim_path.host,
- 'namespace': cim_path.namespace,
- })
-
-
-def _path_str_to_cim_path(path_str):
- """
- Convert a string into CIMInstanceName.
- """
- path_dict = json.loads(path_str)
- return CIMInstanceName(**path_dict)
+ return path_str_to_cim_path(lsm_pool.plugin_data)


def pool_id_of_cim_vol(smis_common, cim_vol_path):
diff --git a/plugin/smispy/utils.py b/plugin/smispy/utils.py
index 95332b8..668241f 100644
--- a/plugin/smispy/utils.py
+++ b/plugin/smispy/utils.py
@@ -17,8 +17,9 @@

import traceback
from lsm import (LsmError, ErrorNumber, error)
-from pywbem import (CIMError)
+from pywbem import (CIMError, CIMInstanceName)
import pywbem
+import json


def merge_list(list_a, list_b):
@@ -66,3 +67,23 @@ def handle_cim_errors(method):
def hex_string_format(hex_str, length, every):
hex_str = hex_str.lower()
return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
+
+
+def cim_path_to_path_str(cim_path):
+ """
+ Convert CIMInstanceName to a string which could save in plugin_data
+ """
+ return json.dumps({
+ 'classname': cim_path.classname,
+ 'keybindings': dict(cim_path.keybindings),
+ 'host': cim_path.host,
+ 'namespace': cim_path.namespace,
+ })
+
+
+def path_str_to_cim_path(path_str):
+ """
+ Convert a string into CIMInstanceName.
+ """
+ path_dict = json.loads(path_str)
+ return CIMInstanceName(**path_dict)
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:06 UTC
Permalink
* Store cim_vol_path data in Volume.plugin_date.
* Replace
smis.Smis._get_cim_instance_by_id('Volume', volume.id)
-> smis_vol.lsm_vol_to_cim_vol_path()
* Changed smis.Smis._deal_volume_associations_netappe() and
smis.Smis._deal_volume_associations() to take cim_vol_path only.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 83 ++++++++++++++++++++++-------------------------
plugin/smispy/smis_vol.py | 24 ++++++++++++--
2 files changed, 61 insertions(+), 46 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 7d60364..92dd164 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -710,15 +710,14 @@ class Smis(IStorageAreaNetwork):
else:
return False

- def _deal_volume_associations_netappe(self, vol, lun):
+ def _deal_volume_associations_netappe(self, vol, cim_vol_path):
"""
Check a volume to see if it has any associations with other
volumes.
"""
rc = False
- lun_path = lun.path

- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')

if len(ss):
@@ -726,31 +725,29 @@ class Smis(IStorageAreaNetwork):
if 'SyncedElement' in s:
item = s['SyncedElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)
rc = True

if 'SystemElement' in s:
item = s['SystemElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)
rc = True

return rc

- def _deal_volume_associations(self, vol, lun):
+ def _deal_volume_associations(self, vol, cim_vol_path):
"""
Check a volume to see if it has any associations with other
volumes and deal with them.
"""
if self._c.is_netappe():
- return self._deal_volume_associations_netappe(vol, lun)
-
- lun_path = lun.path
+ return self._deal_volume_associations_netappe(vol, cim_vol_path)

try:
- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')
except pywbem.CIMError as e:
if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
@@ -781,24 +778,24 @@ class Smis(IStorageAreaNetwork):
if 'SyncedElement' in s:
item = s['SyncedElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)

if 'SystemElement' in s:
item = s['SystemElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)

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

#If we actually have an association to delete, the volume will be
#deleted with the association, no need to call ReturnToStoragePool
- if not self._deal_volume_associations(volume, lun):
- in_params = {'TheElement': lun.path}
+ if not self._deal_volume_associations(volume, cim_vol_path):
+ in_params = {'TheElement': cim_vol_path}

#Delete returns None or Job number
return self._c.invoke_method(
@@ -806,11 +803,11 @@ class Smis(IStorageAreaNetwork):

#Loop to check to see if volume is actually gone yet!
try:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
- while lun is not None:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_vol = self._c.GetInstance(cim_vol_path,PropertyList=[])
+ while cim_vol is not None:
+ cim_vol = self._c.GetInstance(cim_vol_path,PropertyList=[])
time.sleep(0.125)
- except LsmError as e:
+ except (LsmError, CIMError) as e:
pass

@handle_cim_errors
@@ -820,11 +817,12 @@ class Smis(IStorageAreaNetwork):
"""
scs = self._c.get_class_instance('CIM_StorageConfigurationService',
'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)

- self._deal_volume_associations(volume, lun)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+
+ self._deal_volume_associations(volume, cim_vol_path)

- in_params = {'TheElement': lun.path}
+ in_params = {'TheElement': cim_vol_path}

# Delete returns None or Job number
return self._c.invoke_method(
@@ -837,10 +835,11 @@ class Smis(IStorageAreaNetwork):
"""
scs = self._c.get_class_instance('CIM_StorageConfigurationService',
'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

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

return self._c.invoke_method(
@@ -921,7 +920,8 @@ class Smis(IStorageAreaNetwork):
if pool is not None:
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)

- lun = self._get_cim_instance_by_id('Volume', volume_src.id)
+ src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
+ self._c, volume_src)

if rs:
method = 'CreateElementReplica'
@@ -932,7 +932,7 @@ class Smis(IStorageAreaNetwork):
in_params = {'ElementName': name,
'SyncType': sync,
#'Mode': mode,
- 'SourceElement': lun.path,
+ 'SourceElement': src_cim_vol_path,
'WaitForCopyState': dmtf.COPY_STATE_SYNC}

else:
@@ -957,7 +957,7 @@ class Smis(IStorageAreaNetwork):

in_params = {'ElementName': name,
'CopyType': ct,
- 'SourceElement': lun.path}
+ 'SourceElement': src_cim_vol_path}
if rs:

if cim_pool_path is not None:
@@ -1096,9 +1096,7 @@ class Smis(IStorageAreaNetwork):
"access group init_type: %d" %
access_group.init_type)

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'],
- raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')
@@ -1114,7 +1112,7 @@ class Smis(IStorageAreaNetwork):
cim_sys.path, cim_gmm_path, access_group.name,
access_group.init_type)
cim_dev_mg_path = self._cim_dev_mg_path_create(
- cim_gmm_path, access_group.name, cim_vol.path, volume.id)
+ cim_gmm_path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
cim_gmm_path, cim_init_mg.path, cim_tgt_mg_path,
@@ -1142,7 +1140,7 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_DeviceMaskingGroup')[0]
in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
@@ -1181,8 +1179,8 @@ class Smis(IStorageAreaNetwork):
cim_css_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

in_params = {'LUNames': [cim_vol['Name']],
'ProtocolControllers': [cim_spc.path],
@@ -1201,8 +1199,7 @@ class Smis(IStorageAreaNetwork):
If SupportedDeviceGroupFeatures does not allow empty
DeviceMaskingGroup in SPC, we remove SPC and DeviceMaskingGroup.
"""
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)

cim_gmm_cap = self._c.Associators(
@@ -1235,7 +1232,7 @@ class Smis(IStorageAreaNetwork):
cim_sys.path, 'CIM_GroupMaskingMappingService')

cim_spcs_path = self._c.AssociatorNames(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController')
if len(cim_spcs_path) == 0:
@@ -1283,7 +1280,7 @@ class Smis(IStorageAreaNetwork):

in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
@@ -1310,9 +1307,8 @@ class Smis(IStorageAreaNetwork):
cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id,
- property_list=['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

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

@@ -1539,8 +1535,7 @@ class Smis(IStorageAreaNetwork):
def access_groups_granted_to_volume(self, volume, flags=0):
rc = []
mask_type = smis_cap.mask_type(self._c, raise_error=True)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
@@ -1555,7 +1550,7 @@ class Smis(IStorageAreaNetwork):
cim_spc_pros = self._cim_spc_pros()

cim_spcs = self._c.Associators(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController',
PropertyList=cim_spc_pros)
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
index a072275..6499ebf 100644
--- a/plugin/smispy/smis_vol.py
+++ b/plugin/smispy/smis_vol.py
@@ -19,7 +19,7 @@ import re
import sys

from lsm import md5, Volume, LsmError, ErrorNumber
-from utils import merge_list
+from utils import merge_list, cim_path_to_path_str, path_str_to_cim_path
import dmtf
from pywbem import CIMError

@@ -175,10 +175,30 @@ def cim_vol_to_lsm_vol(smis_common, cim_vol, pool_id, sys_id):

admin_state = Volume.ADMIN_STATE_ENABLED

+ plugin_data = cim_path_to_path_str(cim_vol.path)
+
return Volume(
vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
- pool_id)
+ pool_id, plugin_data)
+
+
+def lsm_vol_to_cim_vol_path(smis_common, lsm_vol):
+ """
+ Convert lsm.Volume to CIMInstanceName of CIM_StorageVolume using
+ lsm.Volume.plugin_data
+ """
+ if not lsm_vol.plugin_data:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.Volume instance with empty plugin_data")
+ if smis_common.system_list and \
+ lsm_vol.system_id not in smis_common.system_list:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_vol.plugin_data)


def volume_name_exists(smis_common, volume_name):
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:05 UTC
Permalink
* Replace smis.Smis._pi() with SmisCommon.invoke_method().

* When a exception triggered, invoke_method() will call 'error_handler'
with argument of: SmisCommon, method_data.
In this patch, smis_vol.volume_create_error_handler() is the
error_handler of volume_create(). It's stored in
smis.Smis._JOB_ERROR_HANDLER[SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
so that job_status() could use the same error handler.

* The invoke_method() also take 'out_handler' parameter which will be
called if the method finished in SYNC way.
In this patch, self._new_vol_from_name() is the out_handler of
volume_create().

* Moved job id generator and parser into smis_common.py:
smis.Smis._job_id() -> smis_common.SmisCommon.job_id_of_cim_job()
smis.Smis._parse_job_id() -> smis_common.SmisCommon.parse_job_id()

* Move duplicate volume checker method to smis_vol.py as the volume create
error handler require it while smis_vol.py cannot depend on smis.py:
smis.Smis._volume_exists -> smis_vol.volume_name_exists
smis.Smis._check_for_dupe_vol() -> smis_vol.volume_create_error_handler()

* Tested on EMC VNX for:
volume_create()
volume_resize()
volume_delete()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 269 ++++++++++++-------------------------------
plugin/smispy/smis_common.py | 149 +++++++++++++++++++++++-
plugin/smispy/smis_vol.py | 31 ++++-
3 files changed, 251 insertions(+), 198 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index fa89e64..7d60364 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -19,11 +19,8 @@

from string import split
import time
-import traceback
import copy
import os
-import datetime
-import sys
import re

import pywbem
@@ -140,10 +137,14 @@ class Smis(IStorageAreaNetwork):
_INVOKE_MAX_LOOP_COUNT = 60
_INVOKE_CHECK_INTERVAL = 5

+ _JOB_ERROR_HANDLER = {
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
+ smis_vol.volume_create_error_handler,
+ }
+
def __init__(self):
self._c = None
self.tmo = 0
- self.debug_path = None

def _get_cim_instance_by_id(self, class_type, requested_id,
property_list=None, raise_error=True):
@@ -164,7 +165,8 @@ class Smis(IStorageAreaNetwork):
class_name, PropertyList=property_list)
org_requested_id = requested_id
if class_type == 'Job':
- (requested_id, ignore, ignore) = Smis._parse_job_id(requested_id)
+ (requested_id, ignore, ignore) = SmisCommon.parse_job_id(
+ requested_id)
for cim_xxx in cim_xxxs:
if self._id(class_type, cim_xxx) == requested_id:
return cim_xxx
@@ -175,53 +177,6 @@ class Smis(IStorageAreaNetwork):
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))

- def _pi(self, msg, retrieve_data, method_data, rc, out):
- """
- Handle the the process of invoking an operation.
- """
- # Check to see if operation is done
- if rc == SmisCommon.SNIA_INVOKE_OK:
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- return None, self._new_vol_from_name(out)
- else:
- return None, None
-
- elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
- # We have an async operation
- job_id = self._job_id(out['Job'], retrieve_data, method_data)
- return job_id, None
- elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
- raise LsmError(
- ErrorNumber.NO_SUPPORT,
- 'SMI-S error code indicates operation not supported')
- else:
- # When debugging issues with providers it's helpful to have the
- # xml request/reply to give to provider developers.
- try:
- if self.debug_path is not None:
- if not os.path.exists(self.debug_path):
- os.makedirs(self.debug_path)
-
- if os.path.isdir(self.debug_path):
- debug_fn = "%s_%s" % \
- (msg, datetime.datetime.now().isoformat())
- debug_full = os.path.join(self.debug_path, debug_fn)
-
- # Dump the request & reply to a file
- with open(debug_full, 'w') as d:
- d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
- (self._c.last_request, self._c.last_reply))
-
- except Exception:
- tb = traceback.format_exc()
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc) +
- ' Debug data exception: ' + str(tb))
-
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc))
-
@handle_cim_errors
def plugin_register(self, uri, password, timeout, flags=0):
"""
@@ -261,14 +216,13 @@ class Smis(IStorageAreaNetwork):
and u["parameters"]["no_ssl_verify"] == 'yes':
no_ssl_verify = True

- debug = False
+ debug_path = None
if 'debug_path' in u['parameters']:
self.debug_path = u['parameters']['debug_path']
- debug = True

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

self.tmo = timeout

@@ -320,41 +274,53 @@ class Smis(IStorageAreaNetwork):
"""
completed_item = None

- props = ['JobState', 'PercentComplete', 'ErrorDescription',
- 'OperationalStatus']
- cim_job_pros = self._property_list_of_id('Job', props)
+ error_handler = None

- cim_job = self._get_cim_instance_by_id('Job', job_id, cim_job_pros)
+ (ignore, retrieve_data, method_data) = SmisCommon.parse_job_id(job_id)
+
+ if retrieve_data in Smis._JOB_ERROR_HANDLER.keys():
+ error_handler = Smis._JOB_ERROR_HANDLER[retrieve_data]
+
+ cim_job_pros = SmisCommon.cim_job_pros()
+ cim_job_pros.extend(
+ ['JobState', 'PercentComplete', 'ErrorDescription',
+ 'OperationalStatus'])
+ cim_job = self._c.cim_job_of_job_id(job_id, cim_job_pros)

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

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

- pc = cim_job['PercentComplete']
- if pc > 100:
- percent_complete = 100
- else:
- percent_complete = pc
+ pc = cim_job['PercentComplete']
+ if pc > 100:
+ percent_complete = 100
+ else:
+ percent_complete = pc

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

- if Smis._job_completed_ok(cim_job):
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- completed_item = self._new_vol_from_job(cim_job)
+ if Smis._job_completed_ok(cim_job):
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
+ retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
+ completed_item = self._new_vol_from_job(cim_job)
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ str(cim_job['ErrorDescription']))
else:
- status = JobStatus.ERROR
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG, str(cim_job['ErrorDescription']))

- else:
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- self._check_for_dupe_vol(method_data, None)
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- str(cim_job['ErrorDescription']))
+ except Exception:
+ if error_handler is not None:
+ error_handler(self._c, method_data)
+ else:
+ raise

return status, percent_complete, completed_item

@@ -424,18 +390,6 @@ class Smis(IStorageAreaNetwork):
"""
return self._id('SystemChild', cim_xxx)

- def _job_id(self, cim_job, retrieve_data, method_data):
- """
- Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
- with '@%s' % retrieve_data
- retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
- SmisCommon.JOB_RETRIEVE_VOLUME or etc
- method_data is any string a method would like store for error
- handling by job_status().
- """
- return "%s@%d@%s" % (
- self._id('Job', cim_job), int(retrieve_data), str(method_data))
-
def _init_id(self, cim_init):
"""
Retrieve Initiator ID from CIM_StorageHardwareID
@@ -475,28 +429,12 @@ class Smis(IStorageAreaNetwork):
else:
return md5(id_str)

- @staticmethod
- def _parse_job_id(job_id):
- """
- job_id is assembled by a md5 string, retrieve_data and method_data
- This method will split it and return
- (md5_str, retrieve_data, method_data)
- """
- tmp_list = job_id.split('@', 3)
- md5_str = tmp_list[0]
- retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
- method_data = None
- if len(tmp_list) == 3:
- retrieve_data = int(tmp_list[1])
- method_data = tmp_list[2]
- return (md5_str, retrieve_data, method_data)
-
def _new_vol_from_name(self, out):
"""
Given a volume by CIMInstanceName, return a lsm Volume object
"""
cim_vol = None
- cim_vol_pros = smis_pool.cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()

if 'TheElement' in out:
cim_vol = self._c.GetInstance(
@@ -661,51 +599,6 @@ class Smis(IStorageAreaNetwork):

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

- def _volume_exists(self, name):
- """
- Try to minimize time to search.
- :param name: Volume ElementName
- :return: True if volume exists with 'name', else False
- """
- all_cim_vols = self._c.EnumerateInstances(
- 'CIM_StorageVolume', PropertyList=['ElementName'])
- for exist_cim_vol in all_cim_vols:
- if name == exist_cim_vol['ElementName']:
- return True
- return False
-
- def _check_for_dupe_vol(self, volume_name, original_exception):
- """
- Throw original exception or NAME_CONFLICT if volume name found
- :param volume_name: Volume to check for
- :original_exception Info grabbed from sys.exec_info
- :return:
- if original_exception == None, will not raise any error if not
- NAME_CONFLICT, just return None.
- """
- report_original = True
-
- # Check to see if we already have a volume with this name. If we
- # do we will assume that this is the cause of it. We will hide
- # any errors that happen during this check and just report the
- # original error if we can't determine if we have a duplicate
- # name.
-
- try:
- report_original = not self._volume_exists(volume_name)
- except Exception:
- # Don't report anything here on a failing
- pass
-
- if report_original:
- if original_exception is None:
- return
- raise original_exception[1], None, original_exception[2]
- else:
- raise LsmError(ErrorNumber.NAME_CONFLICT,
- "Volume with name '%s' already exists!" %
- volume_name)
-
@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
flags=0):
@@ -752,15 +645,16 @@ class Smis(IStorageAreaNetwork):
'InPool': cim_pool_path,
'Size': pywbem.Uint64(size_bytes)}

- try:
- return self._pi("volume_create",
- SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
- volume_name,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
- except CIMError:
- self._check_for_dupe_vol(volume_name, sys.exc_info())
+ error_handler = Smis._JOB_ERROR_HANDLER[
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
+
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', scs.path,
+ in_params,
+ out_handler=self._new_vol_from_name,
+ error_handler=error_handler,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
+ method_data=volume_name)

def _poll(self, msg, job):
if job:
@@ -785,12 +679,8 @@ class Smis(IStorageAreaNetwork):
in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}

- job_id = self._pi("_detach",
- SmisCommon.JOB_RETRIEVE_NONE,
- None,
- *(self._c.InvokeMethod(
- 'ModifySynchronization', scs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifySynchronization', scs.path, in_params)[0]

self._poll("ModifySynchronization, detach", job_id)

@@ -805,10 +695,8 @@ class Smis(IStorageAreaNetwork):
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}

- job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE, None,
- *(self._c.InvokeMethod(
- 'ModifyReplicaSynchronization', rs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifyReplicaSynchronization', rs.path, in_params)[0]

self._poll("ModifyReplicaSynchronization, detach", job_id)

@@ -913,10 +801,8 @@ class Smis(IStorageAreaNetwork):
in_params = {'TheElement': lun.path}

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

#Loop to check to see if volume is actually gone yet!
try:
@@ -941,10 +827,8 @@ class Smis(IStorageAreaNetwork):
in_params = {'TheElement': lun.path}

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

@handle_cim_errors
def volume_resize(self, volume, new_size_bytes, flags=0):
@@ -959,10 +843,9 @@ class Smis(IStorageAreaNetwork):
'TheElement': lun.path,
'Size': pywbem.Uint64(new_size_bytes)}

- return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', scs.path,
+ in_params, retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

def _get_supported_sync_and_mode(self, system_id, rep_type):
"""
@@ -1030,7 +913,7 @@ class Smis(IStorageAreaNetwork):

# Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
# ElementName, we have to do pre-check here.
- if self._volume_exists(name):
+ if smis_vol.volume_name_exists(self._c, name):
raise LsmError(ErrorNumber.NAME_CONFLICT,
"Volume with name '%s' already exists!" % name)

@@ -1080,10 +963,9 @@ class Smis(IStorageAreaNetwork):
if cim_pool_path is not None:
in_params['TargetPool'] = cim_pool_path

- return self._pi("volume_replicate",
- SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(method,
- rs.path, **in_params)))
+ return self._c.invoke_method(
+ method, rs.path, in_params,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")
@@ -2005,8 +1887,7 @@ class Smis(IStorageAreaNetwork):
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id,
- ['DeleteOnCompletion'])
+ cim_job = self._c.cim_job_of_job_id(job_id, ['DeleteOnCompletion'])

# See if we should delete the job
if not cim_job['DeleteOnCompletion']:
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 4a303c3..5b86ec8 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -24,9 +24,12 @@

from pywbem import Uint16, CIMError
import pywbem
+import traceback
+import os
+import datetime

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


@@ -179,12 +182,13 @@ class SmisCommon(object):

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

if namespace is None:
namespace = dmtf.DEFAULT_NAMESPACE
@@ -201,7 +205,8 @@ class SmisCommon(object):
# https://bugzilla.redhat.com/show_bug.cgi?id=1039801
pass

- self._wbem_conn.debug = debug
+ if debug_path is not None:
+ self._wbem_conn.debug = True

if namespace.lower() == SmisCommon._MEGARAID_NAMESPACE.lower():
# Skip profile register check on MegaRAID for better performance.
@@ -372,3 +377,141 @@ class SmisCommon(object):

def is_netappe(self):
return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E
+
+ @staticmethod
+ def cim_job_pros():
+ return ['InstanceID']
+
+ def cim_job_of_job_id(self, job_id, property_list=None):
+ """
+ Return CIM_ConcreteJob for given job_id.
+ """
+ if property_list is None:
+ property_list = SmisCommon.cim_job_pros()
+ else:
+ property_list = merge_list(
+ property_list, SmisCommon.cim_job_pros())
+
+ cim_jobs = self.EnumerateInstances(
+ 'CIM_ConcreteJob',
+ PropertyList=property_list)
+ real_job_id = SmisCommon.parse_job_id(job_id)[0]
+ for cim_job in cim_jobs:
+ if md5(cim_job['InstanceID']) == real_job_id:
+ return cim_job
+
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_JOB,
+ "Job %s not found" % job_id)
+
+ @staticmethod
+ def _job_id_of_cim_job(cim_job, retrieve_data, method_data):
+ """
+ Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
+ with '@%s' % retrieve_data
+ retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
+ SmisCommon.JOB_RETRIEVE_VOLUME or etc
+ method_data is any string a method would like store for error
+ handling by job_status().
+ """
+ return "%s@%d@%s" % (
+ md5(cim_job['InstanceID']), int(retrieve_data), str(method_data))
+
+ @staticmethod
+ def parse_job_id(job_id):
+ """
+ job_id is assembled by a md5 string, retrieve_data and method_data
+ This method will split it and return
+ (md5_str, retrieve_data, method_data)
+ """
+ tmp_list = job_id.split('@', 3)
+ md5_str = tmp_list[0]
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ method_data = None
+ if len(tmp_list) == 3:
+ retrieve_data = int(tmp_list[1])
+ method_data = tmp_list[2]
+ return (md5_str, retrieve_data, method_data)
+
+ def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
+ error_handler=None, retrieve_data=None,
+ method_data=None):
+ """
+ cmd
+ A string of command, example:
+ 'CreateOrModifyElementFromStoragePool'
+ cim_path
+ the CIMInstanceName, example:
+ CIM_StorageConfigurationService.path
+ in_params
+ A dictionary of input parameter, example:
+ {'ElementName': volume_name,
+ 'ElementType': dmtf_element_type,
+ 'InPool': cim_pool_path,
+ 'Size': pywbem.Uint64(size_bytes)}
+ out_handler
+ A reference to a method to parse output, example:
+ self._new_vol_from_name
+ error_handler
+ A reference to a method to handle all exceptions.
+ retrieve_data
+ SmisCommon.JOB_RETRIEVE_XXX, it will be used only
+ when a ASYNC job has been created.
+ method_data
+ A string which will be stored in job_id, it could be used by
+ job_status() to do error checking.
+ """
+ if retrieve_data is None:
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ try:
+ (rc, out) = self.InvokeMethod(cmd, cim_path, **in_params)
+
+ # Check to see if operation is done
+ if rc == SmisCommon.SNIA_INVOKE_OK:
+ if out_handler is None:
+ return None, None
+ else:
+ return None, out_handler(out)
+
+ elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
+ # We have an async operation
+ job_id = SmisCommon._job_id_of_cim_job(
+ out['Job'], retrieve_data, method_data)
+ return job_id, None
+ elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ 'SMI-S error code indicates operation not supported')
+ else:
+ # When debugging issues with providers it's helpful to have
+ # the xml request/reply to give to provider developers.
+ try:
+ if self._debug_path is not None:
+ if not os.path.exists(self._debug_path):
+ os.makedirs(self._debug_path)
+
+ if os.path.isdir(self._debug_path):
+ debug_fn = "%s_%s" % (
+ msg, datetime.datetime.now().isoformat())
+ debug_full = os.path.join(
+ self._debug_path, debug_fn)
+
+ # Dump the request & reply to a file
+ with open(debug_full, 'w') as d:
+ d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
+ (self.last_request, self.last_reply))
+
+ except Exception:
+ tb = traceback.format_exc()
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= " % (cmd, str(rc))+
+ " Debug data exception: %s" % str(tb))
+
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= %s" % (cmd, str(rc)))
+
+ except Exception:
+ if error_handler is not None:
+ error_handler(self, method_data)
+ else:
+ raise
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
index e928b26..a072275 100644
--- a/plugin/smispy/smis_vol.py
+++ b/plugin/smispy/smis_vol.py
@@ -16,10 +16,12 @@
# Author: Gris Ge <***@redhat.com>

import re
+import sys

-from lsm import md5, Volume
+from lsm import md5, Volume, LsmError, ErrorNumber
from utils import merge_list
import dmtf
+from pywbem import CIMError


def cim_vol_id_pros():
@@ -177,3 +179,30 @@ def cim_vol_to_lsm_vol(smis_common, cim_vol, pool_id, sys_id):
vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
pool_id)
+
+
+def volume_name_exists(smis_common, volume_name):
+ """
+ Try to minimize time to search.
+ :param name: Volume ElementName
+ :return: True if volume exists with 'name', else False
+ """
+ all_cim_vols = smis_common.EnumerateInstances(
+ 'CIM_StorageVolume', PropertyList=['ElementName'])
+ for exist_cim_vol in all_cim_vols:
+ if volume_name == exist_cim_vol['ElementName']:
+ return True
+ return False
+
+
+def volume_create_error_handler(smis_common, method_data):
+ """
+ When we got CIMError, we check whether we got a duplicate volume name.
+ The method_data is the requested volume name.
+ """
+ if volume_name_exists(smis_common, method_data):
+ raise LsmError(ErrorNumber.NAME_CONFLICT,
+ "Volume with name '%s' already exists!" % method_data)
+
+ (error_type, error_msg, error_trace) = sys.exc_info()
+ raise error_type, error_msg, error_trace
--
1.8.3.1


------------------------------------------------------------------------------
Tony Asleson
2014-11-08 00:57:59 UTC
Permalink
Post by Gris Ge
+ """
+ Try to minimize time to search.
+ :param name: Volume ElementName
Documentation is incorrect, update name -> volume_name

Thanks,
Tony

------------------------------------------------------------------------------
Tony Asleson
2014-11-08 00:58:09 UTC
Permalink
Post by Gris Ge
+ def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
+ error_handler=None, retrieve_data=None,
+ """
+ cmd
+ 'CreateOrModifyElementFromStoragePool'
+ cim_path
+ CIM_StorageConfigurationService.path
+ in_params
+ {'ElementName': volume_name,
+ 'ElementType': dmtf_element_type,
+ 'InPool': cim_pool_path,
+ 'Size': pywbem.Uint64(size_bytes)}
+ out_handler
+ self._new_vol_from_name
+ error_handler
+ A reference to a method to handle all exceptions.
+ retrieve_data
+ SmisCommon.JOB_RETRIEVE_XXX, it will be used only
+ when a ASYNC job has been created.
+ method_data
+ A string which will be stored in job_id, it could be used by
+ job_status() to do error checking.
+ """
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ (rc, out) = self.InvokeMethod(cmd, cim_path, **in_params)
+
+ # Check to see if operation is done
+ return None, None
+ return None, out_handler(out)
+
+ # We have an async operation
+ job_id = SmisCommon._job_id_of_cim_job(
+ out['Job'], retrieve_data, method_data)
+ return job_id, None
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ 'SMI-S error code indicates operation not supported')
+ # When debugging issues with providers it's helpful to have
+ # the xml request/reply to give to provider developers.
+ os.makedirs(self._debug_path)
+
+ debug_fn = "%s_%s" % (
+ msg, datetime.datetime.now().isoformat())
Msg should be rename to cmd

Thanks,
Tony

------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:07 UTC
Permalink
* Replace SmisCommon.get_class_instance() and get_cim_service_path() with:
SmisCommon.cim_scs_of_sys_id() CIM_StorageConfigurationService
SmisCommon.cim_rs_of_sys_id() CIM_ReplicationService
SmisCommon.cim_gmms_of_sys_id() CIM_GroupMaskingMappingService
SmisCommon.cim_ccs_of_sys_id() CIM_ControllerConfigurationService
SmisCommon.cim_hwms_of_sys_id() CIM_StorageHardwareIDManagementService

* smis.Smis._cim_spc_of() changed to use system_id instead of cim_sys.path
to benefit this change.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 219 +++++++++++++++++--------------------------
plugin/smispy/smis_cap.py | 46 ++++-----
plugin/smispy/smis_common.py | 128 +++++++++++++------------
3 files changed, 179 insertions(+), 214 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 92dd164..966a5d1 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -59,8 +59,10 @@ from smis_common import SmisCommon
# cim_ip CIM_IPProtocolEndpoint
# cim_eth CIM_EthernetPort
# cim_pe CIM_SCSIProtocolEndpoint
-# cim_gmm CIM_GroupMaskingMappingService
+# cim_gmms CIM_GroupMaskingMappingService
# cim_ccs CIM_ControllerConfigurationService
+# cim_rs CIM_ReplicationService
+# cim_hwms CIM_StorageHardwareIDManagementService
#
# sys Object of LSM System
# pool Object of LSM Pool
@@ -635,8 +637,8 @@ class Smis(IStorageAreaNetwork):
"requested provisioning type")

# Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(pool.system_id)
+
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
self._c, pool)

@@ -649,7 +651,7 @@ class Smis(IStorageAreaNetwork):
SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]

return self._c.invoke_method(
- 'CreateOrModifyElementFromStoragePool', scs.path,
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
in_params,
out_handler=self._new_vol_from_name,
error_handler=error_handler,
@@ -673,14 +675,13 @@ class Smis(IStorageAreaNetwork):

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

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

job_id = self._c.invoke_method(
- 'ModifySynchronization', scs.path, in_params)[0]
+ 'ModifySynchronization', cim_scs.path, in_params)[0]

self._poll("ModifySynchronization, detach", job_id)

@@ -688,15 +689,14 @@ class Smis(IStorageAreaNetwork):
if self._c.is_netappe():
return self._detach_netapp_e(vol, sync)

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

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

job_id = self._c.invoke_method(
- 'ModifyReplicaSynchronization', rs.path, in_params)[0]
+ 'ModifyReplicaSynchronization', cim_rs.path, in_params)[0]

self._poll("ModifyReplicaSynchronization, detach", job_id)

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

def _volume_delete_netapp_e(self, volume, flags=0):
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

#If we actually have an association to delete, the volume will be
@@ -799,7 +798,7 @@ class Smis(IStorageAreaNetwork):

#Delete returns None or Job number
return self._c.invoke_method(
- 'ReturnToStoragePool', scs.path, in_params)[0]
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]

#Loop to check to see if volume is actually gone yet!
try:
@@ -815,8 +814,7 @@ class Smis(IStorageAreaNetwork):
"""
Delete a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)

cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

@@ -826,15 +824,14 @@ class Smis(IStorageAreaNetwork):

# Delete returns None or Job number
return self._c.invoke_method(
- 'ReturnToStoragePool', scs.path, in_params)[0]
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]

@handle_cim_errors
def volume_resize(self, volume, new_size_bytes, flags=0):
"""
Re-size a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)

cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

@@ -843,7 +840,7 @@ class Smis(IStorageAreaNetwork):
'Size': pywbem.Uint64(new_size_bytes)}

return self._c.invoke_method(
- 'CreateOrModifyElementFromStoragePool', scs.path,
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
in_params, retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

def _get_supported_sync_and_mode(self, system_id, rep_type):
@@ -854,12 +851,11 @@ class Smis(IStorageAreaNetwork):
"""
rc = [None, None]

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

- if rs:
+ if cim_rs:
rs_cap = self._c.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_ReplicationServiceCapabilities')[0]

@@ -906,9 +902,8 @@ class Smis(IStorageAreaNetwork):
or rep_type == Volume.REPLICATE_MIRROR_SYNC:
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")

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

# Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
# ElementName, we have to do pre-check here.
@@ -923,7 +918,7 @@ class Smis(IStorageAreaNetwork):
src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
self._c, volume_src)

- if rs:
+ if cim_rs:
method = 'CreateElementReplica'

sync, mode = self._get_supported_sync_and_mode(
@@ -941,9 +936,8 @@ class Smis(IStorageAreaNetwork):
method = 'CreateReplica'

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

ct = Volume.REPLICATE_CLONE
if rep_type == Volume.REPLICATE_CLONE:
@@ -958,19 +952,19 @@ class Smis(IStorageAreaNetwork):
in_params = {'ElementName': name,
'CopyType': ct,
'SourceElement': src_cim_vol_path}
- if rs:
+ if cim_rs:

if cim_pool_path is not None:
in_params['TargetPool'] = cim_pool_path

return self._c.invoke_method(
- method, rs.path, in_params,
+ method, cim_rs.path, in_params,
retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")

- def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
+ def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
vol_id):
rc = SmisCommon.SNIA_INVOKE_FAILED
out = None
@@ -982,12 +976,12 @@ class Smis(IStorageAreaNetwork):

cim_dev_mg_path = None
try:
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
except CIMError as ce:
if ce[0] == pywbem.CIM_ERR_FAILED:
cim_dev_mg_path = self._check_exist_cim_dev_mg(
- name, cim_gmm_path, cim_vol_path, vol_id)
+ name, cim_gmms_path, cim_vol_path, vol_id)
if cim_dev_mg_path is None:
raise
else:
@@ -999,7 +993,7 @@ class Smis(IStorageAreaNetwork):

return cim_dev_mg_path

- def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
+ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
init_type):
"""
Create CIM_TargetMaskingGroup
@@ -1030,7 +1024,7 @@ class Smis(IStorageAreaNetwork):

cim_tgt_mg_path = None
try:
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
except CIMError as ce:
if ce[0] == pywbem.CIM_ERR_FAILED:
@@ -1047,7 +1041,7 @@ class Smis(IStorageAreaNetwork):

return cim_tgt_mg_path

- def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
+ def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
cim_tgt_mg_path, cim_dev_mg_path, name):
in_params = {
'ElementName': name,
@@ -1056,7 +1050,7 @@ class Smis(IStorageAreaNetwork):
'DeviceMaskingGroup': cim_dev_mg_path,
}

- (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmms_path,
**in_params)

return self._wait_invoke(
@@ -1098,8 +1092,7 @@ class Smis(IStorageAreaNetwork):

cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

cim_spcs_path = self._c.AssociatorNames(
cim_init_mg.path,
@@ -1109,13 +1102,13 @@ class Smis(IStorageAreaNetwork):
if len(cim_spcs_path) == 0:
# We have to create the SPC and dev_mg now.
cim_tgt_mg_path = self._cim_tgt_mg_path_create(
- cim_sys.path, cim_gmm_path, access_group.name,
+ cim_sys.path, cim_gmms.path, access_group.name,
access_group.init_type)
cim_dev_mg_path = self._cim_dev_mg_path_create(
- cim_gmm_path, access_group.name, cim_vol_path, volume.id)
+ cim_gmms.path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
- cim_gmm_path, cim_init_mg.path, cim_tgt_mg_path,
+ cim_gmms.path, cim_init_mg.path, cim_tgt_mg_path,
cim_dev_mg_path, access_group.name)
else:
# CIM_InitiatorMaskingGroup might have multiple SPC when having
@@ -1144,7 +1137,7 @@ class Smis(IStorageAreaNetwork):
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None

@@ -1175,9 +1168,7 @@ class Smis(IStorageAreaNetwork):
access_group.id +
"will not do volume_mask()")

- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_css_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)

cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
@@ -1188,7 +1179,7 @@ class Smis(IStorageAreaNetwork):

(rc, out) = self._c.InvokeMethod(
'ExposePaths',
- cim_css_path, **in_params)
+ cim_ccs.path, **in_params)
self._wait_invoke(rc, out)
return None

@@ -1202,7 +1193,7 @@ class Smis(IStorageAreaNetwork):
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)

- cim_gmm_cap = self._c.Associators(
+ cim_gmms_cap = self._c.Associators(
cim_sys.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_GroupMaskingMappingCapabilities',
@@ -1213,14 +1204,14 @@ class Smis(IStorageAreaNetwork):
flag_empty_dev_in_spc = False

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

if flag_empty_dev_in_spc is False:
if ((dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedSynchronousActions']) and
+ cim_gmms_cap['SupportedSynchronousActions']) and
(dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedAsynchronousActions'])):
+ cim_gmms_cap['SupportedAsynchronousActions'])):
raise LsmError(
ErrorNumber.NO_SUPPORT,
"volume_unmask() not supported. It requires one of these "
@@ -1228,8 +1219,7 @@ class Smis(IStorageAreaNetwork):
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(volume.system_id)

cim_spcs_path = self._c.AssociatorNames(
cim_vol_path,
@@ -1275,7 +1265,7 @@ class Smis(IStorageAreaNetwork):
}
(rc, out) = self._c.InvokeMethod(
'DeleteMaskingView',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)

in_params = {
@@ -1284,7 +1274,7 @@ class Smis(IStorageAreaNetwork):
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)

return None
@@ -1303,9 +1293,7 @@ class Smis(IStorageAreaNetwork):
return self._volume_unmask_old(access_group, volume)

def _volume_unmask_old(self, access_group, volume):
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)

cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
@@ -1315,7 +1303,7 @@ class Smis(IStorageAreaNetwork):
hide_params = {'LUNames': [cim_vol['Name']],
'ProtocolControllers': [cim_spc.path]}

- (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs_path,
+ (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)
self._wait_invoke(rc, out)

@@ -1362,31 +1350,24 @@ class Smis(IStorageAreaNetwork):
"AccessGroup %s not found" % access_group_id)
return None

- def _cim_spc_of(self, cim_sys_path, property_list=None):
+ def _cim_spc_of(self, system_id, property_list=None):
"""
Return a list of CIM_SCSIProtocolController.
Following SNIA SMIS 'Masking and Mapping Profile':
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_ControllerConfigurationService
|
| CIM_ConcreteDependency
v
CIM_SCSIProtocolController
"""
- cim_ccss_path = []
+ cim_ccs = None
rc_cim_spcs = []

if property_list is None:
property_list = []

try:
- cim_ccss_path = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(system_id, raise_error=False)
except CIMError as ce:
error_code = tuple(ce)[0]
if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
@@ -1394,19 +1375,12 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported ' +
'by this array')
- cim_ccs_path = None
- if len(cim_ccss_path) == 1:
- cim_ccs_path = cim_ccss_path[0]
- elif len(cim_ccss_path) == 0:
+ if cim_ccs is None:
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Got %d instance of " % len(cim_ccss_path) +
- "ControllerConfigurationService from %s" %
- cim_sys_path + " in _cim_spc_of()")
+
cim_spcs = self._c.Associators(
- cim_ccs_path,
+ cim_ccs.path,
AssocClass='CIM_ConcreteDependency',
ResultClass='CIM_SCSIProtocolController',
PropertyList=property_list)
@@ -1597,14 +1571,9 @@ class Smis(IStorageAreaNetwork):
"AccessGroup %s not found" % access_group_id)
return None

- def _cim_init_mg_of(self, cim_sys_path, property_list=None):
+ def _cim_init_mg_of(self, system_id, property_list=None):
"""
- There is no CIM_ComputerSystem association to
- CIM_InitiatorMaskingGroup, we use this association:
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
+ We use this association to get all CIM_InitiatorMaskingGroup:
CIM_GroupMaskingMappingService
|
| CIM_ServiceAffectsElement
@@ -1614,11 +1583,10 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = []

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system_id)

return self._c.Associators(
- cim_gmm_path,
+ cim_gmms.path,
AssocClass='CIM_ServiceAffectsElement',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)
@@ -1642,12 +1610,12 @@ class Smis(IStorageAreaNetwork):
system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
- cim_init_mg_pros)
+ cim_init_mgs = self._cim_init_mg_of(
+ system_id, cim_init_mg_pros)
rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
for x in cim_init_mgs))
elif mask_type == smis_cap.MASK_TYPE_MASK:
- cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
+ cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
rc.extend(
list(self._cim_spc_to_lsm(cim_spc, system_id)
for cim_spc in cim_spcs))
@@ -1658,7 +1626,7 @@ class Smis(IStorageAreaNetwork):

return search_property(rc, search_key, search_value)

- def _cim_init_path_check_or_create(self, cim_sys_path, init_id, init_type):
+ def _cim_init_path_check_or_create(self, system_id, init_id, init_type):
"""
Check whether CIM_StorageHardwareID exists, if not, create new one.
"""
@@ -1675,23 +1643,21 @@ class Smis(IStorageAreaNetwork):
"SMI-S Plugin does not support init_type %d" %
init_type)

- return self._cim_init_path_create(
- cim_sys_path, init_id, dmtf_id_type)
+ return self._cim_init_path_create(system_id, init_id, dmtf_id_type)

- def _cim_init_path_create(self, cim_sys_path, init_id, dmtf_id_type):
+ def _cim_init_path_create(self, system_id, init_id, dmtf_id_type):
"""
Create a CIM_StorageHardwareID.
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_StorageHardwareIDManagementService')
+ cim_hwms = self._c.cim_hwms_of_sys_id(system_id)

in_params = {'StorageID': init_id,
'IDType': pywbem.Uint16(dmtf_id_type)}

(rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- cim_hw_srv_path, **in_params)
+ cim_hwms.path, **in_params)
# CreateStorageHardwareID does not allow ASYNC
return self._wait_invoke(
rc, out, out_key='HardwareID',
@@ -1719,17 +1685,16 @@ class Smis(IStorageAreaNetwork):
return copy.deepcopy(access_group)

cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ access_group.system_id, init_id, init_type)

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
'MaskingGroup': cim_init_mg.path,
'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)

new_cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
@@ -1777,16 +1742,16 @@ class Smis(IStorageAreaNetwork):
# Check to see if we have this initiator already, if not we
# create it and then add to the view.

- self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)
+ self._cim_init_path_check_or_create(
+ access_group.system_id, init_id, init_type)

- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

in_params = {'InitiatorPortIDs': [init_id],
'ProtocolControllers': [cim_spc.path]}

(rc, out) = self._c.InvokeMethod('ExposePaths',
- cim_ccs_path, **in_params)
+ cim_ccs.path, **in_params)
cim_spc_path = self._wait_invoke(
rc, out, out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')
@@ -1801,8 +1766,6 @@ class Smis(IStorageAreaNetwork):
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
cim_init_mg_pros = self._cim_init_mg_pros()
cim_init_mg = self._cim_init_mg_of_id(
access_group.id, raise_error=True, property_list=cim_init_mg_pros)
@@ -1827,8 +1790,7 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

# RemoveMembers from InitiatorMaskingGroup
in_params = {
@@ -1838,7 +1800,7 @@ class Smis(IStorageAreaNetwork):

(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return self._cim_init_mg_to_lsm(
cim_init_mg, access_group.system_id)
@@ -1862,17 +1824,14 @@ class Smis(IStorageAreaNetwork):
return self._ag_init_del_old(access_group, init_id)

def _ag_init_del_old(self, access_group, init_id):
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)

- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

hide_params = {'InitiatorPortIDs': [init_id],
'ProtocolControllers': [cim_spc.path]}
(rc, out) = self._c.InvokeMethod(
- 'HidePaths', cim_ccs_path, **hide_params)
+ 'HidePaths', cim_ccs.path, **hide_params)

self._wait_invoke(rc, out)
return None
@@ -2369,7 +2328,7 @@ class Smis(IStorageAreaNetwork):

return None

- def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
+ def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
vol_id):
"""
This is buggy check, but it works on EMC VMAX which is only supported
@@ -2403,7 +2362,7 @@ class Smis(IStorageAreaNetwork):
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return cim_dev_mg.path

@@ -2459,11 +2418,10 @@ class Smis(IStorageAreaNetwork):
"iSCSI IQN access group")

cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ system.id, init_id, init_type)

# Create CIM_InitiatorMaskingGroup
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system.id)

in_params = {'GroupName': name,
'Members': [cim_init_path],
@@ -2473,7 +2431,7 @@ class Smis(IStorageAreaNetwork):

try:
(rc, out) = self._c.InvokeMethod(
- 'CreateGroup', cim_gmm_path, **in_params)
+ 'CreateGroup', cim_gmms.path, **in_params)

cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
@@ -2507,7 +2465,7 @@ class Smis(IStorageAreaNetwork):
# Since 1) already checked whether any group containing
# requested init_id, now, it's surly a conflict.
exist_cim_init_mgs = self._cim_init_mg_of(
- cim_sys.path, property_list=['ElementName'])
+ system.id, property_list=['ElementName'])
for exist_cim_init_mg in exist_cim_init_mgs:
if exist_cim_init_mg['ElementName'] == name:
raise LsmError(ErrorNumber.NAME_CONFLICT,
@@ -2544,17 +2502,14 @@ class Smis(IStorageAreaNetwork):
"Access Group %s has volume masked" %
access_group.id)

- cim_gmm_path = self._c.AssociatorNames(
- cim_init_mg.path,
- AssocClass='CIM_ServiceAffectsElement',
- ResultClass='CIM_GroupMaskingMappingService')[0]
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
'MaskingGroup': cim_init_mg.path,
'Force': True,
}

- (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmms.path,
**in_params)

self._wait_invoke(rc, out)
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
index 1309056..1fee9a8 100644
--- a/plugin/smispy/smis_cap.py
+++ b/plugin/smispy/smis_cap.py
@@ -23,17 +23,19 @@ MASK_TYPE_MASK = 1
MASK_TYPE_GROUP = 2


-def _rs_supported_capabilities(smis_common, system, cap):
+def _rs_supported_capabilities(smis_common, system_id, cap):
"""
Interrogate the supported features of the replication service
"""
- rs = smis_common.get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, raise_error=False)
- if rs:
+ cim_rs = smis_common.cim_rs_of_sys_id(system_id, raise_error=False)
+ if cim_rs:
rs_cap = smis_common.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_ReplicationServiceCapabilities')[0]
+ ResultClass='CIM_ReplicationServiceCapabilities',
+ PropertyList=['SupportedReplicationTypes',
+ 'SupportedAsynchronousActions',
+ 'SupportedSynchronousActions'])[0]

s_rt = rs_cap['SupportedReplicationTypes']
async_actions = rs_cap['SupportedAsynchronousActions']
@@ -55,18 +57,17 @@ def _rs_supported_capabilities(smis_common, system, cap):
else:
# Try older storage configuration service

- rs = smis_common.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', system.id,
- raise_error=False)
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)

- if rs:
- rs_cap = smis_common.Associators(
- rs.path,
+ if cim_scs:
+ cim_sc_cap = smis_common.Associators(
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedCopyTypes'])[0]

- if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
- sct = rs_cap['SupportedCopyTypes']
+ if cim_sc_cap is not None and 'SupportedCopyTypes' in cim_sc_cap:
+ sct = cim_sc_cap['SupportedCopyTypes']

if sct and len(sct):
cap.set(Capabilities.VOLUME_REPLICATE)
@@ -78,7 +79,7 @@ def _rs_supported_capabilities(smis_common, system, cap):
cap.set(Capabilities.VOLUME_REPLICATE_COPY)


-def _bsp_cap_set(smis_common, cim_sys_path, cap):
+def _bsp_cap_set(smis_common, system_id, cap):
"""
Set capabilities for these methods:
volumes()
@@ -87,10 +88,9 @@ def _bsp_cap_set(smis_common, cim_sys_path, cap):
volume_delete()
"""
# CIM_StorageConfigurationService is optional.
- cim_scs_path = smis_common.get_cim_service_path(
- cim_sys_path, 'CIM_StorageConfigurationService')
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)

- if cim_scs_path is None:
+ if cim_scs is None:
return

# These methods are mandatory for CIM_StorageConfigurationService:
@@ -101,7 +101,7 @@ def _bsp_cap_set(smis_common, cim_sys_path, cap):
# Hence we check CIM_StorageConfigurationCapabilities
# which is mandatory if CIM_StorageConfigurationService is supported.
cim_scs_cap = smis_common.Associators(
- cim_scs_path,
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_StorageConfigurationCapabilities',
PropertyList=['SupportedAsynchronousActions',
@@ -353,7 +353,7 @@ def get(smis_common, cim_sys, system):
cap = Capabilities()

if smis_common.is_netappe():
- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)

#TODO We need to investigate why our interrogation code doesn't
#work.
@@ -362,7 +362,7 @@ def get(smis_common, cim_sys, system):
return cap

# 'Block Services Package' profile
- _bsp_cap_set(smis_common, cim_sys.path, cap)
+ _bsp_cap_set(smis_common, system.id, cap)

# 'Disk Drive Lite' profile
_disk_cap_set(smis_common, cim_sys.path, cap)
@@ -380,5 +380,5 @@ def get(smis_common, cim_sys, system):
# 'FC Target Ports' and 'iSCSI Target Ports' profiles
_tgt_cap_set(smis_common, cim_sys.path, cap)

- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)
return cap
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 5b86ec8..3c9b947 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -252,65 +252,6 @@ class SmisCommon(object):
return _profile_check(
self._profile_dict, profile_name, spec_ver, raise_error)

- def get_class_instance(self, class_name, prop_name, prop_value,
- raise_error=True, property_list=None):
- """
- Gets an instance of a class that optionally matches a specific
- property name and value
- """
- instances = None
- if property_list is None:
- property_list = [prop_name]
- else:
- property_list = merge_list(property_list, [prop_name])
-
- try:
- cim_xxxs = self.EnumerateInstances(
- class_name, PropertyList=property_list)
- except CIMError as ce:
- error_code = tuple(ce)[0]
-
- if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
- raise_error is False:
- return None
- else:
- raise
-
- for cim_xxx in cim_xxxs:
- if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
- return cim_xxx
-
- if raise_error:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
- return None
-
- def get_cim_service_path(self, cim_sys_path, class_name):
- """
- Return None if not supported
- """
- try:
- cim_srvs = self.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass=class_name)
- except CIMError as ce:
- if ce[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
- return None
- else:
- raise
- if len(cim_srvs) == 1:
- return cim_srvs[0]
- elif len(cim_srvs) == 0:
- return None
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_get_cim_service_path(): Got unexpected(not 1) "
- "count of %s from cim_sys %s: %s" %
- (class_name, cim_sys_path, cim_srvs))
-
def _vendor_namespace(self):
if self.root_blk_cim_rp:
cim_syss_path = self._wbem_conn.AssociatorNames(
@@ -515,3 +456,72 @@ class SmisCommon(object):
error_handler(self, method_data)
else:
raise
+
+ def _cim_srv_of_sys_id(self, srv_name, sys_id, raise_error):
+ property_list = ['SystemName']
+
+ cim_srvs = self.EnumerateInstances(
+ srv_name,
+ PropertyList=property_list)
+ for cim_srv in cim_srvs:
+ if cim_srv['SystemName'] == sys_id:
+ return cim_srv
+
+ if raise_error:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Cannot find any '%s' for requested systemd ID" % srv_name)
+ return None
+
+
+ def cim_scs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_StorageConfigurationService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageConfigurationService', sys_id, raise_error)
+
+
+ def cim_rs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_ReplicationService for given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ReplicationService', sys_id, raise_error)
+
+
+ def cim_gmms_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_GroupMaskingMappingService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_GroupMaskingMappingService', sys_id, raise_error)
+
+
+ def cim_ccs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_ControllerConfigurationService for given
+ system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ControllerConfigurationService', sys_id, raise_error)
+
+ def cim_hwms_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_StorageHardwareIDManagementService for
+ given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageHardwareIDManagementService', sys_id, raise_error)
--
1.8.3.1


------------------------------------------------------------------------------
Tony Asleson
2014-11-08 00:58:39 UTC
Permalink
Post by Gris Ge
SmisCommon.cim_scs_of_sys_id() CIM_StorageConfigurationService
SmisCommon.cim_rs_of_sys_id() CIM_ReplicationService
SmisCommon.cim_gmms_of_sys_id() CIM_GroupMaskingMappingService
SmisCommon.cim_ccs_of_sys_id() CIM_ControllerConfigurationService
SmisCommon.cim_hwms_of_sys_id() CIM_StorageHardwareIDManagementService
* smis.Smis._cim_spc_of() changed to use system_id instead of cim_sys.path
to benefit this change.
---
plugin/smispy/smis.py | 219 +++++++++++++++++--------------------------
plugin/smispy/smis_cap.py | 46 ++++-----
plugin/smispy/smis_common.py | 128 +++++++++++++------------
3 files changed, 179 insertions(+), 214 deletions(-)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 92dd164..966a5d1 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -59,8 +59,10 @@ from smis_common import SmisCommon
# cim_ip CIM_IPProtocolEndpoint
# cim_eth CIM_EthernetPort
# cim_pe CIM_SCSIProtocolEndpoint
-# cim_gmm CIM_GroupMaskingMappingService
+# cim_gmms CIM_GroupMaskingMappingService
# cim_ccs CIM_ControllerConfigurationService
+# cim_rs CIM_ReplicationService
+# cim_hwms CIM_StorageHardwareIDManagementService
#
# sys Object of LSM System
# pool Object of LSM Pool
"requested provisioning type")
# Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(pool.system_id)
+
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
self._c, pool)
SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
return self._c.invoke_method(
- 'CreateOrModifyElementFromStoragePool', scs.path,
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
in_params,
out_handler=self._new_vol_from_name,
error_handler=error_handler,
#Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', vol.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(vol.system_id)
in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}
job_id = self._c.invoke_method(
- 'ModifySynchronization', scs.path, in_params)[0]
+ 'ModifySynchronization', cim_scs.path, in_params)[0]
self._poll("ModifySynchronization, detach", job_id)
return self._detach_netapp_e(vol, sync)
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- vol.system_id, raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(vol.system_id, raise_error=False)
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}
job_id = self._c.invoke_method(
- 'ModifyReplicaSynchronization', rs.path, in_params)[0]
+ 'ModifyReplicaSynchronization', cim_rs.path, in_params)[0]
self._poll("ModifyReplicaSynchronization, detach", job_id)
self._detach(vol, s)
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
#If we actually have an association to delete, the volume will be
#Delete returns None or Job number
return self._c.invoke_method(
- 'ReturnToStoragePool', scs.path, in_params)[0]
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]
#Loop to check to see if volume is actually gone yet!
"""
Delete a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
# Delete returns None or Job number
return self._c.invoke_method(
- 'ReturnToStoragePool', scs.path, in_params)[0]
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]
@handle_cim_errors
"""
Re-size a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
'Size': pywbem.Uint64(new_size_bytes)}
return self._c.invoke_method(
- 'CreateOrModifyElementFromStoragePool', scs.path,
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
in_params, retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
"""
rc = [None, None]
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- system_id, raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(system_id, raise_error=False)
rs_cap = self._c.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_ReplicationServiceCapabilities')[0]
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- volume_src.system_id,
- raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(
+ volume_src.system_id, raise_error=False)
# Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
# ElementName, we have to do pre-check here.
src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
self._c, volume_src)
method = 'CreateElementReplica'
sync, mode = self._get_supported_sync_and_mode(
method = 'CreateReplica'
# Check for storage configuration service
- rs = self._c.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', volume_src.system_id,
- raise_error=False)
+ cim_rs = self._c.cim_scs_of_sys_id(
+ volume_src.system_id, raise_error=False)
ct = Volume.REPLICATE_CLONE
in_params = {'ElementName': name,
'CopyType': ct,
'SourceElement': src_cim_vol_path}
in_params['TargetPool'] = cim_pool_path
return self._c.invoke_method(
- method, rs.path, in_params,
+ method, cim_rs.path, in_params,
retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")
- def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
+ def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
rc = SmisCommon.SNIA_INVOKE_FAILED
out = None
cim_dev_mg_path = None
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
cim_dev_mg_path = self._check_exist_cim_dev_mg(
- name, cim_gmm_path, cim_vol_path, vol_id)
+ name, cim_gmms_path, cim_vol_path, vol_id)
raise
return cim_dev_mg_path
- def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
+ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
"""
Create CIM_TargetMaskingGroup
cim_tgt_mg_path = None
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
return cim_tgt_mg_path
- def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
+ def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
in_params = {
'ElementName': name,
'DeviceMaskingGroup': cim_dev_mg_path,
}
- (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmms_path,
**in_params)
return self._wait_invoke(
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
cim_spcs_path = self._c.AssociatorNames(
cim_init_mg.path,
# We have to create the SPC and dev_mg now.
cim_tgt_mg_path = self._cim_tgt_mg_path_create(
- cim_sys.path, cim_gmm_path, access_group.name,
+ cim_sys.path, cim_gmms.path, access_group.name,
access_group.init_type)
cim_dev_mg_path = self._cim_dev_mg_path_create(
- cim_gmm_path, access_group.name, cim_vol_path, volume.id)
+ cim_gmms.path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
- cim_gmm_path, cim_init_mg.path, cim_tgt_mg_path,
+ cim_gmms.path, cim_init_mg.path, cim_tgt_mg_path,
cim_dev_mg_path, access_group.name)
# CIM_InitiatorMaskingGroup might have multiple SPC when having
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None
access_group.id +
"will not do volume_mask()")
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_css_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
(rc, out) = self._c.InvokeMethod(
'ExposePaths',
- cim_css_path, **in_params)
+ cim_ccs.path, **in_params)
self._wait_invoke(rc, out)
return None
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_gmm_cap = self._c.Associators(
+ cim_gmms_cap = self._c.Associators(
cim_sys.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_GroupMaskingMappingCapabilities',
flag_empty_dev_in_spc = False
if dmtf.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
flag_empty_dev_in_spc = True
if ((dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedSynchronousActions']) and
+ cim_gmms_cap['SupportedSynchronousActions']) and
(dmtf.GMM_CAP_DELETE_SPC not in
raise LsmError(
ErrorNumber.NO_SUPPORT,
"volume_unmask() not supported. It requires one of these "
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(volume.system_id)
cim_spcs_path = self._c.AssociatorNames(
cim_vol_path,
}
(rc, out) = self._c.InvokeMethod(
'DeleteMaskingView',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
in_params = {
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None
return self._volume_unmask_old(access_group, volume)
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
hide_params = {'LUNames': [cim_vol['Name']],
'ProtocolControllers': [cim_spc.path]}
- (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs_path,
+ (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)
self._wait_invoke(rc, out)
"AccessGroup %s not found" % access_group_id)
return None
"""
Return a list of CIM_SCSIProtocolController.
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_ControllerConfigurationService
|
| CIM_ConcreteDependency
v
CIM_SCSIProtocolController
"""
- cim_ccss_path = []
+ cim_ccs = None
rc_cim_spcs = []
property_list = []
- cim_ccss_path = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(system_id, raise_error=False)
error_code = tuple(ce)[0]
if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported ' +
'by this array')
- cim_ccs_path = None
- cim_ccs_path = cim_ccss_path[0]
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Got %d instance of " % len(cim_ccss_path) +
- "ControllerConfigurationService from %s" %
- cim_sys_path + " in _cim_spc_of()")
+
cim_spcs = self._c.Associators(
- cim_ccs_path,
+ cim_ccs.path,
AssocClass='CIM_ConcreteDependency',
ResultClass='CIM_SCSIProtocolController',
PropertyList=property_list)
"AccessGroup %s not found" % access_group_id)
return None
"""
- There is no CIM_ComputerSystem association to
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_GroupMaskingMappingService
|
| CIM_ServiceAffectsElement
property_list = []
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system_id)
return self._c.Associators(
- cim_gmm_path,
+ cim_gmms.path,
AssocClass='CIM_ServiceAffectsElement',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)
system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
- cim_init_mg_pros)
+ cim_init_mgs = self._cim_init_mg_of(
+ system_id, cim_init_mg_pros)
rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
for x in cim_init_mgs))
- cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
+ cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
rc.extend(
list(self._cim_spc_to_lsm(cim_spc, system_id)
for cim_spc in cim_spcs))
return search_property(rc, search_key, search_value)
"""
Check whether CIM_StorageHardwareID exists, if not, create new one.
"""
"SMI-S Plugin does not support init_type %d" %
init_type)
- return self._cim_init_path_create(
- cim_sys_path, init_id, dmtf_id_type)
+ return self._cim_init_path_create(system_id, init_id, dmtf_id_type)
"""
Create a CIM_StorageHardwareID.
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_StorageHardwareIDManagementService')
+ cim_hwms = self._c.cim_hwms_of_sys_id(system_id)
in_params = {'StorageID': init_id,
'IDType': pywbem.Uint16(dmtf_id_type)}
(rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- cim_hw_srv_path, **in_params)
+ cim_hwms.path, **in_params)
# CreateStorageHardwareID does not allow ASYNC
return self._wait_invoke(
rc, out, out_key='HardwareID',
return copy.deepcopy(access_group)
cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ access_group.system_id, init_id, init_type)
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
in_params = {
'MaskingGroup': cim_init_mg.path,
'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
new_cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
# Check to see if we have this initiator already, if not we
# create it and then add to the view.
- self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)
+ self._cim_init_path_check_or_create(
+ access_group.system_id, init_id, init_type)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
in_params = {'InitiatorPortIDs': [init_id],
'ProtocolControllers': [cim_spc.path]}
(rc, out) = self._c.InvokeMethod('ExposePaths',
- cim_ccs_path, **in_params)
+ cim_ccs.path, **in_params)
cim_spc_path = self._wait_invoke(
rc, out, out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
cim_init_mg_pros = self._cim_init_mg_pros()
cim_init_mg = self._cim_init_mg_of_id(
access_group.id, raise_error=True, property_list=cim_init_mg_pros)
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
# RemoveMembers from InitiatorMaskingGroup
in_params = {
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return self._cim_init_mg_to_lsm(
cim_init_mg, access_group.system_id)
return self._ag_init_del_old(access_group, init_id)
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
hide_params = {'InitiatorPortIDs': [init_id],
'ProtocolControllers': [cim_spc.path]}
(rc, out) = self._c.InvokeMethod(
- 'HidePaths', cim_ccs_path, **hide_params)
+ 'HidePaths', cim_ccs.path, **hide_params)
self._wait_invoke(rc, out)
return None
return None
- def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
+ def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
"""
This is buggy check, but it works on EMC VMAX which is only supported
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
Should be cim_gmms_path.path or cim_gmms_path, not sure which at the
moment? cim_gmms is not a variable in this method.

Thanks,
Tony

------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:08 UTC
Permalink
* Empty smis_ag.py with license only.
* Makefile and RPM SPEC file updated.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 1 +
plugin/smispy/smis_ag.py | 16 ++++++++++++++++
3 files changed, 18 insertions(+)
create mode 100644 plugin/smispy/smis_ag.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 4fef3a4..d7f132d 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -479,6 +479,7 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
%{python_sitelib}/lsm/plugin/smispy/smis_disk.*
%{python_sitelib}/lsm/plugin/smispy/smis_vol.*
+%{python_sitelib}/lsm/plugin/smispy/smis_ag.*
%{_bindir}/smispy_lsmplugin

%files -n %{libstoragemgmt}-netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index 19da66a..78ceb36 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -32,6 +32,7 @@ smispy_PYTHON = \
smispy/smis_sys.py \
smispy/smis_pool.py \
smispy/smis_disk.py \
+ smispy/smis_ag.py \
smispy/smis_vol.py

nstordir = $(plugindir)/nstor
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
new file mode 100644
index 0000000..e1f46a5
--- /dev/null
+++ b/plugin/smispy/smis_ag.py
@@ -0,0 +1,16 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author: Gris Ge <***@redhat.com>
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:09 UTC
Permalink
* Removed smis._dmtf_init_type_to_lsm(). It has been merged into
smis_ag._cim_inits_to_lsm_init_id_and_type()

* Replaced these methods:
smis.Smis._cim_spc_pros()
-> smis_ag.cim_spc_pros()
smis.Smis._cim_inits_to_lsm()
-> smis_ag._cim_inits_to_lsm_init_id_and_type()
smis.Smis._cim_spc_to_lsm()
-> smis_ag.cim_spc_to_lsm_ag()
smis.Smis._cim_init_of_spc()
-> cim_init_of_cim_spc_path()
smis.Smis._cim_init_of_init_mg()
-> cim_init_of_cim_init_mg_path()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 212 +++++++++--------------------------------------
plugin/smispy/smis_ag.py | 136 ++++++++++++++++++++++++++++++
2 files changed, 174 insertions(+), 174 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 966a5d1..6a5bba3 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -30,6 +30,7 @@ import smis_sys
import smis_pool
import smis_disk
import smis_vol
+import smis_ag
import dmtf

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
@@ -96,15 +97,6 @@ def _lsm_init_id_to_snia(lsm_init_id):
return lsm_init_id


-def _dmtf_init_type_to_lsm(cim_init):
- if 'IDType' in cim_init:
- if cim_init['IDType'] == dmtf.ID_TYPE_WWPN:
- return AccessGroup.INIT_TYPE_WWPN
- elif cim_init['IDType'] == dmtf.ID_TYPE_ISCSI:
- return AccessGroup.INIT_TYPE_ISCSI_IQN
- return AccessGroup.INIT_TYPE_UNKNOWN
-
-
def _lsm_tgt_port_type_of_cim_fc_tgt(cim_fc_tgt):
"""
We are assuming we got CIM_FCPort. Caller should make sure of that.
@@ -452,59 +444,6 @@ class Smis(IStorageAreaNetwork):

return smis_vol.cim_vol_to_lsm_vol(self._c, cim_vol, pool_id, sys_id)

- def _cim_spc_pros(self):
- """
- Return a list of properties required to build new AccessGroup.
- """
- cim_spc_pros = ['DeviceID']
- cim_spc_pros.extend(self._property_list_of_id('SystemChild'))
- cim_spc_pros.extend(['ElementName', 'StorageID'])
- cim_spc_pros.extend(['EMCAdapterRole']) # EMC specific, used to
- # filter out the mapping SPC.
- return cim_spc_pros
-
- def _cim_inits_to_lsm(self, cim_inits):
- """
- Retrieve AccessGroup.init_ids and AccessGroup.init_type from
- a list of CIM_StorageHardwareID.
- """
- init_ids = []
- init_type = AccessGroup.INIT_TYPE_UNKNOWN
- init_types = []
- for cim_init in cim_inits:
- init_type = _dmtf_init_type_to_lsm(cim_init)
- if init_type == AccessGroup.INIT_TYPE_WWPN:
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- elif init_type == AccessGroup.INIT_TYPE_ISCSI_IQN:
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- # Skip if not a iscsi initiator IQN or WWPN.
- continue
-
- init_type_dict = {}
- for cur_init_type in init_types:
- init_type_dict[cur_init_type] = 1
-
- if len(init_type_dict) == 1:
- init_type = init_types[0]
- elif len(init_type_dict) == 2:
- init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
- return (init_ids, init_type)
-
- def _cim_spc_to_lsm(self, cim_spc, system_id=None):
- if system_id is None:
- system_id = self._sys_id_child(cim_spc)
- ag_id = md5(cim_spc['DeviceID'])
- ag_name = cim_spc['ElementName']
- ag_init_ids = []
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- sys_id = self._sys_id_child(cim_spc)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, sys_id)
-
def _new_vol_from_job(self, job):
"""
Given a concrete job instance, return referenced volume as lsm volume
@@ -1075,7 +1014,8 @@ class Smis(IStorageAreaNetwork):
cim_init_mg = self._cim_init_mg_of_id(access_group.id,
raise_error=True)

- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path)
+ cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg.path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
@@ -1161,7 +1101,7 @@ class Smis(IStorageAreaNetwork):

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

- cim_inits = self._cim_init_of_spc(cim_spc.path)
+ cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc.path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
@@ -1310,7 +1250,7 @@ class Smis(IStorageAreaNetwork):
return None

def _is_access_group(self, cim_spc):
- if self._c.is_netappe:
+ if self._c.is_netappe():
return True

rc = True
@@ -1389,77 +1329,6 @@ class Smis(IStorageAreaNetwork):
rc_cim_spcs.append(cim_spc)
return rc_cim_spcs

- def _cim_init_of_spc(self, cim_spc_path, property_list=None):
- """
- Take CIM_SCSIProtocolController and return a list of
- CIM_StorageHardwareID, both are CIMInstance.
- Two ways to get StorageHardwareID from SCSIProtocolController:
- * Method A (defined in SNIA SMIS 1.6):
- CIM_SCSIProtocolController
- |
- | CIM_AssociatedPrivilege
- v
- CIM_StorageHardwareID
-
- * Method B (defined in SNIA SMIS 1.3, 1.4, 1.5 and 1.6):
- CIM_SCSIProtocolController
- |
- | CIM_AuthorizedTarget
- v
- CIM_AuthorizedPrivilege
- |
- | CIM_AuthorizedSubject
- v
- CIM_StorageHardwareID
-
- Method A defined in SNIA SMIS 1.6 deprecated the Method B and Method A
- saved 1 query which provide better performance.
- Hence we try method A.
- Maybe someday, we will stop trying after knowing array's supported
- SMIS version.
- """
- cim_inits = []
- if property_list is None:
- property_list = []
-
- if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_6,
- raise_error=False):
- return self._c.Associators(
- cim_spc_path,
- AssocClass='CIM_AssociatedPrivilege',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
- else:
- cim_aps_path = self._c.AssociatorNames(
- cim_spc_path,
- AssocClass='CIM_AuthorizedTarget',
- ResultClass='CIM_AuthorizedPrivilege')
- for cim_ap_path in cim_aps_path:
- cim_inits.extend(self._c.Associators(
- cim_ap_path,
- AssocClass='CIM_AuthorizedSubject',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list))
- return cim_inits
-
- def _cim_init_of_init_mg(self, cim_init_mg_path, property_list=None):
- """
- Use this association:
- CIM_InitiatorMaskingGroup
- |
- | CIM_MemberOfCollection
- v
- CIM_StorageHardwareID
- """
- if property_list is None:
- property_list = []
- return self._c.Associators(
- cim_init_mg_path,
- AssocClass='CIM_MemberOfCollection',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
-
@handle_cim_errors
def volumes_accessible_by_access_group(self, access_group, flags=0):
mask_type = smis_cap.mask_type(self._c, raise_error=True)
@@ -1521,7 +1390,7 @@ class Smis(IStorageAreaNetwork):
if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_spc_pros = []
else:
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()

cim_spcs = self._c.Associators(
cim_vol_path,
@@ -1537,13 +1406,17 @@ class Smis(IStorageAreaNetwork):
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, volume.system_id)
- for x in cim_init_mgs))
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, x, volume.system_id)
+ for x in cim_init_mgs))
else:
for cim_spc in cim_spcs:
if self._is_access_group(cim_spc):
- rc.extend(
- [self._cim_spc_to_lsm(cim_spc, volume.system_id)])
+ rc.append(
+ smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, volume.system_id))

return rc

@@ -1599,7 +1472,7 @@ class Smis(IStorageAreaNetwork):
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)

- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
for cim_sys in cim_syss:
if cim_sys.path.classname == 'Clar_StorageSystem':
# Workaround for EMC VNX/CX.
@@ -1612,13 +1485,16 @@ class Smis(IStorageAreaNetwork):
cim_init_mg_pros = self._cim_init_mg_pros()
cim_init_mgs = self._cim_init_mg_of(
system_id, cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
- for x in cim_init_mgs))
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(self._c, x, system_id)
+ for x in cim_init_mgs))
elif mask_type == smis_cap.MASK_TYPE_MASK:
cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
rc.extend(
- list(self._cim_spc_to_lsm(cim_spc, system_id)
- for cim_spc in cim_spcs))
+ list(
+ smis_ag.cim_spc_to_lsm_ag(self._c, cim_spc, system_id)
+ for cim_spc in cim_spcs))
else:
raise LsmError(ErrorNumber.PLUGIN_BUG,
"_get_cim_spc_by_id(): Got invalid mask_type: "
@@ -1674,10 +1550,8 @@ class Smis(IStorageAreaNetwork):

cim_init_mg = self._cim_init_mg_of_id(access_group.id)

- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg.path)

# Check whether already added.
for exist_cim_init in exist_cim_inits:
@@ -1703,8 +1577,8 @@ class Smis(IStorageAreaNetwork):
new_cim_init_mg = self._c.GetInstance(
new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
LocalOnly=False)
- return self._cim_init_mg_to_lsm(
- new_cim_init_mg, access_group.system_id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, new_cim_init_mg, access_group.system_id)

@handle_cim_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
@@ -1731,9 +1605,8 @@ class Smis(IStorageAreaNetwork):

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

- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_spc_path(
+ self._c, cim_spc.path)

for exist_cim_init in exist_cim_inits:
if self._init_id(exist_cim_init) == init_id:
@@ -1756,10 +1629,11 @@ class Smis(IStorageAreaNetwork):
rc, out, out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')

- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
cim_spc = self._c.GetInstance(
cim_spc_path, PropertyList=cim_spc_pros, LocalOnly=False)
- return self._cim_spc_to_lsm(cim_spc, access_group.system_id)
+ return smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, access_group.system_id)

def _ag_init_del_group(self, access_group, init_id):
"""
@@ -1770,9 +1644,8 @@ class Smis(IStorageAreaNetwork):
cim_init_mg = self._cim_init_mg_of_id(
access_group.id, raise_error=True, property_list=cim_init_mg_pros)

- cim_init_pros = self._property_list_of_id('Initiator')
- cur_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, property_list=cim_init_pros)
+ cur_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg.path)

cim_init = None
for cur_cim_init in cur_cim_inits:
@@ -1802,8 +1675,8 @@ class Smis(IStorageAreaNetwork):
'RemoveMembers',
cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
- return self._cim_init_mg_to_lsm(
- cim_init_mg, access_group.system_id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, cim_init_mg, access_group.system_id)

@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, init_type,
@@ -2225,15 +2098,6 @@ class Smis(IStorageAreaNetwork):
def _cim_init_mg_pros(self):
return ['ElementName', 'InstanceID']

- def _cim_init_mg_to_lsm(self, cim_init_mg, system_id):
- ag_name = cim_init_mg['ElementName']
- ag_id = md5(cim_init_mg['InstanceID'])
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
-
def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
flag_out_array=False,):
"""
@@ -2451,8 +2315,8 @@ class Smis(IStorageAreaNetwork):
if len(exist_cim_init_mgs) != 0:
for exist_cim_init_mg in exist_cim_init_mgs:
if exist_cim_init_mg['ElementName'] == name:
- return self._cim_init_mg_to_lsm(
- exist_cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, exist_cim_init_mg, system.id)

# Name does not match.
raise LsmError(ErrorNumber.EXISTS_INITIATOR,
@@ -2476,7 +2340,7 @@ class Smis(IStorageAreaNetwork):

cim_init_mg = self._c.GetInstance(
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
- return self._cim_init_mg_to_lsm(cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(self._c, cim_init_mg, system.id)

@handle_cim_errors
def access_group_delete(self, access_group, flags=0):
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
index e1f46a5..102ce27 100644
--- a/plugin/smispy/smis_ag.py
+++ b/plugin/smispy/smis_ag.py
@@ -14,3 +14,139 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Author: Gris Ge <***@redhat.com>
+
+from pywbem import CIMError, CIM_ERR_NOT_FOUND
+
+from lsm import AccessGroup, md5
+
+from smis_common import SmisCommon
+import dmtf
+
+_CIM_INIT_PROS = ['StorageID', 'IDType']
+
+
+def _cim_inits_to_lsm_init_id_and_type(cim_inits):
+ """
+ Retrieve AccessGroup.init_ids and AccessGroup.init_type from
+ a list of CIM_StorageHardwareID.
+ """
+ init_ids = []
+ init_type = AccessGroup.INIT_TYPE_UNKNOWN
+ init_types = []
+ for cim_init in cim_inits:
+ if cim_init['IDType'] == dmtf.ID_TYPE_WWPN:
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_WWPN)
+ if cim_init['IDType'] == dmtf.ID_TYPE_ISCSI:
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_ISCSI_IQN)
+ # Skip if not a iscsi initiator IQN or WWPN.
+ continue
+
+ init_type_dict = {}
+ for cur_init_type in init_types:
+ init_type_dict[cur_init_type] = 1
+
+ if len(init_type_dict) == 1:
+ init_type = init_types[0]
+ elif len(init_type_dict) == 2:
+ init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
+ return (init_ids, init_type)
+
+
+def cim_spc_pros():
+ """
+ Return the property of CIM_SCSIProtocolController required to gernarate
+ lsm.AccessGroup
+ 'EMCAdapterRole' is for EMC VNX only.
+ """
+ return ['DeviceID', 'ElementName', 'StorageID', 'EMCAdapterRole',
+ 'SystemName']
+
+
+def cim_init_of_cim_spc_path(smis_common, cim_spc_path):
+ """
+ Return a list of CIM_StorageHardwareID associated to cim_spc.
+ Only contain ['StorageID', 'IDType'] property.
+ Two ways to get StorageHardwareID from SCSIProtocolController:
+ * Method A (defined in SNIA SMIS 1.6):
+ CIM_SCSIProtocolController
+ |
+ | CIM_AssociatedPrivilege
+ v
+ CIM_StorageHardwareID
+
+ * Method B (defined in SNIA SMIS 1.3, 1.4, 1.5 and 1.6):
+ CIM_SCSIProtocolController
+ |
+ | CIM_AuthorizedTarget
+ v
+ CIM_AuthorizedPrivilege
+ |
+ | CIM_AuthorizedSubject
+ v
+ CIM_StorageHardwareID
+ """
+ rc = []
+ if smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_6,
+ raise_error=False):
+ try:
+ rc = smis_common.Associators(
+ cim_spc_path,
+ AssocClass='CIM_AssociatedPrivilege',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+ except CIMError as ce:
+ if ce[0] == CIM_ERR_NOT_FOUND:
+ pass
+ else:
+ raise
+
+ if len(rc) == 0:
+ cim_aps_path = smis_common.AssociatorNames(
+ cim_spc_path,
+ AssocClass='CIM_AuthorizedTarget',
+ ResultClass='CIM_AuthorizedPrivilege')
+
+ for cim_ap_path in cim_aps_path:
+ rc.extend(smis_common.Associators(
+ cim_ap_path,
+ AssocClass='CIM_AuthorizedSubject',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS))
+ return rc
+
+
+def cim_spc_to_lsm_ag(smis_common, cim_spc, system_id):
+ ag_id = md5(cim_spc['DeviceID'])
+ ag_name = cim_spc['ElementName']
+ ag_init_ids = []
+ cim_inits = cim_init_of_cim_spc_path(smis_common, cim_spc.path)
+ (init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
+ return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
+
+
+def cim_init_of_cim_init_mg_path(smis_common, cim_init_mg_path):
+ """
+ Use this association to get a list of CIM_StorageHardwareID:
+ CIM_InitiatorMaskingGroup
+ |
+ | CIM_MemberOfCollection
+ v
+ CIM_StorageHardwareID
+ Only contain ['StorageID', 'IDType'] property.
+ """
+ return smis_common.Associators(
+ cim_init_mg_path,
+ AssocClass='CIM_MemberOfCollection',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+
+
+def cim_init_mg_to_lsm_ag(smis_common, cim_init_mg, system_id):
+ ag_name = cim_init_mg['ElementName']
+ ag_id = md5(cim_init_mg['InstanceID'])
+ cim_inits = cim_init_of_cim_init_mg_path(smis_common, cim_init_mg.path)
+ (init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
+ return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:10 UTC
Permalink
* Save cim_spc_path or cim_init_mg_path into lsm.AccessGroup.plugin_data
* Replaces these methods for converting lsm.AccessGroup to
cim_spc/cim_init_mg:
smis.Smis._cim_spc_of_id()
-> smis_ag.lsm_ag_to_cim_spc_path()
smis.Smis._cim_init_mg_of_id()
-> smis_ag.lsm_ag_to_cim_init_mg_path()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 121 +++++++++++++++--------------------------------
plugin/smispy/smis_ag.py | 39 ++++++++++++++-
2 files changed, 76 insertions(+), 84 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 6a5bba3..02d9a6d 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -1011,11 +1011,11 @@ class Smis(IStorageAreaNetwork):
"""
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

- cim_init_mg = self._cim_init_mg_of_id(access_group.id,
- raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
- self._c, cim_init_mg.path)
+ self._c, cim_init_mg_path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
@@ -1035,7 +1035,7 @@ class Smis(IStorageAreaNetwork):
cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

@@ -1048,7 +1048,7 @@ class Smis(IStorageAreaNetwork):
cim_gmms.path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
- cim_gmms.path, cim_init_mg.path, cim_tgt_mg_path,
+ cim_gmms.path, cim_init_mg_path, cim_tgt_mg_path,
cim_dev_mg_path, access_group.name)
else:
# CIM_InitiatorMaskingGroup might have multiple SPC when having
@@ -1098,10 +1098,9 @@ class Smis(IStorageAreaNetwork):
return self._volume_mask_old(access_group, volume, flags)

def _volume_mask_old(self, access_group, volume, flags):
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc.path)
+ cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc_path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
@@ -1114,7 +1113,7 @@ class Smis(IStorageAreaNetwork):
cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

in_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path],
+ 'ProtocolControllers': [cim_spc_path],
'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}

(rc, out) = self._c.InvokeMethod(
@@ -1238,10 +1237,10 @@ class Smis(IStorageAreaNetwork):
cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

hide_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}

(rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)
@@ -1266,30 +1265,6 @@ class Smis(IStorageAreaNetwork):
rc = False
return rc

- def _cim_spc_of_id(self, access_group_id, property_list=None,
- raise_error=False):
- """
- Return CIMInstance of CIM_SCSIProtocolController
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- if property_list is None:
- property_list = ['DeviceID']
- else:
- property_list = merge_list(property_list, ['DeviceID'])
-
- cim_spcs = self._c.EnumerateInstances(
- 'CIM_SCSIProtocolController', PropertyList=property_list)
-
- for cim_spc in cim_spcs:
- if md5(cim_spc['DeviceID']) == access_group_id:
- return cim_spc
-
- if raise_error is True:
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
def _cim_spc_of(self, system_id, property_list=None):
"""
Return a list of CIM_SCSIProtocolController.
@@ -1343,11 +1318,11 @@ class Smis(IStorageAreaNetwork):
mask_type = smis_cap.MASK_TYPE_MASK

if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

@@ -1359,9 +1334,10 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros))
else:
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)
cim_vols = self._c.Associators(
- cim_spc.path,
+ cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
@@ -1420,30 +1396,6 @@ class Smis(IStorageAreaNetwork):

return rc

- def _cim_init_mg_of_id(self, access_group_id, property_list=None,
- raise_error=False):
- """
- Return CIMInstance of CIM_InitiatorMaskingGroup
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- if property_list is None:
- property_list = ['InstanceID']
- else:
- property_list = merge_list(property_list, ['InstanceID'])
-
- cim_init_mgs = self._c.EnumerateInstances(
- 'CIM_InitiatorMaskingGroup', PropertyList=property_list)
-
- for cim_init_mg in cim_init_mgs:
- if md5(cim_init_mg['InstanceID']) == access_group_id:
- return cim_init_mg
-
- if raise_error is True:
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
def _cim_init_mg_of(self, system_id, property_list=None):
"""
We use this association to get all CIM_InitiatorMaskingGroup:
@@ -1548,10 +1500,11 @@ class Smis(IStorageAreaNetwork):
"new initiator which is not supported by LSM yet. "
"Please do it via EMC vendor specific tools.")

- cim_init_mg = self._cim_init_mg_of_id(access_group.id)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

exist_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
- self._c, cim_init_mg.path)
+ self._c, cim_init_mg_path)

# Check whether already added.
for exist_cim_init in exist_cim_inits:
@@ -1564,7 +1517,7 @@ class Smis(IStorageAreaNetwork):
cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
@@ -1603,10 +1556,11 @@ class Smis(IStorageAreaNetwork):
"Please do it via EMC vendor specific tools. "
"EMC VNX does not support adding iSCSI IQN neither")

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)

exist_cim_inits = smis_ag.cim_init_of_cim_spc_path(
- self._c, cim_spc.path)
+ self._c, cim_spc_path)

for exist_cim_init in exist_cim_inits:
if self._init_id(exist_cim_init) == init_id:
@@ -1621,7 +1575,7 @@ class Smis(IStorageAreaNetwork):
cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

in_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}

(rc, out) = self._c.InvokeMethod('ExposePaths',
cim_ccs.path, **in_params)
@@ -1640,12 +1594,10 @@ class Smis(IStorageAreaNetwork):
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True, property_list=cim_init_mg_pros)
-
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
cur_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
- self._c, cim_init_mg.path)
+ self._c, cim_init_mg_path)

cim_init = None
for cur_cim_init in cur_cim_inits:
@@ -1667,7 +1619,7 @@ class Smis(IStorageAreaNetwork):

# RemoveMembers from InitiatorMaskingGroup
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init.path],
}

@@ -1675,6 +1627,11 @@ class Smis(IStorageAreaNetwork):
'RemoveMembers',
cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
+
+ cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg = self._c.GetInstance(
+ cim_init_mg_path, PropertyList=cim_init_mg_pros)
+
return smis_ag.cim_init_mg_to_lsm_ag(
self._c, cim_init_mg, access_group.system_id)

@@ -1697,12 +1654,12 @@ class Smis(IStorageAreaNetwork):
return self._ag_init_del_old(access_group, init_id)

def _ag_init_del_old(self, access_group, init_id):
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

hide_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
(rc, out) = self._c.InvokeMethod(
'HidePaths', cim_ccs.path, **hide_params)

@@ -2348,12 +2305,12 @@ class Smis(IStorageAreaNetwork):
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
raise_error=True)

- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

# Check whether still have volume masked.
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

@@ -2369,7 +2326,7 @@ class Smis(IStorageAreaNetwork):
cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Force': True,
}

diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
index 102ce27..1473047 100644
--- a/plugin/smispy/smis_ag.py
+++ b/plugin/smispy/smis_ag.py
@@ -21,6 +21,7 @@ from lsm import AccessGroup, md5

from smis_common import SmisCommon
import dmtf
+from utils import cim_path_to_path_str, path_str_to_cim_path

_CIM_INIT_PROS = ['StorageID', 'IDType']

@@ -124,7 +125,9 @@ def cim_spc_to_lsm_ag(smis_common, cim_spc, system_id):
ag_init_ids = []
cim_inits = cim_init_of_cim_spc_path(smis_common, cim_spc.path)
(init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
+ plugin_data = cim_path_to_path_str(cim_spc.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)


def cim_init_of_cim_init_mg_path(smis_common, cim_init_mg_path):
@@ -149,4 +152,36 @@ def cim_init_mg_to_lsm_ag(smis_common, cim_init_mg, system_id):
ag_id = md5(cim_init_mg['InstanceID'])
cim_inits = cim_init_of_cim_init_mg_path(smis_common, cim_init_mg.path)
(init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
+ plugin_data = cim_path_to_path_str(cim_init_mg.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+def lsm_ag_to_cim_spc_path(smis_common, lsm_ag):
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_SCSIProtocolController
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ if not lsm_ag.plugin_data:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.AccessGroup instance with empty plugin_data")
+ if smis_common.system_list and \
+ lsm_ag.system_id not in smis_common.system_list:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_ag.plugin_data)
+
+
+def lsm_ag_to_cim_init_mg_path(smis_common, lsm_ag):
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_InitiatorMaskingGroup
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ return lsm_ag_to_cim_spc_path(smis_common, lsm_ag)
--
1.8.3.1


------------------------------------------------------------------------------
Tony Asleson
2014-11-08 00:58:53 UTC
Permalink
Post by Gris Ge
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
index 102ce27..1473047 100644
--- a/plugin/smispy/smis_ag.py
+++ b/plugin/smispy/smis_ag.py
@@ -21,6 +21,7 @@ from lsm import AccessGroup, md5
from smis_common import SmisCommon
import dmtf
+from utils import cim_path_to_path_str, path_str_to_cim_path
_CIM_INIT_PROS = ['StorageID', 'IDType']
ag_init_ids = []
cim_inits = cim_init_of_cim_spc_path(smis_common, cim_spc.path)
(init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
+ plugin_data = cim_path_to_path_str(cim_spc.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
ag_id = md5(cim_init_mg['InstanceID'])
cim_inits = cim_init_of_cim_init_mg_path(smis_common, cim_init_mg.path)
(init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
+ plugin_data = cim_path_to_path_str(cim_init_mg.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_SCSIProtocolController
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.AccessGroup instance with empty plugin_data")
+ if smis_common.system_list and \
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
Missing imports for ErrorNumber and LsmError for smis_ag.py

Thanks,
Tony

------------------------------------------------------------------------------
Gris Ge
2014-11-07 11:44:11 UTC
Permalink
* Replace smis.Smis._cim_init_mg_pros() with
smis_ag.cim_init_mg_pros()

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 13 +++++--------
plugin/smispy/smis_ag.py | 8 ++++++++
2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 02d9a6d..38880e4 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -1375,7 +1375,7 @@ class Smis(IStorageAreaNetwork):
PropertyList=cim_spc_pros)

if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
for cim_spc in cim_spcs:
cim_init_mgs = self._c.Associators(
cim_spc.path,
@@ -1434,7 +1434,7 @@ class Smis(IStorageAreaNetwork):

system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
cim_init_mgs = self._cim_init_mg_of(
system_id, cim_init_mg_pros)
rc.extend(
@@ -1526,7 +1526,7 @@ class Smis(IStorageAreaNetwork):
new_cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
expect_class='CIM_InitiatorMaskingGroup')
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
new_cim_init_mg = self._c.GetInstance(
new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
LocalOnly=False)
@@ -1628,7 +1628,7 @@ class Smis(IStorageAreaNetwork):
cim_gmms.path, **in_params)
self._wait_invoke(rc, out)

- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
cim_init_mg = self._c.GetInstance(
cim_init_mg_path, PropertyList=cim_init_mg_pros)

@@ -2052,9 +2052,6 @@ class Smis(IStorageAreaNetwork):

return search_property(rc, search_key, search_value)

- def _cim_init_mg_pros(self):
- return ['ElementName', 'InstanceID']
-
def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
flag_out_array=False,):
"""
@@ -2248,7 +2245,7 @@ class Smis(IStorageAreaNetwork):
'Members': [cim_init_path],
'Type': dmtf.MASK_GROUP_TYPE_INIT}

- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()

try:
(rc, out) = self._c.InvokeMethod(
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
index 1473047..b571aaf 100644
--- a/plugin/smispy/smis_ag.py
+++ b/plugin/smispy/smis_ag.py
@@ -65,6 +65,14 @@ def cim_spc_pros():
'SystemName']


+def cim_init_mg_pros():
+ """
+ Return the property of CIM_InitiatorMaskingGroup required to gernarate
+ lsm.AccessGroup
+ """
+ return ['ElementName', 'InstanceID']
+
+
def cim_init_of_cim_spc_path(smis_common, cim_spc_path):
"""
Return a list of CIM_StorageHardwareID associated to cim_spc.
--
1.8.3.1


------------------------------------------------------------------------------
Tony Asleson
2014-11-08 01:04:51 UTC
Permalink
I will likely squash the revised patch set before it gets committed. A
number of the intermediate steps are incomplete and cannot stand alone.

Thanks,
Tony
Post by Gris Ge
* The volume mask/unmask require both smis_ag and smis_vol, hence I
use one big patch set instead of two patch sets.
* EMC VMAX
* EMC VNX
* HP 3PAR
SMI-S Plugin: Add smis_vol.py file.
SMI-S Plugin: Move Volume.id generator to smis_vol.py
SMI-S Plugin: Move _cim_vol_pros() to smis_vol.py
SMI-S Plugin: Move cim_vol converter to smis_vol.py
SMI-S Plugin: Move CIMInstanceName converter to utils.py
SMI-S Plugin: Move job handling to SmisCommon
SMI-S Plugin: Store cim_vol_path in Volume.plugin_date
SMI-S Plugin: Move service retriever to smis_common.py
SMI-S Plugin: Add smis_ag.py file.
SMI-S Plugin: Move lsm.AccessGroup converter to smis_ag.py
SMI-S Plugin: Store cim_xxx_path in lsm.AccessGroup.plugin_data
SMI-S Plugin: Move CIM_InitiatorMaskingGroup property list to
smis_ag.py
packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 4 +-
plugin/smispy/dmtf.py | 2 +
plugin/smispy/smis.py | 1095 +++++++++++---------------------------
plugin/smispy/smis_ag.py | 195 +++++++
plugin/smispy/smis_cap.py | 46 +-
plugin/smispy/smis_common.py | 277 +++++++---
plugin/smispy/smis_pool.py | 28 +-
plugin/smispy/smis_sys.py | 10 +
plugin/smispy/smis_vol.py | 228 ++++++++
plugin/smispy/utils.py | 23 +-
11 files changed, 1014 insertions(+), 896 deletions(-)
create mode 100644 plugin/smispy/smis_ag.py
create mode 100644 plugin/smispy/smis_vol.py
------------------------------------------------------------------------------
Gris Ge
2014-11-10 15:13:25 UTC
Permalink
* New script:
1. smis_ag.py: Hold AccessGroup related methods
2. smis_vol.py: Hold Volume related methods
* Makefile and RPM SPEC file updated for new file smis_ag.py and smis_vol.py.
* Replaces smis.Smis._vol_id() with smis_vol.vol_id_of_cim_vol()
* Replaces smis.Smis._property_list_of_id('Volume') with
smis_vol.cim_vol_id_pros()
* Replace smis.Smis._cim_vol_pros() with smis_vol.cim_vol_pros()
* Replace smis.Smis._new_vol() with smis_pool.cim_vol_to_lsm_vol()
* Moved _vpd83_xxx method into smis_pool.py as it's private used by
smis_pool.cim_vol_to_lsm_vol()
* The smis_pool.cim_vol_to_lsm_vol() require caller to provide pool_id and
systemd_id as they should handled by smis_pool.py and smis_sys.py.
smis_sys.sys_id_of_cim_vol() is added for this seek.
* As these two methods will be commonly used across smis_xxx.py,
move them into utils.py file:
smis_pool._cim_path_to_path_str()
-> utils.cim_path_to_path_str()
smis_pool._path_str_to_cim_path()
- utils.path_str_to_cim_path()
* Replace smis.Smis._pi() with SmisCommon.invoke_method().
* When a exception triggered, invoke_method() will call 'error_handler'
with argument of: SmisCommon, method_data.
In this patch, smis_vol.volume_create_error_handler() is the
error_handler of volume_create(). It's stored in
smis.Smis._JOB_ERROR_HANDLER[SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
so that job_status() could use the same error handler.
* The invoke_method() also take 'out_handler' parameter which will be
called if the method finished in SYNC way.
In this patch, self._new_vol_from_name() is the out_handler of
volume_create().
* Moved job id generator and parser into smis_common.py:
smis.Smis._job_id() -> smis_common.SmisCommon.job_id_of_cim_job()
smis.Smis._parse_job_id() -> smis_common.SmisCommon.parse_job_id()
* Move duplicate volume checker method to smis_vol.py as the volume create
error handler require it while smis_vol.py cannot depend on smis.py:
smis.Smis._volume_exists -> smis_vol.volume_name_exists
smis.Smis._check_for_dupe_vol() -> smis_vol.volume_create_error_handler()
* Store cim_vol_path data in Volume.plugin_date.
* Replace
smis.Smis._get_cim_instance_by_id('Volume', volume.id)
-> smis_vol.lsm_vol_to_cim_vol_path()
* Changed smis.Smis._deal_volume_associations_netappe() and
smis.Smis._deal_volume_associations() to take cim_vol_path only.
* Replace SmisCommon.get_class_instance() and get_cim_service_path() with:
SmisCommon.cim_scs_of_sys_id() CIM_StorageConfigurationService
SmisCommon.cim_rs_of_sys_id() CIM_ReplicationService
SmisCommon.cim_gmms_of_sys_id() CIM_GroupMaskingMappingService
SmisCommon.cim_ccs_of_sys_id() CIM_ControllerConfigurationService
SmisCommon.cim_hwms_of_sys_id() CIM_StorageHardwareIDManagementService
* smis.Smis._cim_spc_of() changed to use system_id instead of cim_sys.path
to benefit this change.
* Empty smis_ag.py with license only.
* Makefile and RPM SPEC file updated.
* Removed smis._dmtf_init_type_to_lsm(). It has been merged into
smis_ag._cim_inits_to_lsm_init_id_and_type()
* Replaced these methods:
smis.Smis._cim_spc_pros()
-> smis_ag.cim_spc_pros()
smis.Smis._cim_inits_to_lsm()
-> smis_ag._cim_inits_to_lsm_init_id_and_type()
smis.Smis._cim_spc_to_lsm()
-> smis_ag.cim_spc_to_lsm_ag()
smis.Smis._cim_init_of_spc()
-> cim_init_of_cim_spc_path()
smis.Smis._cim_init_of_init_mg()
-> cim_init_of_cim_init_mg_path()
* Save cim_spc_path or cim_init_mg_path into lsm.AccessGroup.plugin_data
* Replaces these methods for converting lsm.AccessGroup to
cim_spc/cim_init_mg:
smis.Smis._cim_spc_of_id()
-> smis_ag.lsm_ag_to_cim_spc_path()
smis.Smis._cim_init_mg_of_id()
-> smis_ag.lsm_ag_to_cim_init_mg_path()
* Replace smis.Smis._cim_init_mg_pros() with
smis_ag.cim_init_mg_pros()

Changes in V2:
* Fix typo: gernarate -> generate in smis_vol.py.
* Correct document for smis_vol.volume_name_exists:
:param name: Volume ElementName
-> :param volume_name: Volume ElementName
* Fix incorrect variable name in smis_common.SmisCommon.invoke_method():
msg, datetime.datetime.now().isoformat())
-> : cmd, datetime.datetime.now().isoformat())
* Fix typo in smis_common.SmisCommon:
defination -> definition
metioned -> motioned
* Fix incorrect variable in smis.Smis._check_exist_cim_dev_mg():
cim_gmm.path, **in_params)
-> cim_gmms_path, **in_params)
* Add the missing import in smis_ag.py:
LsmError, ErrorNumber

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 4 +-
plugin/smispy/dmtf.py | 2 +
plugin/smispy/smis.py | 1095 +++++++++++---------------------------
plugin/smispy/smis_ag.py | 195 +++++++
plugin/smispy/smis_cap.py | 46 +-
plugin/smispy/smis_common.py | 281 +++++++---
plugin/smispy/smis_pool.py | 28 +-
plugin/smispy/smis_sys.py | 10 +
plugin/smispy/smis_vol.py | 228 ++++++++
plugin/smispy/utils.py | 23 +-
11 files changed, 1016 insertions(+), 898 deletions(-)
create mode 100644 plugin/smispy/smis_ag.py
create mode 100644 plugin/smispy/smis_vol.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 0ef7c16..d7f132d 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -478,6 +478,8 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
%{python_sitelib}/lsm/plugin/smispy/smis_disk.*
+%{python_sitelib}/lsm/plugin/smispy/smis_vol.*
+%{python_sitelib}/lsm/plugin/smispy/smis_ag.*
%{_bindir}/smispy_lsmplugin

%files -n %{libstoragemgmt}-netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index c3084c9..78ceb36 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -31,7 +31,9 @@ smispy_PYTHON = \
smispy/smis_cap.py \
smispy/smis_sys.py \
smispy/smis_pool.py \
- smispy/smis_disk.py
+ smispy/smis_disk.py \
+ smispy/smis_ag.py \
+ smispy/smis_vol.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 576c72e..c44db2f 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -242,3 +242,5 @@ def op_status_list_conv(conv_dict, dmtf_op_status_list,
CTRL_CONF_SRV_DA_RW = Uint16(2)

VOL_OTHER_INFO_NAA_VPD83_TYPE3H = 'NAA;VPD83Type3'
+
+VOL_USAGE_SYS_RESERVED = Uint16(3)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a571d9d..bdca963 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -19,11 +19,8 @@

from string import split
import time
-import traceback
import copy
import os
-import datetime
-import sys
import re

import pywbem
@@ -32,6 +29,8 @@
import smis_sys
import smis_pool
import smis_disk
+import smis_vol
+import smis_ag
import dmtf

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
@@ -61,8 +60,10 @@
# cim_ip CIM_IPProtocolEndpoint
# cim_eth CIM_EthernetPort
# cim_pe CIM_SCSIProtocolEndpoint
-# cim_gmm CIM_GroupMaskingMappingService
+# cim_gmms CIM_GroupMaskingMappingService
# cim_ccs CIM_ControllerConfigurationService
+# cim_rs CIM_ReplicationService
+# cim_hwms CIM_StorageHardwareIDManagementService
#
# sys Object of LSM System
# pool Object of LSM Pool
@@ -96,15 +97,6 @@ def _lsm_init_id_to_snia(lsm_init_id):
return lsm_init_id


-def _dmtf_init_type_to_lsm(cim_init):
- if 'IDType' in cim_init:
- if cim_init['IDType'] == dmtf.ID_TYPE_WWPN:
- return AccessGroup.INIT_TYPE_WWPN
- elif cim_init['IDType'] == dmtf.ID_TYPE_ISCSI:
- return AccessGroup.INIT_TYPE_ISCSI_IQN
- return AccessGroup.INIT_TYPE_UNKNOWN
-
-
def _lsm_tgt_port_type_of_cim_fc_tgt(cim_fc_tgt):
"""
We are assuming we got CIM_FCPort. Caller should make sure of that.
@@ -139,10 +131,14 @@ class Smis(IStorageAreaNetwork):
_INVOKE_MAX_LOOP_COUNT = 60
_INVOKE_CHECK_INTERVAL = 5

+ _JOB_ERROR_HANDLER = {
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
+ smis_vol.volume_create_error_handler,
+ }
+
def __init__(self):
self._c = None
self.tmo = 0
- self.debug_path = None

def _get_cim_instance_by_id(self, class_type, requested_id,
property_list=None, raise_error=True):
@@ -163,7 +159,8 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
class_name, PropertyList=property_list)
org_requested_id = requested_id
if class_type == 'Job':
- (requested_id, ignore, ignore) = Smis._parse_job_id(requested_id)
+ (requested_id, ignore, ignore) = SmisCommon.parse_job_id(
+ requested_id)
for cim_xxx in cim_xxxs:
if self._id(class_type, cim_xxx) == requested_id:
return cim_xxx
@@ -174,53 +171,6 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))

- def _pi(self, msg, retrieve_data, method_data, rc, out):
- """
- Handle the the process of invoking an operation.
- """
- # Check to see if operation is done
- if rc == SmisCommon.SNIA_INVOKE_OK:
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- return None, self._new_vol_from_name(out)
- else:
- return None, None
-
- elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
- # We have an async operation
- job_id = self._job_id(out['Job'], retrieve_data, method_data)
- return job_id, None
- elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
- raise LsmError(
- ErrorNumber.NO_SUPPORT,
- 'SMI-S error code indicates operation not supported')
- else:
- # When debugging issues with providers it's helpful to have the
- # xml request/reply to give to provider developers.
- try:
- if self.debug_path is not None:
- if not os.path.exists(self.debug_path):
- os.makedirs(self.debug_path)
-
- if os.path.isdir(self.debug_path):
- debug_fn = "%s_%s" % \
- (msg, datetime.datetime.now().isoformat())
- debug_full = os.path.join(self.debug_path, debug_fn)
-
- # Dump the request & reply to a file
- with open(debug_full, 'w') as d:
- d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
- (self._c.last_request, self._c.last_reply))
-
- except Exception:
- tb = traceback.format_exc()
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc) +
- ' Debug data exception: ' + str(tb))
-
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc))
-
@handle_cim_errors
def plugin_register(self, uri, password, timeout, flags=0):
"""
@@ -260,14 +210,13 @@ def plugin_register(self, uri, password, timeout, flags=0):
and u["parameters"]["no_ssl_verify"] == 'yes':
no_ssl_verify = True

- debug = False
+ debug_path = None
if 'debug_path' in u['parameters']:
self.debug_path = u['parameters']['debug_path']
- debug = True

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

self.tmo = timeout

@@ -319,41 +268,53 @@ def job_status(self, job_id, flags=0):
"""
completed_item = None

- props = ['JobState', 'PercentComplete', 'ErrorDescription',
- 'OperationalStatus']
- cim_job_pros = self._property_list_of_id('Job', props)
+ error_handler = None
+
+ (ignore, retrieve_data, method_data) = SmisCommon.parse_job_id(job_id)

- cim_job = self._get_cim_instance_by_id('Job', job_id, cim_job_pros)
+ if retrieve_data in Smis._JOB_ERROR_HANDLER.keys():
+ error_handler = Smis._JOB_ERROR_HANDLER[retrieve_data]
+
+ cim_job_pros = SmisCommon.cim_job_pros()
+ cim_job_pros.extend(
+ ['JobState', 'PercentComplete', 'ErrorDescription',
+ 'OperationalStatus'])
+ cim_job = self._c.cim_job_of_job_id(job_id, cim_job_pros)

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

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

- pc = cim_job['PercentComplete']
- if pc > 100:
- percent_complete = 100
- else:
- percent_complete = pc
+ pc = cim_job['PercentComplete']
+ if pc > 100:
+ percent_complete = 100
+ else:
+ percent_complete = pc

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

- if Smis._job_completed_ok(cim_job):
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- completed_item = self._new_vol_from_job(cim_job)
+ if Smis._job_completed_ok(cim_job):
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
+ retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
+ completed_item = self._new_vol_from_job(cim_job)
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ str(cim_job['ErrorDescription']))
else:
- status = JobStatus.ERROR
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG, str(cim_job['ErrorDescription']))

- else:
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- self._check_for_dupe_vol(method_data, None)
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- str(cim_job['ErrorDescription']))
+ except Exception:
+ if error_handler is not None:
+ error_handler(self._c, method_data)
+ else:
+ raise

return status, percent_complete, completed_item

@@ -423,25 +384,6 @@ def _sys_id_child(self, cim_xxx):
"""
return self._id('SystemChild', cim_xxx)

- def _vol_id(self, cim_vol):
- """
- Return the MD5 hash of CIM_StorageVolume['SystemName'] and
- ['DeviceID']
- """
- return self._id('Volume', cim_vol)
-
- def _job_id(self, cim_job, retrieve_data, method_data):
- """
- Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
- with '@%s' % retrieve_data
- retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
- SmisCommon.JOB_RETRIEVE_VOLUME or etc
- method_data is any string a method would like store for error
- handling by job_status().
- """
- return "%s@%d@%s" % (
- self._id('Job', cim_job), int(retrieve_data), str(method_data))
-
def _init_id(self, cim_init):
"""
Retrieve Initiator ID from CIM_StorageHardwareID
@@ -481,225 +423,42 @@ def _id(self, class_type, cim_xxx):
else:
return md5(id_str)

- @staticmethod
- def _parse_job_id(job_id):
- """
- job_id is assembled by a md5 string, retrieve_data and method_data
- This method will split it and return
- (md5_str, retrieve_data, method_data)
- """
- tmp_list = job_id.split('@', 3)
- md5_str = tmp_list[0]
- retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
- method_data = None
- if len(tmp_list) == 3:
- retrieve_data = int(tmp_list[1])
- method_data = tmp_list[2]
- return (md5_str, retrieve_data, method_data)
-
- @staticmethod
- def _get_vol_other_id_info(cv):
- other_id = None
-
- if 'OtherIdentifyingInfo' in cv \
- and cv["OtherIdentifyingInfo"] is not None \
- and len(cv["OtherIdentifyingInfo"]) > 0:
-
- other_id = cv["OtherIdentifyingInfo"]
-
- if isinstance(other_id, list):
- other_id = other_id[0]
-
- # This is not what we are looking for if the field has this value
- if other_id is not None and other_id == "VPD83Type3":
- other_id = None
-
- return other_id
-
- def _cim_vol_pros(self):
- """
- Return the PropertyList required for creating new LSM Volume.
- """
- props = ['ElementName', 'NameFormat',
- 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
- 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
- 'OtherNameFormat', 'OtherNameNamespace']
- cim_vol_pros = self._property_list_of_id("Volume", props)
- return cim_vol_pros
-
- def _new_vol(self, cv, pool_id=None, sys_id=None):
- """
- Takes a CIMInstance that represents a volume and returns a lsm Volume
- """
-
- # This is optional (User friendly name)
- if 'ElementName' in cv:
- user_name = cv["ElementName"]
- else:
- #Better fallback value?
- user_name = cv['DeviceID']
-
- vpd_83 = Smis._vpd83_in_cv_name(cv)
- if vpd_83 is None:
- vpd_83 = Smis._vpd83_in_cv_otherinfo(cv)
- if vpd_83 is None:
- vpd_83 = Smis._vpd83_in_cv_otherinfo_netapp(cv)
-
- if vpd_83 and re.match('^[a-fA-F0-9]{32}$', vpd_83) and \
- vpd_83[0] == '6':
- vpd_83 = vpd_83.lower()
- else:
- vpd_83 = ''
-
- #This is a fairly expensive operation, so it's in our best interest
- #to not call this very often.
- if pool_id is None:
- #Go an retrieve the pool id
- pool_id = smis_pool.pool_id_of_cim_vol(self._c, cv.path)
-
- if sys_id is None:
- sys_id = cv['SystemName']
-
- admin_state = Volume.ADMIN_STATE_ENABLED
-
- return Volume(self._vol_id(cv), user_name, vpd_83, cv["BlockSize"],
- cv["NumberOfBlocks"], admin_state, sys_id, pool_id)
-
- @staticmethod
- def _vpd83_in_cv_name(cv):
- """
- We require NAA Type 3 VPD83 address:
- Only this is allowed when storing VPD83 in cv["Name"]:
- * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
- """
- if not ('NameFormat' in cv and
- 'NameNamespace' in cv and
- 'Name' in cv):
- return None
- nf = cv['NameFormat']
- nn = cv['NameNamespace']
- name = cv['Name']
- if not (nf and nn and name):
- return None
-
- if nf == dmtf.VOL_NAME_FORMAT_NNA and \
- nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE3:
- return name
-
- @staticmethod
- def _vpd83_in_cv_otherinfo(cv):
- """
- IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
- Will return the vpd_83 value if found
- """
- if not ("IdentifyingDescriptions" in cv and
- "OtherIdentifyingInfo" in cv):
- return None
-
- id_des = cv["IdentifyingDescriptions"]
- other_info = cv["OtherIdentifyingInfo"]
- if not (isinstance(cv["IdentifyingDescriptions"], list) and
- isinstance(cv["OtherIdentifyingInfo"], list)):
- return None
-
- index = 0
- len_id_des = len(id_des)
- len_other_info = len(other_info)
- while index < min(len_id_des, len_other_info):
- if dmtf.VOL_OTHER_INFO_NAA_VPD83_TYPE3H == id_des[index]:
- return other_info[index]
- index += 1
- return None
-
- @staticmethod
- def _vpd83_in_cv_otherinfo_netapp(cv):
- # workaround for NetApp, they use OtherNameNamespace and
- # OtherNameFormat.
- if 'OtherNameFormat' in cv and \
- cv['OtherNameFormat'] == 'NAA' and \
- 'OtherNameNamespace' in cv and \
- cv['OtherNameNamespace'] == 'VPD83Type3' and \
- 'OtherIdentifyingInfo' in cv and \
- isinstance(cv["OtherIdentifyingInfo"], list) and \
- len(cv['OtherIdentifyingInfo']) == 1:
- return cv['OtherIdentifyingInfo'][0]
-
def _new_vol_from_name(self, out):
"""
Given a volume by CIMInstanceName, return a lsm Volume object
"""
- instance = None
+ cim_vol = None
+ cim_vol_pros = smis_vol.cim_vol_pros()

if 'TheElement' in out:
- instance = self._c.GetInstance(out['TheElement'],
- LocalOnly=False)
+ cim_vol = self._c.GetInstance(
+ out['TheElement'],
+ PropertyList=cim_vol_pros)
elif 'TargetElement' in out:
- instance = self._c.GetInstance(out['TargetElement'],
- LocalOnly=False)
-
- return self._new_vol(instance)
-
- def _cim_spc_pros(self):
- """
- Return a list of properties required to build new AccessGroup.
- """
- cim_spc_pros = ['DeviceID']
- cim_spc_pros.extend(self._property_list_of_id('SystemChild'))
- cim_spc_pros.extend(['ElementName', 'StorageID'])
- cim_spc_pros.extend(['EMCAdapterRole']) # EMC specific, used to
- # filter out the mapping SPC.
- return cim_spc_pros
-
- def _cim_inits_to_lsm(self, cim_inits):
- """
- Retrieve AccessGroup.init_ids and AccessGroup.init_type from
- a list of CIM_StorageHardwareID.
- """
- init_ids = []
- init_type = AccessGroup.INIT_TYPE_UNKNOWN
- init_types = []
- for cim_init in cim_inits:
- init_type = _dmtf_init_type_to_lsm(cim_init)
- if init_type == AccessGroup.INIT_TYPE_WWPN:
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- elif init_type == AccessGroup.INIT_TYPE_ISCSI_IQN:
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- # Skip if not a iscsi initiator IQN or WWPN.
- continue
-
- init_type_dict = {}
- for cur_init_type in init_types:
- init_type_dict[cur_init_type] = 1
-
- if len(init_type_dict) == 1:
- init_type = init_types[0]
- elif len(init_type_dict) == 2:
- init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
- return (init_ids, init_type)
-
- def _cim_spc_to_lsm(self, cim_spc, system_id=None):
- if system_id is None:
- system_id = self._sys_id_child(cim_spc)
- ag_id = md5(cim_spc['DeviceID'])
- ag_name = cim_spc['ElementName']
- ag_init_ids = []
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- sys_id = self._sys_id_child(cim_spc)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, sys_id)
+ cim_vol = self._c.GetInstance(
+ out['TargetElement'],
+ PropertyList=cim_vol_pros)
+
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+
+ return smis_vol.cim_vol_to_lsm_vol(self._c, cim_vol, pool_id, sys_id)

def _new_vol_from_job(self, job):
"""
Given a concrete job instance, return referenced volume as lsm volume
"""
- for a in self._c.Associators(job.path,
- AssocClass='CIM_AffectedJobElement',
- ResultClass='CIM_StorageVolume'):
- return self._new_vol(self._c.GetInstance(a.path, LocalOnly=False))
+ cim_vol_pros = smis_vol.cim_vol_pros()
+ cim_vols = self._c.Associators(
+ job.path,
+ AssocClass='CIM_AffectedJobElement',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=cim_vol_pros)
+ for cim_vol in cim_vols:
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ return smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id)
return None

@handle_cim_errors
@@ -726,7 +485,7 @@ def volumes(self, search_key=None, search_value=None, flags=0):
rc = []
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()
for cim_sys in cim_syss:
sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
pool_pros = smis_pool.cim_pool_id_pros()
@@ -734,20 +493,12 @@ def volumes(self, search_key=None, search_value=None, flags=0):
self._c, cim_sys.path, pool_pros)
for cim_pool in cim_pools:
pool_id = smis_pool.pool_id_of_cim_pool(cim_pool)
- cim_vols = self._c.Associators(
- cim_pool.path,
- AssocClass='CIM_AllocatedFromStoragePool',
- ResultClass='CIM_StorageVolume',
- PropertyList=cim_vol_pros)
+ cim_vols = smis_vol.cim_vol_of_cim_pool_path(
+ self._c, cim_pool.path, cim_vol_pros)
for cim_vol in cim_vols:
- # Exclude those volumes which are reserved for system
- if 'Usage' in cim_vol:
- if cim_vol['Usage'] != 3:
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
- else:
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id))
return search_property(rc, search_key, search_value)

@handle_cim_errors
@@ -789,51 +540,6 @@ def systems(self, flags=0):

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

- def _volume_exists(self, name):
- """
- Try to minimize time to search.
- :param name: Volume ElementName
- :return: True if volume exists with 'name', else False
- """
- all_cim_vols = self._c.EnumerateInstances(
- 'CIM_StorageVolume', PropertyList=['ElementName'])
- for exist_cim_vol in all_cim_vols:
- if name == exist_cim_vol['ElementName']:
- return True
- return False
-
- def _check_for_dupe_vol(self, volume_name, original_exception):
- """
- Throw original exception or NAME_CONFLICT if volume name found
- :param volume_name: Volume to check for
- :original_exception Info grabbed from sys.exec_info
- :return:
- if original_exception == None, will not raise any error if not
- NAME_CONFLICT, just return None.
- """
- report_original = True
-
- # Check to see if we already have a volume with this name. If we
- # do we will assume that this is the cause of it. We will hide
- # any errors that happen during this check and just report the
- # original error if we can't determine if we have a duplicate
- # name.
-
- try:
- report_original = not self._volume_exists(volume_name)
- except Exception:
- # Don't report anything here on a failing
- pass
-
- if report_original:
- if original_exception is None:
- return
- raise original_exception[1], None, original_exception[2]
- else:
- raise LsmError(ErrorNumber.NAME_CONFLICT,
- "Volume with name '%s' already exists!" %
- volume_name)
-
@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
flags=0):
@@ -870,8 +576,8 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
"requested provisioning type")

# Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(pool.system_id)
+
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
self._c, pool)

@@ -880,15 +586,16 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
'InPool': cim_pool_path,
'Size': pywbem.Uint64(size_bytes)}

- try:
- return self._pi("volume_create",
- SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
- volume_name,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
- except CIMError:
- self._check_for_dupe_vol(volume_name, sys.exc_info())
+ error_handler = Smis._JOB_ERROR_HANDLER[
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
+
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params,
+ out_handler=self._new_vol_from_name,
+ error_handler=error_handler,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
+ method_data=volume_name)

def _poll(self, msg, job):
if job:
@@ -907,18 +614,13 @@ def _poll(self, msg, job):

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

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

- job_id = self._pi("_detach",
- SmisCommon.JOB_RETRIEVE_NONE,
- None,
- *(self._c.InvokeMethod(
- 'ModifySynchronization', scs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifySynchronization', cim_scs.path, in_params)[0]

self._poll("ModifySynchronization, detach", job_id)

@@ -926,17 +628,14 @@ def _detach(self, vol, sync):
if self._c.is_netappe():
return self._detach_netapp_e(vol, sync)

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

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

- job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE, None,
- *(self._c.InvokeMethod(
- 'ModifyReplicaSynchronization', rs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifyReplicaSynchronization', cim_rs.path, in_params)[0]

self._poll("ModifyReplicaSynchronization, detach", job_id)

@@ -950,15 +649,14 @@ def _cim_name_match(a, b):
else:
return False

- def _deal_volume_associations_netappe(self, vol, lun):
+ def _deal_volume_associations_netappe(self, vol, cim_vol_path):
"""
Check a volume to see if it has any associations with other
volumes.
"""
rc = False
- lun_path = lun.path

- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')

if len(ss):
@@ -966,31 +664,29 @@ def _deal_volume_associations_netappe(self, vol, lun):
if 'SyncedElement' in s:
item = s['SyncedElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)
rc = True

if 'SystemElement' in s:
item = s['SystemElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)
rc = True

return rc

- def _deal_volume_associations(self, vol, lun):
+ def _deal_volume_associations(self, vol, cim_vol_path):
"""
Check a volume to see if it has any associations with other
volumes and deal with them.
"""
if self._c.is_netappe():
- return self._deal_volume_associations_netappe(vol, lun)
-
- lun_path = lun.path
+ return self._deal_volume_associations_netappe(vol, cim_vol_path)

try:
- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')
except pywbem.CIMError as e:
if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
@@ -1021,38 +717,35 @@ def _deal_volume_associations(self, vol, lun):
if 'SyncedElement' in s:
item = s['SyncedElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)

if 'SystemElement' in s:
item = s['SystemElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)

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

#If we actually have an association to delete, the volume will be
#deleted with the association, no need to call ReturnToStoragePool
- if not self._deal_volume_associations(volume, lun):
- in_params = {'TheElement': lun.path}
+ if not self._deal_volume_associations(volume, cim_vol_path):
+ in_params = {'TheElement': cim_vol_path}

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

#Loop to check to see if volume is actually gone yet!
try:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
- while lun is not None:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_vol = self._c.GetInstance(cim_vol_path,PropertyList=[])
+ while cim_vol is not None:
+ cim_vol = self._c.GetInstance(cim_vol_path,PropertyList=[])
time.sleep(0.125)
- except LsmError as e:
+ except (LsmError, CIMError) as e:
pass

@handle_cim_errors
@@ -1060,37 +753,34 @@ def volume_delete(self, volume, flags=0):
"""
Delete a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

- self._deal_volume_associations(volume, lun)
+ self._deal_volume_associations(volume, cim_vol_path)

- in_params = {'TheElement': lun.path}
+ in_params = {'TheElement': cim_vol_path}

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

@handle_cim_errors
def volume_resize(self, volume, new_size_bytes, flags=0):
"""
Re-size a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

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

- return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params, retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

def _get_supported_sync_and_mode(self, system_id, rep_type):
"""
@@ -1100,12 +790,11 @@ def _get_supported_sync_and_mode(self, system_id, rep_type):
"""
rc = [None, None]

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

- if rs:
+ if cim_rs:
rs_cap = self._c.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_ReplicationServiceCapabilities')[0]

@@ -1152,13 +841,12 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
or rep_type == Volume.REPLICATE_MIRROR_SYNC:
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")

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

# Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
# ElementName, we have to do pre-check here.
- if self._volume_exists(name):
+ if smis_vol.volume_name_exists(self._c, name):
raise LsmError(ErrorNumber.NAME_CONFLICT,
"Volume with name '%s' already exists!" % name)

@@ -1166,9 +854,10 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
if pool is not None:
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)

- lun = self._get_cim_instance_by_id('Volume', volume_src.id)
+ src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
+ self._c, volume_src)

- if rs:
+ if cim_rs:
method = 'CreateElementReplica'

sync, mode = self._get_supported_sync_and_mode(
@@ -1177,7 +866,7 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
in_params = {'ElementName': name,
'SyncType': sync,
#'Mode': mode,
- 'SourceElement': lun.path,
+ 'SourceElement': src_cim_vol_path,
'WaitForCopyState': dmtf.COPY_STATE_SYNC}

else:
@@ -1186,9 +875,8 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
method = 'CreateReplica'

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

ct = Volume.REPLICATE_CLONE
if rep_type == Volume.REPLICATE_CLONE:
@@ -1202,21 +890,20 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):

in_params = {'ElementName': name,
'CopyType': ct,
- 'SourceElement': lun.path}
- if rs:
+ 'SourceElement': src_cim_vol_path}
+ if cim_rs:

if cim_pool_path is not None:
in_params['TargetPool'] = cim_pool_path

- return self._pi("volume_replicate",
- SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(method,
- rs.path, **in_params)))
+ return self._c.invoke_method(
+ method, cim_rs.path, in_params,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")

- def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
+ def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
vol_id):
rc = SmisCommon.SNIA_INVOKE_FAILED
out = None
@@ -1228,12 +915,12 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,

cim_dev_mg_path = None
try:
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
except CIMError as ce:
if ce[0] == pywbem.CIM_ERR_FAILED:
cim_dev_mg_path = self._check_exist_cim_dev_mg(
- name, cim_gmm_path, cim_vol_path, vol_id)
+ name, cim_gmms_path, cim_vol_path, vol_id)
if cim_dev_mg_path is None:
raise
else:
@@ -1245,7 +932,7 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,

return cim_dev_mg_path

- def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
+ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
init_type):
"""
Create CIM_TargetMaskingGroup
@@ -1276,7 +963,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,

cim_tgt_mg_path = None
try:
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
except CIMError as ce:
if ce[0] == pywbem.CIM_ERR_FAILED:
@@ -1293,7 +980,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,

return cim_tgt_mg_path

- def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
+ def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
cim_tgt_mg_path, cim_dev_mg_path, name):
in_params = {
'ElementName': name,
@@ -1302,7 +989,7 @@ def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
'DeviceMaskingGroup': cim_dev_mg_path,
}

- (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmms_path,
**in_params)

return self._wait_invoke(
@@ -1324,10 +1011,11 @@ def _volume_mask_group(self, access_group, volume, flags=0):
"""
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

- cim_init_mg = self._cim_init_mg_of_id(access_group.id,
- raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path)
+ cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
@@ -1342,42 +1030,39 @@ def _volume_mask_group(self, access_group, volume, flags=0):
"access group init_type: %d" %
access_group.init_type)

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'],
- raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

if len(cim_spcs_path) == 0:
# We have to create the SPC and dev_mg now.
cim_tgt_mg_path = self._cim_tgt_mg_path_create(
- cim_sys.path, cim_gmm_path, access_group.name,
+ cim_sys.path, cim_gmms.path, access_group.name,
access_group.init_type)
cim_dev_mg_path = self._cim_dev_mg_path_create(
- cim_gmm_path, access_group.name, cim_vol.path, volume.id)
+ cim_gmms.path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
- cim_gmm_path, cim_init_mg.path, cim_tgt_mg_path,
+ cim_gmms.path, cim_init_mg_path, cim_tgt_mg_path,
cim_dev_mg_path, access_group.name)
else:
# CIM_InitiatorMaskingGroup might have multiple SPC when having
# many tgt_mg. It's seldom use, but possible.
for cim_spc_path in cim_spcs_path:
# Check whether already masked
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
for cur_cim_vol in cim_vols:
- if self._vol_id(cur_cim_vol) == volume.id:
+ if smis_vol.vol_id_of_cim_vol(cur_cim_vol) == volume.id:
# Masked.
return None

@@ -1388,11 +1073,11 @@ def _volume_mask_group(self, access_group, volume, flags=0):
ResultClass='CIM_DeviceMaskingGroup')[0]
in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None

@@ -1413,30 +1098,27 @@ def volume_mask(self, access_group, volume, flags=0):
return self._volume_mask_old(access_group, volume, flags)

def _volume_mask_old(self, access_group, volume, flags):
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_inits = self._cim_init_of_spc(cim_spc.path)
+ cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc_path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
access_group.id +
"will not do volume_mask()")

- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_css_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

in_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path],
+ 'ProtocolControllers': [cim_spc_path],
'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}

(rc, out) = self._c.InvokeMethod(
'ExposePaths',
- cim_css_path, **in_params)
+ cim_ccs.path, **in_params)
self._wait_invoke(rc, out)
return None

@@ -1447,11 +1129,10 @@ def _volume_unmask_group(self, access_group, volume):
If SupportedDeviceGroupFeatures does not allow empty
DeviceMaskingGroup in SPC, we remove SPC and DeviceMaskingGroup.
"""
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)

- cim_gmm_cap = self._c.Associators(
+ cim_gmms_cap = self._c.Associators(
cim_sys.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_GroupMaskingMappingCapabilities',
@@ -1462,14 +1143,14 @@ def _volume_unmask_group(self, access_group, volume):
flag_empty_dev_in_spc = False

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

if flag_empty_dev_in_spc is False:
if ((dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedSynchronousActions']) and
+ cim_gmms_cap['SupportedSynchronousActions']) and
(dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedAsynchronousActions'])):
+ cim_gmms_cap['SupportedAsynchronousActions'])):
raise LsmError(
ErrorNumber.NO_SUPPORT,
"volume_unmask() not supported. It requires one of these "
@@ -1477,11 +1158,10 @@ def _volume_unmask_group(self, access_group, volume):
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(volume.system_id)

cim_spcs_path = self._c.AssociatorNames(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController')
if len(cim_spcs_path) == 0:
@@ -1524,16 +1204,16 @@ def _volume_unmask_group(self, access_group, volume):
}
(rc, out) = self._c.InvokeMethod(
'DeleteMaskingView',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)

in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)

return None
@@ -1552,27 +1232,24 @@ def volume_unmask(self, access_group, volume, flags=0):
return self._volume_unmask_old(access_group, volume)

def _volume_unmask_old(self, access_group, volume):
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id,
- property_list=['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

hide_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}

- (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs_path,
+ (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)
self._wait_invoke(rc, out)

return None

def _is_access_group(self, cim_spc):
- if self._c.is_netappe:
+ if self._c.is_netappe():
return True

rc = True
@@ -1588,55 +1265,24 @@ def _is_access_group(self, cim_spc):
rc = False
return rc

- def _cim_spc_of_id(self, access_group_id, property_list=None,
- raise_error=False):
- """
- Return CIMInstance of CIM_SCSIProtocolController
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- if property_list is None:
- property_list = ['DeviceID']
- else:
- property_list = merge_list(property_list, ['DeviceID'])
-
- cim_spcs = self._c.EnumerateInstances(
- 'CIM_SCSIProtocolController', PropertyList=property_list)
-
- for cim_spc in cim_spcs:
- if md5(cim_spc['DeviceID']) == access_group_id:
- return cim_spc
-
- if raise_error is True:
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
- def _cim_spc_of(self, cim_sys_path, property_list=None):
+ def _cim_spc_of(self, system_id, property_list=None):
"""
Return a list of CIM_SCSIProtocolController.
Following SNIA SMIS 'Masking and Mapping Profile':
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_ControllerConfigurationService
|
| CIM_ConcreteDependency
v
CIM_SCSIProtocolController
"""
- cim_ccss_path = []
+ cim_ccs = None
rc_cim_spcs = []

if property_list is None:
property_list = []

try:
- cim_ccss_path = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(system_id, raise_error=False)
except CIMError as ce:
error_code = tuple(ce)[0]
if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
@@ -1644,19 +1290,12 @@ def _cim_spc_of(self, cim_sys_path, property_list=None):
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported ' +
'by this array')
- cim_ccs_path = None
- if len(cim_ccss_path) == 1:
- cim_ccs_path = cim_ccss_path[0]
- elif len(cim_ccss_path) == 0:
+ if cim_ccs is None:
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Got %d instance of " % len(cim_ccss_path) +
- "ControllerConfigurationService from %s" %
- cim_sys_path + " in _cim_spc_of()")
+
cim_spcs = self._c.Associators(
- cim_ccs_path,
+ cim_ccs.path,
AssocClass='CIM_ConcreteDependency',
ResultClass='CIM_SCSIProtocolController',
PropertyList=property_list)
@@ -1665,82 +1304,11 @@ def _cim_spc_of(self, cim_sys_path, property_list=None):
rc_cim_spcs.append(cim_spc)
return rc_cim_spcs

- def _cim_init_of_spc(self, cim_spc_path, property_list=None):
- """
- Take CIM_SCSIProtocolController and return a list of
- CIM_StorageHardwareID, both are CIMInstance.
- Two ways to get StorageHardwareID from SCSIProtocolController:
- * Method A (defined in SNIA SMIS 1.6):
- CIM_SCSIProtocolController
- |
- | CIM_AssociatedPrivilege
- v
- CIM_StorageHardwareID
-
- * Method B (defined in SNIA SMIS 1.3, 1.4, 1.5 and 1.6):
- CIM_SCSIProtocolController
- |
- | CIM_AuthorizedTarget
- v
- CIM_AuthorizedPrivilege
- |
- | CIM_AuthorizedSubject
- v
- CIM_StorageHardwareID
-
- Method A defined in SNIA SMIS 1.6 deprecated the Method B and Method A
- saved 1 query which provide better performance.
- Hence we try method A.
- Maybe someday, we will stop trying after knowing array's supported
- SMIS version.
- """
- cim_inits = []
- if property_list is None:
- property_list = []
-
- if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_6,
- raise_error=False):
- return self._c.Associators(
- cim_spc_path,
- AssocClass='CIM_AssociatedPrivilege',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
- else:
- cim_aps_path = self._c.AssociatorNames(
- cim_spc_path,
- AssocClass='CIM_AuthorizedTarget',
- ResultClass='CIM_AuthorizedPrivilege')
- for cim_ap_path in cim_aps_path:
- cim_inits.extend(self._c.Associators(
- cim_ap_path,
- AssocClass='CIM_AuthorizedSubject',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list))
- return cim_inits
-
- def _cim_init_of_init_mg(self, cim_init_mg_path, property_list=None):
- """
- Use this association:
- CIM_InitiatorMaskingGroup
- |
- | CIM_MemberOfCollection
- v
- CIM_StorageHardwareID
- """
- if property_list is None:
- property_list = []
- return self._c.Associators(
- cim_init_mg_path,
- AssocClass='CIM_MemberOfCollection',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
-
@handle_cim_errors
def volumes_accessible_by_access_group(self, access_group, flags=0):
mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vols = []
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
@@ -1750,11 +1318,11 @@ def volumes_accessible_by_access_group(self, access_group, flags=0):
mask_type = smis_cap.MASK_TYPE_MASK

if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

@@ -1766,21 +1334,27 @@ def volumes_accessible_by_access_group(self, access_group, flags=0):
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros))
else:
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)
cim_vols = self._c.Associators(
- cim_spc.path,
+ cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
-
- return [self._new_vol(v) for v in cim_vols]
+ rc = []
+ for cim_vol in cim_vols:
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id))
+ return rc

@handle_cim_errors
def access_groups_granted_to_volume(self, volume, flags=0):
rc = []
mask_type = smis_cap.mask_type(self._c, raise_error=True)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
@@ -1792,64 +1366,39 @@ def access_groups_granted_to_volume(self, volume, flags=0):
if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_spc_pros = []
else:
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()

cim_spcs = self._c.Associators(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController',
PropertyList=cim_spc_pros)

if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
for cim_spc in cim_spcs:
cim_init_mgs = self._c.Associators(
cim_spc.path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, volume.system_id)
- for x in cim_init_mgs))
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, x, volume.system_id)
+ for x in cim_init_mgs))
else:
for cim_spc in cim_spcs:
if self._is_access_group(cim_spc):
- rc.extend(
- [self._cim_spc_to_lsm(cim_spc, volume.system_id)])
+ rc.append(
+ smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, volume.system_id))

return rc

- def _cim_init_mg_of_id(self, access_group_id, property_list=None,
- raise_error=False):
- """
- Return CIMInstance of CIM_InitiatorMaskingGroup
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- if property_list is None:
- property_list = ['InstanceID']
- else:
- property_list = merge_list(property_list, ['InstanceID'])
-
- cim_init_mgs = self._c.EnumerateInstances(
- 'CIM_InitiatorMaskingGroup', PropertyList=property_list)
-
- for cim_init_mg in cim_init_mgs:
- if md5(cim_init_mg['InstanceID']) == access_group_id:
- return cim_init_mg
-
- if raise_error is True:
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
- def _cim_init_mg_of(self, cim_sys_path, property_list=None):
+ def _cim_init_mg_of(self, system_id, property_list=None):
"""
- There is no CIM_ComputerSystem association to
- CIM_InitiatorMaskingGroup, we use this association:
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
+ We use this association to get all CIM_InitiatorMaskingGroup:
CIM_GroupMaskingMappingService
|
| CIM_ServiceAffectsElement
@@ -1859,11 +1408,10 @@ def _cim_init_mg_of(self, cim_sys_path, property_list=None):
if property_list is None:
property_list = []

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system_id)

return self._c.Associators(
- cim_gmm_path,
+ cim_gmms.path,
AssocClass='CIM_ServiceAffectsElement',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)
@@ -1876,7 +1424,7 @@ def access_groups(self, search_key=None, search_value=None, flags=0):
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)

- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
for cim_sys in cim_syss:
if cim_sys.path.classname == 'Clar_StorageSystem':
# Workaround for EMC VNX/CX.
@@ -1886,16 +1434,19 @@ def access_groups(self, search_key=None, search_value=None, flags=0):

system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
- cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
- for x in cim_init_mgs))
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mgs = self._cim_init_mg_of(
+ system_id, cim_init_mg_pros)
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(self._c, x, system_id)
+ for x in cim_init_mgs))
elif mask_type == smis_cap.MASK_TYPE_MASK:
- cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
+ cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
rc.extend(
- list(self._cim_spc_to_lsm(cim_spc, system_id)
- for cim_spc in cim_spcs))
+ list(
+ smis_ag.cim_spc_to_lsm_ag(self._c, cim_spc, system_id)
+ for cim_spc in cim_spcs))
else:
raise LsmError(ErrorNumber.PLUGIN_BUG,
"_get_cim_spc_by_id(): Got invalid mask_type: "
@@ -1903,7 +1454,7 @@ def access_groups(self, search_key=None, search_value=None, flags=0):

return search_property(rc, search_key, search_value)

- def _cim_init_path_check_or_create(self, cim_sys_path, init_id, init_type):
+ def _cim_init_path_check_or_create(self, system_id, init_id, init_type):
"""
Check whether CIM_StorageHardwareID exists, if not, create new one.
"""
@@ -1920,23 +1471,21 @@ def _cim_init_path_check_or_create(self, cim_sys_path, init_id, init_type):
"SMI-S Plugin does not support init_type %d" %
init_type)

- return self._cim_init_path_create(
- cim_sys_path, init_id, dmtf_id_type)
+ return self._cim_init_path_create(system_id, init_id, dmtf_id_type)

- def _cim_init_path_create(self, cim_sys_path, init_id, dmtf_id_type):
+ def _cim_init_path_create(self, system_id, init_id, dmtf_id_type):
"""
Create a CIM_StorageHardwareID.
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_StorageHardwareIDManagementService')
+ cim_hwms = self._c.cim_hwms_of_sys_id(system_id)

in_params = {'StorageID': init_id,
'IDType': pywbem.Uint16(dmtf_id_type)}

(rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- cim_hw_srv_path, **in_params)
+ cim_hwms.path, **in_params)
# CreateStorageHardwareID does not allow ASYNC
return self._wait_invoke(
rc, out, out_key='HardwareID',
@@ -1951,12 +1500,11 @@ def _ag_init_add_group(self, access_group, init_id, init_type):
"new initiator which is not supported by LSM yet. "
"Please do it via EMC vendor specific tools.")

- cim_init_mg = self._cim_init_mg_of_id(access_group.id)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)

# Check whether already added.
for exist_cim_init in exist_cim_inits:
@@ -1964,27 +1512,26 @@ def _ag_init_add_group(self, access_group, init_id, init_type):
return copy.deepcopy(access_group)

cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ access_group.system_id, init_id, init_type)

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)

new_cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
expect_class='CIM_InitiatorMaskingGroup')
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
new_cim_init_mg = self._c.GetInstance(
new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
LocalOnly=False)
- return self._cim_init_mg_to_lsm(
- new_cim_init_mg, access_group.system_id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, new_cim_init_mg, access_group.system_id)

@handle_cim_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
@@ -2009,11 +1556,11 @@ def _ag_init_add_old(self, access_group, init_id, init_type):
"Please do it via EMC vendor specific tools. "
"EMC VNX does not support adding iSCSI IQN neither")

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)

- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_spc_path(
+ self._c, cim_spc_path)

for exist_cim_init in exist_cim_inits:
if self._init_id(exist_cim_init) == init_id:
@@ -2022,39 +1569,35 @@ def _ag_init_add_old(self, access_group, init_id, init_type):
# Check to see if we have this initiator already, if not we
# create it and then add to the view.

- self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)
+ self._cim_init_path_check_or_create(
+ access_group.system_id, init_id, init_type)

- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

in_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}

(rc, out) = self._c.InvokeMethod('ExposePaths',
- cim_ccs_path, **in_params)
+ cim_ccs.path, **in_params)
cim_spc_path = self._wait_invoke(
rc, out, out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')

- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
cim_spc = self._c.GetInstance(
cim_spc_path, PropertyList=cim_spc_pros, LocalOnly=False)
- return self._cim_spc_to_lsm(cim_spc, access_group.system_id)
+ return smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, access_group.system_id)

def _ag_init_del_group(self, access_group, init_id):
"""
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True, property_list=cim_init_mg_pros)
-
- cim_init_pros = self._property_list_of_id('Initiator')
- cur_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, property_list=cim_init_pros)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
+ cur_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)

cim_init = None
for cur_cim_init in cur_cim_inits:
@@ -2072,21 +1615,25 @@ def _ag_init_del_group(self, access_group, init_id):
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

# RemoveMembers from InitiatorMaskingGroup
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init.path],
}

(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
- return self._cim_init_mg_to_lsm(
- cim_init_mg, access_group.system_id)
+
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mg = self._c.GetInstance(
+ cim_init_mg_path, PropertyList=cim_init_mg_pros)
+
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, cim_init_mg, access_group.system_id)

@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, init_type,
@@ -2107,17 +1654,14 @@ def access_group_initiator_delete(self, access_group, init_id, init_type,
return self._ag_init_del_old(access_group, init_id)

def _ag_init_del_old(self, access_group, init_id):
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

hide_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
(rc, out) = self._c.InvokeMethod(
- 'HidePaths', cim_ccs_path, **hide_params)
+ 'HidePaths', cim_ccs.path, **hide_params)

self._wait_invoke(rc, out)
return None
@@ -2127,8 +1671,7 @@ def job_free(self, job_id, flags=0):
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id,
- ['DeleteOnCompletion'])
+ cim_job = self._c.cim_job_of_job_id(job_id, ['DeleteOnCompletion'])

# See if we should delete the job
if not cim_job['DeleteOnCompletion']:
@@ -2509,18 +2052,6 @@ def target_ports(self, search_key=None, search_value=None, flags=0):

return search_property(rc, search_key, search_value)

- def _cim_init_mg_pros(self):
- return ['ElementName', 'InstanceID']
-
- def _cim_init_mg_to_lsm(self, cim_init_mg, system_id):
- ag_name = cim_init_mg['ElementName']
- ag_id = md5(cim_init_mg['InstanceID'])
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
-
def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
flag_out_array=False,):
"""
@@ -2615,7 +2146,7 @@ def _check_exist_cim_tgt_mg(self, name):

return None

- def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
+ def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
vol_id):
"""
This is buggy check, but it works on EMC VMAX which is only supported
@@ -2632,14 +2163,14 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
break
if cim_dev_mg:
# Check whether cim_vol included.
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_dev_mg.path,
AssocClass='CIM_OrderedMemberOfCollection',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
for cim_vol in cim_vols:
- if self._vol_id(cim_vol) == vol_id:
+ if smis_vol.vol_id_of_cim_vol(cim_vol) == vol_id:
return cim_dev_mg.path

# We should add this volume to found DeviceMaskingGroup
@@ -2649,7 +2180,7 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms_path, **in_params)
self._wait_invoke(rc, out)
return cim_dev_mg.path

@@ -2705,21 +2236,20 @@ def access_group_create(self, name, init_id, init_type, system,
"iSCSI IQN access group")

cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ system.id, init_id, init_type)

# Create CIM_InitiatorMaskingGroup
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system.id)

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

- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()

try:
(rc, out) = self._c.InvokeMethod(
- 'CreateGroup', cim_gmm_path, **in_params)
+ 'CreateGroup', cim_gmms.path, **in_params)

cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
@@ -2739,8 +2269,8 @@ def access_group_create(self, name, init_id, init_type, system,
if len(exist_cim_init_mgs) != 0:
for exist_cim_init_mg in exist_cim_init_mgs:
if exist_cim_init_mg['ElementName'] == name:
- return self._cim_init_mg_to_lsm(
- exist_cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, exist_cim_init_mg, system.id)

# Name does not match.
raise LsmError(ErrorNumber.EXISTS_INITIATOR,
@@ -2753,7 +2283,7 @@ def access_group_create(self, name, init_id, init_type, system,
# Since 1) already checked whether any group containing
# requested init_id, now, it's surly a conflict.
exist_cim_init_mgs = self._cim_init_mg_of(
- cim_sys.path, property_list=['ElementName'])
+ system.id, property_list=['ElementName'])
for exist_cim_init_mg in exist_cim_init_mgs:
if exist_cim_init_mg['ElementName'] == name:
raise LsmError(ErrorNumber.NAME_CONFLICT,
@@ -2764,7 +2294,7 @@ def access_group_create(self, name, init_id, init_type, system,

cim_init_mg = self._c.GetInstance(
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
- return self._cim_init_mg_to_lsm(cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(self._c, cim_init_mg, system.id)

@handle_cim_errors
def access_group_delete(self, access_group, flags=0):
@@ -2772,12 +2302,12 @@ def access_group_delete(self, access_group, flags=0):
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
raise_error=True)

- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

# Check whether still have volume masked.
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

@@ -2790,17 +2320,14 @@ def access_group_delete(self, access_group, flags=0):
"Access Group %s has volume masked" %
access_group.id)

- cim_gmm_path = self._c.AssociatorNames(
- cim_init_mg.path,
- AssocClass='CIM_ServiceAffectsElement',
- ResultClass='CIM_GroupMaskingMappingService')[0]
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Force': True,
}

- (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmms.path,
**in_params)

self._wait_invoke(rc, out)
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
new file mode 100644
index 0000000..3c125ef
--- /dev/null
+++ b/plugin/smispy/smis_ag.py
@@ -0,0 +1,195 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author: Gris Ge <***@redhat.com>
+
+from pywbem import CIMError, CIM_ERR_NOT_FOUND
+
+from lsm import AccessGroup, md5, LsmError, ErrorNumber
+
+from smis_common import SmisCommon
+import dmtf
+from utils import cim_path_to_path_str, path_str_to_cim_path
+
+_CIM_INIT_PROS = ['StorageID', 'IDType']
+
+
+def _cim_inits_to_lsm_init_id_and_type(cim_inits):
+ """
+ Retrieve AccessGroup.init_ids and AccessGroup.init_type from
+ a list of CIM_StorageHardwareID.
+ """
+ init_ids = []
+ init_type = AccessGroup.INIT_TYPE_UNKNOWN
+ init_types = []
+ for cim_init in cim_inits:
+ if cim_init['IDType'] == dmtf.ID_TYPE_WWPN:
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_WWPN)
+ if cim_init['IDType'] == dmtf.ID_TYPE_ISCSI:
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_ISCSI_IQN)
+ # Skip if not a iscsi initiator IQN or WWPN.
+ continue
+
+ init_type_dict = {}
+ for cur_init_type in init_types:
+ init_type_dict[cur_init_type] = 1
+
+ if len(init_type_dict) == 1:
+ init_type = init_types[0]
+ elif len(init_type_dict) == 2:
+ init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
+ return (init_ids, init_type)
+
+
+def cim_spc_pros():
+ """
+ Return the property of CIM_SCSIProtocolController required to gernarate
+ lsm.AccessGroup
+ 'EMCAdapterRole' is for EMC VNX only.
+ """
+ return ['DeviceID', 'ElementName', 'StorageID', 'EMCAdapterRole',
+ 'SystemName']
+
+
+def cim_init_mg_pros():
+ """
+ Return the property of CIM_InitiatorMaskingGroup required to gernarate
+ lsm.AccessGroup
+ """
+ return ['ElementName', 'InstanceID']
+
+
+def cim_init_of_cim_spc_path(smis_common, cim_spc_path):
+ """
+ Return a list of CIM_StorageHardwareID associated to cim_spc.
+ Only contain ['StorageID', 'IDType'] property.
+ Two ways to get StorageHardwareID from SCSIProtocolController:
+ * Method A (defined in SNIA SMIS 1.6):
+ CIM_SCSIProtocolController
+ |
+ | CIM_AssociatedPrivilege
+ v
+ CIM_StorageHardwareID
+
+ * Method B (defined in SNIA SMIS 1.3, 1.4, 1.5 and 1.6):
+ CIM_SCSIProtocolController
+ |
+ | CIM_AuthorizedTarget
+ v
+ CIM_AuthorizedPrivilege
+ |
+ | CIM_AuthorizedSubject
+ v
+ CIM_StorageHardwareID
+ """
+ rc = []
+ if smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_6,
+ raise_error=False):
+ try:
+ rc = smis_common.Associators(
+ cim_spc_path,
+ AssocClass='CIM_AssociatedPrivilege',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+ except CIMError as ce:
+ if ce[0] == CIM_ERR_NOT_FOUND:
+ pass
+ else:
+ raise
+
+ if len(rc) == 0:
+ cim_aps_path = smis_common.AssociatorNames(
+ cim_spc_path,
+ AssocClass='CIM_AuthorizedTarget',
+ ResultClass='CIM_AuthorizedPrivilege')
+
+ for cim_ap_path in cim_aps_path:
+ rc.extend(smis_common.Associators(
+ cim_ap_path,
+ AssocClass='CIM_AuthorizedSubject',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS))
+ return rc
+
+
+def cim_spc_to_lsm_ag(smis_common, cim_spc, system_id):
+ ag_id = md5(cim_spc['DeviceID'])
+ ag_name = cim_spc['ElementName']
+ ag_init_ids = []
+ cim_inits = cim_init_of_cim_spc_path(smis_common, cim_spc.path)
+ (init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_spc.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+def cim_init_of_cim_init_mg_path(smis_common, cim_init_mg_path):
+ """
+ Use this association to get a list of CIM_StorageHardwareID:
+ CIM_InitiatorMaskingGroup
+ |
+ | CIM_MemberOfCollection
+ v
+ CIM_StorageHardwareID
+ Only contain ['StorageID', 'IDType'] property.
+ """
+ return smis_common.Associators(
+ cim_init_mg_path,
+ AssocClass='CIM_MemberOfCollection',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+
+
+def cim_init_mg_to_lsm_ag(smis_common, cim_init_mg, system_id):
+ ag_name = cim_init_mg['ElementName']
+ ag_id = md5(cim_init_mg['InstanceID'])
+ cim_inits = cim_init_of_cim_init_mg_path(smis_common, cim_init_mg.path)
+ (init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_init_mg.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+def lsm_ag_to_cim_spc_path(smis_common, lsm_ag):
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_SCSIProtocolController
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ if not lsm_ag.plugin_data:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.AccessGroup instance with empty plugin_data")
+ if smis_common.system_list and \
+ lsm_ag.system_id not in smis_common.system_list:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_ag.plugin_data)
+
+
+def lsm_ag_to_cim_init_mg_path(smis_common, lsm_ag):
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_InitiatorMaskingGroup
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ return lsm_ag_to_cim_spc_path(smis_common, lsm_ag)
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
index 1309056..1fee9a8 100644
--- a/plugin/smispy/smis_cap.py
+++ b/plugin/smispy/smis_cap.py
@@ -23,17 +23,19 @@
MASK_TYPE_GROUP = 2


-def _rs_supported_capabilities(smis_common, system, cap):
+def _rs_supported_capabilities(smis_common, system_id, cap):
"""
Interrogate the supported features of the replication service
"""
- rs = smis_common.get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, raise_error=False)
- if rs:
+ cim_rs = smis_common.cim_rs_of_sys_id(system_id, raise_error=False)
+ if cim_rs:
rs_cap = smis_common.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_ReplicationServiceCapabilities')[0]
+ ResultClass='CIM_ReplicationServiceCapabilities',
+ PropertyList=['SupportedReplicationTypes',
+ 'SupportedAsynchronousActions',
+ 'SupportedSynchronousActions'])[0]

s_rt = rs_cap['SupportedReplicationTypes']
async_actions = rs_cap['SupportedAsynchronousActions']
@@ -55,18 +57,17 @@ def _rs_supported_capabilities(smis_common, system, cap):
else:
# Try older storage configuration service

- rs = smis_common.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', system.id,
- raise_error=False)
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)

- if rs:
- rs_cap = smis_common.Associators(
- rs.path,
+ if cim_scs:
+ cim_sc_cap = smis_common.Associators(
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedCopyTypes'])[0]

- if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
- sct = rs_cap['SupportedCopyTypes']
+ if cim_sc_cap is not None and 'SupportedCopyTypes' in cim_sc_cap:
+ sct = cim_sc_cap['SupportedCopyTypes']

if sct and len(sct):
cap.set(Capabilities.VOLUME_REPLICATE)
@@ -78,7 +79,7 @@ def _rs_supported_capabilities(smis_common, system, cap):
cap.set(Capabilities.VOLUME_REPLICATE_COPY)


-def _bsp_cap_set(smis_common, cim_sys_path, cap):
+def _bsp_cap_set(smis_common, system_id, cap):
"""
Set capabilities for these methods:
volumes()
@@ -87,10 +88,9 @@ def _bsp_cap_set(smis_common, cim_sys_path, cap):
volume_delete()
"""
# CIM_StorageConfigurationService is optional.
- cim_scs_path = smis_common.get_cim_service_path(
- cim_sys_path, 'CIM_StorageConfigurationService')
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)

- if cim_scs_path is None:
+ if cim_scs is None:
return

# These methods are mandatory for CIM_StorageConfigurationService:
@@ -101,7 +101,7 @@ def _bsp_cap_set(smis_common, cim_sys_path, cap):
# Hence we check CIM_StorageConfigurationCapabilities
# which is mandatory if CIM_StorageConfigurationService is supported.
cim_scs_cap = smis_common.Associators(
- cim_scs_path,
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_StorageConfigurationCapabilities',
PropertyList=['SupportedAsynchronousActions',
@@ -353,7 +353,7 @@ def get(smis_common, cim_sys, system):
cap = Capabilities()

if smis_common.is_netappe():
- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)

#TODO We need to investigate why our interrogation code doesn't
#work.
@@ -362,7 +362,7 @@ def get(smis_common, cim_sys, system):
return cap

# 'Block Services Package' profile
- _bsp_cap_set(smis_common, cim_sys.path, cap)
+ _bsp_cap_set(smis_common, system.id, cap)

# 'Disk Drive Lite' profile
_disk_cap_set(smis_common, cim_sys.path, cap)
@@ -380,5 +380,5 @@ def get(smis_common, cim_sys, system):
# 'FC Target Ports' and 'iSCSI Target Ports' profiles
_tgt_cap_set(smis_common, cim_sys.path, cap)

- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)
return cap
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 4a303c3..456e6bc 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -24,9 +24,12 @@

from pywbem import Uint16, CIMError
import pywbem
+import traceback
+import os
+import datetime

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


@@ -143,9 +146,9 @@ def _profile_spec_ver_to_num(spec_ver_str):

class SmisCommon(object):
# Even many CIM_XXX_Service in DMTF shared the same return value
- # defination as SNIA do, but there is no DMTF standard metioned
+ # definition as SNIA do, but there is no DMTF standard motioned
# InvokeMethod() should follow that list of return value.
- # We use SNIA defination here.
+ # We use SNIA definition here.
# SNIA 1.6 rev4 Block book, BSP 5.5.3.12 Return Values section.
SNIA_INVOKE_OK = 0
SNIA_INVOKE_NOT_SUPPORTED = 1
@@ -179,12 +182,13 @@ class SmisCommon(object):

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

if namespace is None:
namespace = dmtf.DEFAULT_NAMESPACE
@@ -201,7 +205,8 @@ def __init__(self, url, username, password,
# https://bugzilla.redhat.com/show_bug.cgi?id=1039801
pass

- self._wbem_conn.debug = debug
+ if debug_path is not None:
+ self._wbem_conn.debug = True

if namespace.lower() == SmisCommon._MEGARAID_NAMESPACE.lower():
# Skip profile register check on MegaRAID for better performance.
@@ -247,65 +252,6 @@ def profile_check(self, profile_name, spec_ver, raise_error=False):
return _profile_check(
self._profile_dict, profile_name, spec_ver, raise_error)

- def get_class_instance(self, class_name, prop_name, prop_value,
- raise_error=True, property_list=None):
- """
- Gets an instance of a class that optionally matches a specific
- property name and value
- """
- instances = None
- if property_list is None:
- property_list = [prop_name]
- else:
- property_list = merge_list(property_list, [prop_name])
-
- try:
- cim_xxxs = self.EnumerateInstances(
- class_name, PropertyList=property_list)
- except CIMError as ce:
- error_code = tuple(ce)[0]
-
- if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
- raise_error is False:
- return None
- else:
- raise
-
- for cim_xxx in cim_xxxs:
- if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
- return cim_xxx
-
- if raise_error:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
- return None
-
- def get_cim_service_path(self, cim_sys_path, class_name):
- """
- Return None if not supported
- """
- try:
- cim_srvs = self.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass=class_name)
- except CIMError as ce:
- if ce[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
- return None
- else:
- raise
- if len(cim_srvs) == 1:
- return cim_srvs[0]
- elif len(cim_srvs) == 0:
- return None
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_get_cim_service_path(): Got unexpected(not 1) "
- "count of %s from cim_sys %s: %s" %
- (class_name, cim_sys_path, cim_srvs))
-
def _vendor_namespace(self):
if self.root_blk_cim_rp:
cim_syss_path = self._wbem_conn.AssociatorNames(
@@ -372,3 +318,210 @@ def is_megaraid(self):

def is_netappe(self):
return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E
+
+ @staticmethod
+ def cim_job_pros():
+ return ['InstanceID']
+
+ def cim_job_of_job_id(self, job_id, property_list=None):
+ """
+ Return CIM_ConcreteJob for given job_id.
+ """
+ if property_list is None:
+ property_list = SmisCommon.cim_job_pros()
+ else:
+ property_list = merge_list(
+ property_list, SmisCommon.cim_job_pros())
+
+ cim_jobs = self.EnumerateInstances(
+ 'CIM_ConcreteJob',
+ PropertyList=property_list)
+ real_job_id = SmisCommon.parse_job_id(job_id)[0]
+ for cim_job in cim_jobs:
+ if md5(cim_job['InstanceID']) == real_job_id:
+ return cim_job
+
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_JOB,
+ "Job %s not found" % job_id)
+
+ @staticmethod
+ def _job_id_of_cim_job(cim_job, retrieve_data, method_data):
+ """
+ Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
+ with '@%s' % retrieve_data
+ retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
+ SmisCommon.JOB_RETRIEVE_VOLUME or etc
+ method_data is any string a method would like store for error
+ handling by job_status().
+ """
+ return "%s@%d@%s" % (
+ md5(cim_job['InstanceID']), int(retrieve_data), str(method_data))
+
+ @staticmethod
+ def parse_job_id(job_id):
+ """
+ job_id is assembled by a md5 string, retrieve_data and method_data
+ This method will split it and return
+ (md5_str, retrieve_data, method_data)
+ """
+ tmp_list = job_id.split('@', 3)
+ md5_str = tmp_list[0]
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ method_data = None
+ if len(tmp_list) == 3:
+ retrieve_data = int(tmp_list[1])
+ method_data = tmp_list[2]
+ return (md5_str, retrieve_data, method_data)
+
+ def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
+ error_handler=None, retrieve_data=None,
+ method_data=None):
+ """
+ cmd
+ A string of command, example:
+ 'CreateOrModifyElementFromStoragePool'
+ cim_path
+ the CIMInstanceName, example:
+ CIM_StorageConfigurationService.path
+ in_params
+ A dictionary of input parameter, example:
+ {'ElementName': volume_name,
+ 'ElementType': dmtf_element_type,
+ 'InPool': cim_pool_path,
+ 'Size': pywbem.Uint64(size_bytes)}
+ out_handler
+ A reference to a method to parse output, example:
+ self._new_vol_from_name
+ error_handler
+ A reference to a method to handle all exceptions.
+ retrieve_data
+ SmisCommon.JOB_RETRIEVE_XXX, it will be used only
+ when a ASYNC job has been created.
+ method_data
+ A string which will be stored in job_id, it could be used by
+ job_status() to do error checking.
+ """
+ if retrieve_data is None:
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ try:
+ (rc, out) = self.InvokeMethod(cmd, cim_path, **in_params)
+
+ # Check to see if operation is done
+ if rc == SmisCommon.SNIA_INVOKE_OK:
+ if out_handler is None:
+ return None, None
+ else:
+ return None, out_handler(out)
+
+ elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
+ # We have an async operation
+ job_id = SmisCommon._job_id_of_cim_job(
+ out['Job'], retrieve_data, method_data)
+ return job_id, None
+ elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ 'SMI-S error code indicates operation not supported')
+ else:
+ # When debugging issues with providers it's helpful to have
+ # the xml request/reply to give to provider developers.
+ try:
+ if self._debug_path is not None:
+ if not os.path.exists(self._debug_path):
+ os.makedirs(self._debug_path)
+
+ if os.path.isdir(self._debug_path):
+ debug_fn = "%s_%s" % (
+ cmd, datetime.datetime.now().isoformat())
+ debug_full = os.path.join(
+ self._debug_path, debug_fn)
+
+ # Dump the request & reply to a file
+ with open(debug_full, 'w') as d:
+ d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
+ (self.last_request, self.last_reply))
+
+ except Exception:
+ tb = traceback.format_exc()
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= " % (cmd, str(rc))+
+ " Debug data exception: %s" % str(tb))
+
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= %s" % (cmd, str(rc)))
+
+ except Exception:
+ if error_handler is not None:
+ error_handler(self, method_data)
+ else:
+ raise
+
+ def _cim_srv_of_sys_id(self, srv_name, sys_id, raise_error):
+ property_list = ['SystemName']
+
+ cim_srvs = self.EnumerateInstances(
+ srv_name,
+ PropertyList=property_list)
+ for cim_srv in cim_srvs:
+ if cim_srv['SystemName'] == sys_id:
+ return cim_srv
+
+ if raise_error:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Cannot find any '%s' for requested systemd ID" % srv_name)
+ return None
+
+
+ def cim_scs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_StorageConfigurationService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageConfigurationService', sys_id, raise_error)
+
+
+ def cim_rs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_ReplicationService for given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ReplicationService', sys_id, raise_error)
+
+
+ def cim_gmms_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_GroupMaskingMappingService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_GroupMaskingMappingService', sys_id, raise_error)
+
+
+ def cim_ccs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_ControllerConfigurationService for given
+ system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ControllerConfigurationService', sys_id, raise_error)
+
+ def cim_hwms_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_StorageHardwareIDManagementService for
+ given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageHardwareIDManagementService', sys_id, raise_error)
diff --git a/plugin/smispy/smis_pool.py b/plugin/smispy/smis_pool.py
index ca0999e..c9f4345 100644
--- a/plugin/smispy/smis_pool.py
+++ b/plugin/smispy/smis_pool.py
@@ -15,11 +15,9 @@
#
# Author: Gris Ge <***@redhat.com>

-from utils import merge_list
+from utils import merge_list, path_str_to_cim_path, cim_path_to_path_str
import dmtf
from lsm import LsmError, ErrorNumber, Pool
-import json
-from pywbem import CIMInstanceName


def cim_pools_of_cim_sys_path(smis_common, cim_sys_path, property_list=None):
@@ -226,7 +224,7 @@ def cim_pool_to_lsm_pool(smis_common, cim_pool, system_id):

element_type, unsupported = _pool_element_type(smis_common, cim_pool)

- plugin_data = _cim_path_to_path_str(cim_pool.path)
+ plugin_data = cim_path_to_path_str(cim_pool.path)

return Pool(pool_id, name, element_type, unsupported,
total_space, free_space,
@@ -248,27 +246,7 @@ def lsm_pool_to_cim_pool_path(smis_common, lsm_pool):
ErrorNumber.NOT_FOUND_SYSTEM,
"System filtered in URI")

- return _path_str_to_cim_path(lsm_pool.plugin_data)
-
-
-def _cim_path_to_path_str(cim_path):
- """
- Convert CIMInstanceName to a string which could save in plugin_data
- """
- return json.dumps({
- 'classname': cim_path.classname,
- 'keybindings': dict(cim_path.keybindings),
- 'host': cim_path.host,
- 'namespace': cim_path.namespace,
- })
-
-
-def _path_str_to_cim_path(path_str):
- """
- Convert a string into CIMInstanceName.
- """
- path_dict = json.loads(path_str)
- return CIMInstanceName(**path_dict)
+ return path_str_to_cim_path(lsm_pool.plugin_data)


def pool_id_of_cim_vol(smis_common, cim_vol_path):
diff --git a/plugin/smispy/smis_sys.py b/plugin/smispy/smis_sys.py
index 64a9723..4101137 100644
--- a/plugin/smispy/smis_sys.py
+++ b/plugin/smispy/smis_sys.py
@@ -38,6 +38,16 @@ def sys_id_of_cim_sys(cim_sys):
"'Name' property: %s, %s" % (cim_sys.items(), cim_sys.path))


+def sys_id_of_cim_vol(cim_vol):
+ if 'SystemName' in cim_vol:
+ return cim_vol['SystemName']
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_id_of_cim_vol(): Got a CIM_StorageVolume does not have "
+ "'SystemName' property: %s, %s" % (cim_vol.items(), cim_vol.path))
+
+
def root_cim_sys(smis_common, property_list=None):
"""
Use this association to find out the root CIM_ComputerSystem:
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
new file mode 100644
index 0000000..4e125b5
--- /dev/null
+++ b/plugin/smispy/smis_vol.py
@@ -0,0 +1,228 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author: Gris Ge <***@redhat.com>
+
+import re
+import sys
+
+from lsm import md5, Volume, LsmError, ErrorNumber
+from utils import merge_list, cim_path_to_path_str, path_str_to_cim_path
+import dmtf
+from pywbem import CIMError
+
+
+def cim_vol_id_pros():
+ """
+ Return the property of CIM_StorageVolume required to generate
+ lsm.Volume.id
+ """
+ return ['SystemName', 'DeviceID']
+
+
+def vol_id_of_cim_vol(cim_vol):
+ if 'SystemName' not in cim_vol or 'DeviceID' not in cim_vol:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "vol_id_of_cim_vol(): Got cim_vol with no "
+ "SystemName or DeviceID property: %s, %s" %
+ (cim_vol.path, cim_vol.items()))
+
+ return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
+
+
+def cim_vol_pros():
+ """
+ Return the PropertyList required for creating new lsm.Volume.
+ """
+ props = ['ElementName', 'NameFormat',
+ 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
+ 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
+ 'OtherNameFormat', 'OtherNameNamespace']
+ props.extend(cim_vol_id_pros())
+ return props
+
+
+def cim_vol_of_cim_pool_path(smis_common, cim_pool_path, property_list=None):
+ """
+ Use this association to get a list of CIM_StorageVolume:
+ CIM_StoragePool
+ |
+ | CIM_AllocatedFromStoragePool
+ |
+ v
+ CIM_StorageVolume
+ CIM_StorageVolume['Usage'] == dmtf.VOL_USAGE_SYS_RESERVED will be filtered
+ out.
+ Return a list of CIM_StorageVolume.
+ """
+ if property_list is None:
+ property_list = ['Usage']
+ else:
+ property_list = merge_list(property_list, ['Usage'])
+
+ cim_vols = smis_common.Associators(
+ cim_pool_path,
+ AssocClass='CIM_AllocatedFromStoragePool',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=property_list)
+
+ rc = []
+ for cim_vol in cim_vols:
+ if 'Usage' not in cim_vol or \
+ cim_vol['Usage'] != dmtf.VOL_USAGE_SYS_RESERVED:
+ rc.append(cim_vol)
+ return rc
+
+
+def _vpd83_in_cim_vol_name(cim_vol):
+ """
+ We require NAA Type 3 VPD83 address:
+ Only this is allowed when storing VPD83 in cim_vol["Name"]:
+ * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
+ """
+ if not ('NameFormat' in cim_vol and
+ 'NameNamespace' in cim_vol and
+ 'Name' in cim_vol):
+ return None
+ nf = cim_vol['NameFormat']
+ nn = cim_vol['NameNamespace']
+ name = cim_vol['Name']
+ if not (nf and nn and name):
+ return None
+
+ if nf == dmtf.VOL_NAME_FORMAT_NNA and \
+ nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE3:
+ return name
+
+
+def _vpd83_in_cim_vol_otherinfo(cim_vol):
+ """
+ IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
+ Will return the vpd_83 value if found
+ """
+ if not ("IdentifyingDescriptions" in cim_vol and
+ "OtherIdentifyingInfo" in cim_vol):
+ return None
+
+ id_des = cim_vol["IdentifyingDescriptions"]
+ other_info = cim_vol["OtherIdentifyingInfo"]
+ if not (isinstance(cim_vol["IdentifyingDescriptions"], list) and
+ isinstance(cim_vol["OtherIdentifyingInfo"], list)):
+ return None
+
+ index = 0
+ len_id_des = len(id_des)
+ len_other_info = len(other_info)
+ while index < min(len_id_des, len_other_info):
+ if dmtf.VOL_OTHER_INFO_NAA_VPD83_TYPE3H == id_des[index]:
+ return other_info[index]
+ index += 1
+ return None
+
+
+def _vpd83_in_cim_vol_otherinfo_netapp(cim_vol):
+ # workaround for NetApp, they use OtherNameNamespace and
+ # OtherNameFormat.
+ if 'OtherNameFormat' in cim_vol and \
+ cim_vol['OtherNameFormat'] == 'NAA' and \
+ 'OtherNameNamespace' in cim_vol and \
+ cim_vol['OtherNameNamespace'] == 'VPD83Type3' and \
+ 'OtherIdentifyingInfo' in cim_vol and \
+ isinstance(cim_vol["OtherIdentifyingInfo"], list) and \
+ len(cim_vol['OtherIdentifyingInfo']) == 1:
+ return cim_vol['OtherIdentifyingInfo'][0]
+
+
+def _vpd83_of_cim_vol(cim_vol):
+ vpd_83 = _vpd83_in_cim_vol_name(cim_vol)
+ if vpd_83 is None:
+ vpd_83 = _vpd83_in_cim_vol_otherinfo(cim_vol)
+ if vpd_83 is None:
+ vpd_83 = _vpd83_in_cim_vol_otherinfo_netapp(cim_vol)
+
+ if vpd_83 and re.match('^6[a-fA-F0-9]{31}$', vpd_83):
+ return vpd_83.lower()
+ else:
+ return ''
+
+
+def cim_vol_to_lsm_vol(smis_common, cim_vol, pool_id, sys_id):
+ """
+ Takes a CIMInstance that represents a volume and returns a lsm Volume
+ """
+
+ # This is optional (User friendly name)
+ if 'ElementName' in cim_vol:
+ user_name = cim_vol["ElementName"]
+ else:
+ #Better fallback value?
+ user_name = cim_vol['DeviceID']
+
+ vpd_83 = _vpd83_of_cim_vol(cim_vol)
+
+ admin_state = Volume.ADMIN_STATE_ENABLED
+
+ plugin_data = cim_path_to_path_str(cim_vol.path)
+
+ return Volume(
+ vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
+ cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
+ pool_id, plugin_data)
+
+
+def lsm_vol_to_cim_vol_path(smis_common, lsm_vol):
+ """
+ Convert lsm.Volume to CIMInstanceName of CIM_StorageVolume using
+ lsm.Volume.plugin_data
+ """
+ if not lsm_vol.plugin_data:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.Volume instance with empty plugin_data")
+ if smis_common.system_list and \
+ lsm_vol.system_id not in smis_common.system_list:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_vol.plugin_data)
+
+
+def volume_name_exists(smis_common, volume_name):
+ """
+ Try to minimize time to search.
+ :param volume_name: Volume ElementName
+ :return: True if volume exists with 'name', else False
+ """
+ all_cim_vols = smis_common.EnumerateInstances(
+ 'CIM_StorageVolume', PropertyList=['ElementName'])
+ for exist_cim_vol in all_cim_vols:
+ if volume_name == exist_cim_vol['ElementName']:
+ return True
+ return False
+
+
+def volume_create_error_handler(smis_common, method_data):
+ """
+ When we got CIMError, we check whether we got a duplicate volume name.
+ The method_data is the requested volume name.
+ """
+ if volume_name_exists(smis_common, method_data):
+ raise LsmError(ErrorNumber.NAME_CONFLICT,
+ "Volume with name '%s' already exists!" % method_data)
+
+ (error_type, error_msg, error_trace) = sys.exc_info()
+ raise error_type, error_msg, error_trace
diff --git a/plugin/smispy/utils.py b/plugin/smispy/utils.py
index 95332b8..668241f 100644
--- a/plugin/smispy/utils.py
+++ b/plugin/smispy/utils.py
@@ -17,8 +17,9 @@

import traceback
from lsm import (LsmError, ErrorNumber, error)
-from pywbem import (CIMError)
+from pywbem import (CIMError, CIMInstanceName)
import pywbem
+import json


def merge_list(list_a, list_b):
@@ -66,3 +67,23 @@ def cim_wrapper(*args, **kwargs):
def hex_string_format(hex_str, length, every):
hex_str = hex_str.lower()
return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
+
+
+def cim_path_to_path_str(cim_path):
+ """
+ Convert CIMInstanceName to a string which could save in plugin_data
+ """
+ return json.dumps({
+ 'classname': cim_path.classname,
+ 'keybindings': dict(cim_path.keybindings),
+ 'host': cim_path.host,
+ 'namespace': cim_path.namespace,
+ })
+
+
+def path_str_to_cim_path(path_str):
+ """
+ Convert a string into CIMInstanceName.
+ """
+ path_dict = json.loads(path_str)
+ return CIMInstanceName(**path_dict)
--
1.8.3.1


------------------------------------------------------------------------------
Tony Asleson
2014-11-10 19:27:33 UTC
Permalink
Hi Gris,

Note: For this patch set and any that are already posted, you don't need
to go back and redo, but please try to do things outlined below for
future patch submissions. I will document this stuff on the wiki. We
haven't had much requirements on commits in the past, but I would like
to do so moving forward.


* Each commit should leave the code tree in a working state. This
allows for:
* Using bisect to find when bugs are introduced
* Allowing cherry-pick to be used for specific commits (typically
bug fixes)
* Take parts of patch set while other later parts are being reworked
- When moving code (add new files if needed), move the code and fix-up
references in one commit. Don't do other changes at the same time
(change signatures of methods, change moved code structure etc.)
- WS & spelling corrections in separate commit
- Use the plugin_test.py across as many arrays the plug-in supports for
every change
- Python, run the pep8 checks
- Run make distcheck

When I made the comment about squashing this patch set last week it was
referring to first item above. Some of your commits would not stand
alone and resulted in code that would not run.

Thanks!
Post by Gris Ge
1. smis_ag.py: Hold AccessGroup related methods
2. smis_vol.py: Hold Volume related methods
* Makefile and RPM SPEC file updated for new file smis_ag.py and smis_vol.py.
* Replaces smis.Smis._vol_id() with smis_vol.vol_id_of_cim_vol()
* Replaces smis.Smis._property_list_of_id('Volume') with
smis_vol.cim_vol_id_pros()
* Replace smis.Smis._cim_vol_pros() with smis_vol.cim_vol_pros()
* Replace smis.Smis._new_vol() with smis_pool.cim_vol_to_lsm_vol()
* Moved _vpd83_xxx method into smis_pool.py as it's private used by
smis_pool.cim_vol_to_lsm_vol()
* The smis_pool.cim_vol_to_lsm_vol() require caller to provide pool_id and
systemd_id as they should handled by smis_pool.py and smis_sys.py.
smis_sys.sys_id_of_cim_vol() is added for this seek.
* As these two methods will be commonly used across smis_xxx.py,
smis_pool._cim_path_to_path_str()
-> utils.cim_path_to_path_str()
smis_pool._path_str_to_cim_path()
- utils.path_str_to_cim_path()
* Replace smis.Smis._pi() with SmisCommon.invoke_method().
* When a exception triggered, invoke_method() will call 'error_handler'
with argument of: SmisCommon, method_data.
In this patch, smis_vol.volume_create_error_handler() is the
error_handler of volume_create(). It's stored in
smis.Smis._JOB_ERROR_HANDLER[SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
so that job_status() could use the same error handler.
* The invoke_method() also take 'out_handler' parameter which will be
called if the method finished in SYNC way.
In this patch, self._new_vol_from_name() is the out_handler of
volume_create().
smis.Smis._job_id() -> smis_common.SmisCommon.job_id_of_cim_job()
smis.Smis._parse_job_id() -> smis_common.SmisCommon.parse_job_id()
* Move duplicate volume checker method to smis_vol.py as the volume create
smis.Smis._volume_exists -> smis_vol.volume_name_exists
smis.Smis._check_for_dupe_vol() -> smis_vol.volume_create_error_handler()
* Store cim_vol_path data in Volume.plugin_date.
* Replace
smis.Smis._get_cim_instance_by_id('Volume', volume.id)
-> smis_vol.lsm_vol_to_cim_vol_path()
* Changed smis.Smis._deal_volume_associations_netappe() and
smis.Smis._deal_volume_associations() to take cim_vol_path only.
SmisCommon.cim_scs_of_sys_id() CIM_StorageConfigurationService
SmisCommon.cim_rs_of_sys_id() CIM_ReplicationService
SmisCommon.cim_gmms_of_sys_id() CIM_GroupMaskingMappingService
SmisCommon.cim_ccs_of_sys_id() CIM_ControllerConfigurationService
SmisCommon.cim_hwms_of_sys_id() CIM_StorageHardwareIDManagementService
* smis.Smis._cim_spc_of() changed to use system_id instead of cim_sys.path
to benefit this change.
* Empty smis_ag.py with license only.
* Makefile and RPM SPEC file updated.
* Removed smis._dmtf_init_type_to_lsm(). It has been merged into
smis_ag._cim_inits_to_lsm_init_id_and_type()
smis.Smis._cim_spc_pros()
-> smis_ag.cim_spc_pros()
smis.Smis._cim_inits_to_lsm()
-> smis_ag._cim_inits_to_lsm_init_id_and_type()
smis.Smis._cim_spc_to_lsm()
-> smis_ag.cim_spc_to_lsm_ag()
smis.Smis._cim_init_of_spc()
-> cim_init_of_cim_spc_path()
smis.Smis._cim_init_of_init_mg()
-> cim_init_of_cim_init_mg_path()
* Save cim_spc_path or cim_init_mg_path into lsm.AccessGroup.plugin_data
* Replaces these methods for converting lsm.AccessGroup to
smis.Smis._cim_spc_of_id()
-> smis_ag.lsm_ag_to_cim_spc_path()
smis.Smis._cim_init_mg_of_id()
-> smis_ag.lsm_ag_to_cim_init_mg_path()
* Replace smis.Smis._cim_init_mg_pros() with
smis_ag.cim_init_mg_pros()
* Fix typo: gernarate -> generate in smis_vol.py.
:param name: Volume ElementName
-> :param volume_name: Volume ElementName
msg, datetime.datetime.now().isoformat())
-> : cmd, datetime.datetime.now().isoformat())
defination -> definition
metioned -> motioned
cim_gmm.path, **in_params)
-> cim_gmms_path, **in_params)
LsmError, ErrorNumber
---
packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 4 +-
plugin/smispy/dmtf.py | 2 +
plugin/smispy/smis.py | 1095 +++++++++++---------------------------
plugin/smispy/smis_ag.py | 195 +++++++
plugin/smispy/smis_cap.py | 46 +-
plugin/smispy/smis_common.py | 281 +++++++---
plugin/smispy/smis_pool.py | 28 +-
plugin/smispy/smis_sys.py | 10 +
plugin/smispy/smis_vol.py | 228 ++++++++
plugin/smispy/utils.py | 23 +-
11 files changed, 1016 insertions(+), 898 deletions(-)
create mode 100644 plugin/smispy/smis_ag.py
create mode 100644 plugin/smispy/smis_vol.py
diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 0ef7c16..d7f132d 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -478,6 +478,8 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
%{python_sitelib}/lsm/plugin/smispy/smis_disk.*
+%{python_sitelib}/lsm/plugin/smispy/smis_vol.*
+%{python_sitelib}/lsm/plugin/smispy/smis_ag.*
%{_bindir}/smispy_lsmplugin
%files -n %{libstoragemgmt}-netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index c3084c9..78ceb36 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -31,7 +31,9 @@ smispy_PYTHON = \
smispy/smis_cap.py \
smispy/smis_sys.py \
smispy/smis_pool.py \
- smispy/smis_disk.py
+ smispy/smis_disk.py \
+ smispy/smis_ag.py \
+ smispy/smis_vol.py
nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 576c72e..c44db2f 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -242,3 +242,5 @@ def op_status_list_conv(conv_dict, dmtf_op_status_list,
CTRL_CONF_SRV_DA_RW = Uint16(2)
VOL_OTHER_INFO_NAA_VPD83_TYPE3H = 'NAA;VPD83Type3'
+
+VOL_USAGE_SYS_RESERVED = Uint16(3)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a571d9d..bdca963 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -19,11 +19,8 @@
from string import split
import time
-import traceback
import copy
import os
-import datetime
-import sys
import re
import pywbem
@@ -32,6 +29,8 @@
import smis_sys
import smis_pool
import smis_disk
+import smis_vol
+import smis_ag
import dmtf
from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
@@ -61,8 +60,10 @@
# cim_ip CIM_IPProtocolEndpoint
# cim_eth CIM_EthernetPort
# cim_pe CIM_SCSIProtocolEndpoint
-# cim_gmm CIM_GroupMaskingMappingService
+# cim_gmms CIM_GroupMaskingMappingService
# cim_ccs CIM_ControllerConfigurationService
+# cim_rs CIM_ReplicationService
+# cim_hwms CIM_StorageHardwareIDManagementService
#
# sys Object of LSM System
# pool Object of LSM Pool
return lsm_init_id
- return AccessGroup.INIT_TYPE_WWPN
- return AccessGroup.INIT_TYPE_ISCSI_IQN
- return AccessGroup.INIT_TYPE_UNKNOWN
-
-
"""
We are assuming we got CIM_FCPort. Caller should make sure of that.
_INVOKE_MAX_LOOP_COUNT = 60
_INVOKE_CHECK_INTERVAL = 5
+ _JOB_ERROR_HANDLER = {
+ smis_vol.volume_create_error_handler,
+ }
+
self._c = None
self.tmo = 0
- self.debug_path = None
def _get_cim_instance_by_id(self, class_type, requested_id,
@@ -163,7 +159,8 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
class_name, PropertyList=property_list)
org_requested_id = requested_id
- (requested_id, ignore, ignore) = Smis._parse_job_id(requested_id)
+ (requested_id, ignore, ignore) = SmisCommon.parse_job_id(
+ requested_id)
return cim_xxx
@@ -174,53 +171,6 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))
- """
- Handle the the process of invoking an operation.
- """
- # Check to see if operation is done
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- return None, self._new_vol_from_name(out)
- return None, None
-
- # We have an async operation
- job_id = self._job_id(out['Job'], retrieve_data, method_data)
- return job_id, None
- raise LsmError(
- ErrorNumber.NO_SUPPORT,
- 'SMI-S error code indicates operation not supported')
- # When debugging issues with providers it's helpful to have the
- # xml request/reply to give to provider developers.
- os.makedirs(self.debug_path)
-
- debug_fn = "%s_%s" % \
- (msg, datetime.datetime.now().isoformat())
- debug_full = os.path.join(self.debug_path, debug_fn)
-
- # Dump the request & reply to a file
- d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
- (self._c.last_request, self._c.last_reply))
-
- tb = traceback.format_exc()
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc) +
- ' Debug data exception: ' + str(tb))
-
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc))
-
@handle_cim_errors
"""
no_ssl_verify = True
- debug = False
+ debug_path = None
self.debug_path = u['parameters']['debug_path']
I thought I mentioned this one already, but looks like I missed it.
self.debug_path is not used in smis.py, please change self.debug_path to
just debug_path, otherwise we are not getting the debug_path passed to
SmisCommon constructor.
Post by Gris Ge
- debug = True
self._c = SmisCommon(
- url, u['username'], password, namespace, no_ssl_verify, debug,
- system_list)
+ url, u['username'], password, namespace, no_ssl_verify,
+ debug_path, system_list)
self.tmo = timeout
"""
completed_item = None
- props = ['JobState', 'PercentComplete', 'ErrorDescription',
- 'OperationalStatus']
- cim_job_pros = self._property_list_of_id('Job', props)
+ error_handler = None
+
+ (ignore, retrieve_data, method_data) = SmisCommon.parse_job_id(job_id)
- cim_job = self._get_cim_instance_by_id('Job', job_id, cim_job_pros)
+ error_handler = Smis._JOB_ERROR_HANDLER[retrieve_data]
+
+ cim_job_pros = SmisCommon.cim_job_pros()
+ cim_job_pros.extend(
+ ['JobState', 'PercentComplete', 'ErrorDescription',
+ 'OperationalStatus'])
+ cim_job = self._c.cim_job_of_job_id(job_id, cim_job_pros)
job_state = cim_job['JobState']
- (ignore, retrieve_data, method_data) = self._parse_job_id(job_id)
- if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
- status = JobStatus.INPROGRESS
+ if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
+ status = JobStatus.INPROGRESS
- pc = cim_job['PercentComplete']
- percent_complete = 100
- percent_complete = pc
+ pc = cim_job['PercentComplete']
+ percent_complete = 100
+ percent_complete = pc
- status = JobStatus.COMPLETE
- percent_complete = 100
+ status = JobStatus.COMPLETE
+ percent_complete = 100
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- completed_item = self._new_vol_from_job(cim_job)
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
+ completed_item = self._new_vol_from_job(cim_job)
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ str(cim_job['ErrorDescription']))
- status = JobStatus.ERROR
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG, str(cim_job['ErrorDescription']))
- self._check_for_dupe_vol(method_data, None)
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- str(cim_job['ErrorDescription']))
+ error_handler(self._c, method_data)
+ raise
return status, percent_complete, completed_item
"""
return self._id('SystemChild', cim_xxx)
- """
- Return the MD5 hash of CIM_StorageVolume['SystemName'] and
- ['DeviceID']
- """
- return self._id('Volume', cim_vol)
-
- """
- Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
- retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
- SmisCommon.JOB_RETRIEVE_VOLUME or etc
- method_data is any string a method would like store for error
- handling by job_status().
- """
- self._id('Job', cim_job), int(retrieve_data), str(method_data))
-
"""
Retrieve Initiator ID from CIM_StorageHardwareID
return md5(id_str)
- """
- job_id is assembled by a md5 string, retrieve_data and method_data
- This method will split it and return
- (md5_str, retrieve_data, method_data)
- """
- md5_str = tmp_list[0]
- retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
- method_data = None
- retrieve_data = int(tmp_list[1])
- method_data = tmp_list[2]
- return (md5_str, retrieve_data, method_data)
-
- other_id = None
-
- if 'OtherIdentifyingInfo' in cv \
- and cv["OtherIdentifyingInfo"] is not None \
-
- other_id = cv["OtherIdentifyingInfo"]
-
- other_id = other_id[0]
-
- # This is not what we are looking for if the field has this value
- other_id = None
-
- return other_id
-
- """
- Return the PropertyList required for creating new LSM Volume.
- """
- props = ['ElementName', 'NameFormat',
- 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
- 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
- 'OtherNameFormat', 'OtherNameNamespace']
- cim_vol_pros = self._property_list_of_id("Volume", props)
- return cim_vol_pros
-
- """
- Takes a CIMInstance that represents a volume and returns a lsm Volume
- """
-
- # This is optional (User friendly name)
- user_name = cv["ElementName"]
- #Better fallback value?
- user_name = cv['DeviceID']
-
- vpd_83 = Smis._vpd83_in_cv_name(cv)
- vpd_83 = Smis._vpd83_in_cv_otherinfo(cv)
- vpd_83 = Smis._vpd83_in_cv_otherinfo_netapp(cv)
-
- if vpd_83 and re.match('^[a-fA-F0-9]{32}$', vpd_83) and \
- vpd_83 = vpd_83.lower()
- vpd_83 = ''
-
- #This is a fairly expensive operation, so it's in our best interest
- #to not call this very often.
- #Go an retrieve the pool id
- pool_id = smis_pool.pool_id_of_cim_vol(self._c, cv.path)
-
- sys_id = cv['SystemName']
-
- admin_state = Volume.ADMIN_STATE_ENABLED
-
- return Volume(self._vol_id(cv), user_name, vpd_83, cv["BlockSize"],
- cv["NumberOfBlocks"], admin_state, sys_id, pool_id)
-
- """
- * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
- """
- if not ('NameFormat' in cv and
- 'NameNamespace' in cv and
- return None
- nf = cv['NameFormat']
- nn = cv['NameNamespace']
- name = cv['Name']
- return None
-
- if nf == dmtf.VOL_NAME_FORMAT_NNA and \
- return name
-
- """
- IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
- Will return the vpd_83 value if found
- """
- if not ("IdentifyingDescriptions" in cv and
- return None
-
- id_des = cv["IdentifyingDescriptions"]
- other_info = cv["OtherIdentifyingInfo"]
- if not (isinstance(cv["IdentifyingDescriptions"], list) and
- return None
-
- index = 0
- len_id_des = len(id_des)
- len_other_info = len(other_info)
- return other_info[index]
- index += 1
- return None
-
- # workaround for NetApp, they use OtherNameNamespace and
- # OtherNameFormat.
- if 'OtherNameFormat' in cv and \
- cv['OtherNameFormat'] == 'NAA' and \
- 'OtherNameNamespace' in cv and \
- cv['OtherNameNamespace'] == 'VPD83Type3' and \
- 'OtherIdentifyingInfo' in cv and \
- isinstance(cv["OtherIdentifyingInfo"], list) and \
- return cv['OtherIdentifyingInfo'][0]
-
"""
Given a volume by CIMInstanceName, return a lsm Volume object
"""
- instance = None
+ cim_vol = None
+ cim_vol_pros = smis_vol.cim_vol_pros()
- instance = self._c.GetInstance(out['TheElement'],
- LocalOnly=False)
+ cim_vol = self._c.GetInstance(
+ out['TheElement'],
+ PropertyList=cim_vol_pros)
- instance = self._c.GetInstance(out['TargetElement'],
- LocalOnly=False)
-
- return self._new_vol(instance)
-
- """
- Return a list of properties required to build new AccessGroup.
- """
- cim_spc_pros = ['DeviceID']
- cim_spc_pros.extend(self._property_list_of_id('SystemChild'))
- cim_spc_pros.extend(['ElementName', 'StorageID'])
- cim_spc_pros.extend(['EMCAdapterRole']) # EMC specific, used to
- # filter out the mapping SPC.
- return cim_spc_pros
-
- """
- Retrieve AccessGroup.init_ids and AccessGroup.init_type from
- a list of CIM_StorageHardwareID.
- """
- init_ids = []
- init_type = AccessGroup.INIT_TYPE_UNKNOWN
- init_types = []
- init_type = _dmtf_init_type_to_lsm(cim_init)
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- # Skip if not a iscsi initiator IQN or WWPN.
- continue
-
- init_type_dict = {}
- init_type_dict[cur_init_type] = 1
-
- init_type = init_types[0]
- init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
- return (init_ids, init_type)
-
- system_id = self._sys_id_child(cim_spc)
- ag_id = md5(cim_spc['DeviceID'])
- ag_name = cim_spc['ElementName']
- ag_init_ids = []
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- sys_id = self._sys_id_child(cim_spc)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, sys_id)
+ cim_vol = self._c.GetInstance(
+ out['TargetElement'],
+ PropertyList=cim_vol_pros)
+
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+
+ return smis_vol.cim_vol_to_lsm_vol(self._c, cim_vol, pool_id, sys_id)
"""
Given a concrete job instance, return referenced volume as lsm volume
"""
- for a in self._c.Associators(job.path,
- AssocClass='CIM_AffectedJobElement',
- return self._new_vol(self._c.GetInstance(a.path, LocalOnly=False))
+ cim_vol_pros = smis_vol.cim_vol_pros()
+ cim_vols = self._c.Associators(
+ job.path,
+ AssocClass='CIM_AffectedJobElement',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=cim_vol_pros)
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ return smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id)
return None
@handle_cim_errors
rc = []
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()
sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
pool_pros = smis_pool.cim_pool_id_pros()
self._c, cim_sys.path, pool_pros)
pool_id = smis_pool.pool_id_of_cim_pool(cim_pool)
- cim_vols = self._c.Associators(
- cim_pool.path,
- AssocClass='CIM_AllocatedFromStoragePool',
- ResultClass='CIM_StorageVolume',
- PropertyList=cim_vol_pros)
+ cim_vols = smis_vol.cim_vol_of_cim_pool_path(
+ self._c, cim_pool.path, cim_vol_pros)
- # Exclude those volumes which are reserved for system
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id))
return search_property(rc, search_key, search_value)
@handle_cim_errors
return [smis_sys.cim_sys_to_lsm_sys(s) for s in cim_syss]
- """
- Try to minimize time to search.
- :param name: Volume ElementName
- :return: True if volume exists with 'name', else False
- """
- all_cim_vols = self._c.EnumerateInstances(
- 'CIM_StorageVolume', PropertyList=['ElementName'])
- return True
- return False
-
- """
- Throw original exception or NAME_CONFLICT if volume name found
- :param volume_name: Volume to check for
- :original_exception Info grabbed from sys.exec_info
- if original_exception == None, will not raise any error if not
- NAME_CONFLICT, just return None.
- """
- report_original = True
-
- # Check to see if we already have a volume with this name. If we
- # do we will assume that this is the cause of it. We will hide
- # any errors that happen during this check and just report the
- # original error if we can't determine if we have a duplicate
- # name.
-
- report_original = not self._volume_exists(volume_name)
- # Don't report anything here on a failing
- pass
-
- return
- raise original_exception[1], None, original_exception[2]
- raise LsmError(ErrorNumber.NAME_CONFLICT,
- "Volume with name '%s' already exists!" %
- volume_name)
-
@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
@@ -870,8 +576,8 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
"requested provisioning type")
# Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(pool.system_id)
+
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
self._c, pool)
@@ -880,15 +586,16 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
'InPool': cim_pool_path,
'Size': pywbem.Uint64(size_bytes)}
- return self._pi("volume_create",
- SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
- volume_name,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
- self._check_for_dupe_vol(volume_name, sys.exc_info())
+ error_handler = Smis._JOB_ERROR_HANDLER[
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
+
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params,
+ out_handler=self._new_vol_from_name,
+ error_handler=error_handler,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
+ method_data=volume_name)
#Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', vol.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(vol.system_id)
in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}
- job_id = self._pi("_detach",
- SmisCommon.JOB_RETRIEVE_NONE,
- None,
- *(self._c.InvokeMethod(
- 'ModifySynchronization', scs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifySynchronization', cim_scs.path, in_params)[0]
self._poll("ModifySynchronization, detach", job_id)
return self._detach_netapp_e(vol, sync)
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- vol.system_id, raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(vol.system_id, raise_error=False)
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}
- job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE, None,
- *(self._c.InvokeMethod(
- 'ModifyReplicaSynchronization', rs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifyReplicaSynchronization', cim_rs.path, in_params)[0]
self._poll("ModifyReplicaSynchronization, detach", job_id)
return False
"""
Check a volume to see if it has any associations with other
volumes.
"""
rc = False
- lun_path = lun.path
- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')
item = s['SyncedElement']
self._detach(vol, s)
rc = True
item = s['SystemElement']
self._detach(vol, s)
rc = True
return rc
"""
Check a volume to see if it has any associations with other
volumes and deal with them.
"""
- return self._deal_volume_associations_netappe(vol, lun)
-
- lun_path = lun.path
+ return self._deal_volume_associations_netappe(vol, cim_vol_path)
- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')
item = s['SyncedElement']
self._detach(vol, s)
item = s['SystemElement']
self._detach(vol, s)
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
#If we actually have an association to delete, the volume will be
#deleted with the association, no need to call ReturnToStoragePool
- in_params = {'TheElement': lun.path}
+ in_params = {'TheElement': cim_vol_path}
#Delete returns None or Job number
- return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE,
- None,
- *(self._c.InvokeMethod('ReturnToStoragePool',
- scs.path, **in_params)))[0]
+ return self._c.invoke_method(
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]
#Loop to check to see if volume is actually gone yet!
- lun = self._get_cim_instance_by_id('Volume', volume.id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_vol = self._c.GetInstance(cim_vol_path,PropertyList=[])
^
Pep8 missing space after ,
Post by Gris Ge
+ cim_vol = self._c.GetInstance(cim_vol_path,PropertyList=[])
^
Pep8 missing space after ,
Post by Gris Ge
time.sleep(0.125)
pass
@handle_cim_errors
"""
Delete a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
- self._deal_volume_associations(volume, lun)
+ self._deal_volume_associations(volume, cim_vol_path)
- in_params = {'TheElement': lun.path}
+ in_params = {'TheElement': cim_vol_path}
# Delete returns None or Job number
- return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE, None,
- *(self._c.InvokeMethod('ReturnToStoragePool',
- scs.path,
- **in_params)))[0]
+ return self._c.invoke_method(
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]
@handle_cim_errors
"""
Re-size a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
in_params = {'ElementType': pywbem.Uint16(2),
- 'TheElement': lun.path,
+ 'TheElement': cim_vol_path,
'Size': pywbem.Uint64(new_size_bytes)}
- return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params, retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
"""
"""
rc = [None, None]
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- system_id, raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(system_id, raise_error=False)
rs_cap = self._c.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_ReplicationServiceCapabilities')[0]
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- volume_src.system_id,
- raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(
+ volume_src.system_id, raise_error=False)
# Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
# ElementName, we have to do pre-check here.
raise LsmError(ErrorNumber.NAME_CONFLICT,
"Volume with name '%s' already exists!" % name)
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)
- lun = self._get_cim_instance_by_id('Volume', volume_src.id)
+ src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
+ self._c, volume_src)
method = 'CreateElementReplica'
sync, mode = self._get_supported_sync_and_mode(
in_params = {'ElementName': name,
'SyncType': sync,
#'Mode': mode,
- 'SourceElement': lun.path,
+ 'SourceElement': src_cim_vol_path,
'WaitForCopyState': dmtf.COPY_STATE_SYNC}
method = 'CreateReplica'
# Check for storage configuration service
- rs = self._c.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', volume_src.system_id,
- raise_error=False)
+ cim_rs = self._c.cim_scs_of_sys_id(
+ volume_src.system_id, raise_error=False)
ct = Volume.REPLICATE_CLONE
in_params = {'ElementName': name,
'CopyType': ct,
- 'SourceElement': lun.path}
+ 'SourceElement': src_cim_vol_path}
in_params['TargetPool'] = cim_pool_path
- return self._pi("volume_replicate",
- SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(method,
- rs.path, **in_params)))
+ return self._c.invoke_method(
+ method, cim_rs.path, in_params,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")
- def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
+ def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
rc = SmisCommon.SNIA_INVOKE_FAILED
out = None
@@ -1228,12 +915,12 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
cim_dev_mg_path = None
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
cim_dev_mg_path = self._check_exist_cim_dev_mg(
- name, cim_gmm_path, cim_vol_path, vol_id)
+ name, cim_gmms_path, cim_vol_path, vol_id)
raise
@@ -1245,7 +932,7 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
return cim_dev_mg_path
- def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
+ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
"""
Create CIM_TargetMaskingGroup
@@ -1276,7 +963,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
cim_tgt_mg_path = None
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
@@ -1293,7 +980,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
return cim_tgt_mg_path
- def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
+ def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
in_params = {
'ElementName': name,
@@ -1302,7 +989,7 @@ def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
'DeviceMaskingGroup': cim_dev_mg_path,
}
- (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmms_path,
**in_params)
return self._wait_invoke(
"""
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_init_mg = self._cim_init_mg_of_id(access_group.id,
- raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path)
+ cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
"access group init_type: %d" %
access_group.init_type)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'],
- raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')
# We have to create the SPC and dev_mg now.
cim_tgt_mg_path = self._cim_tgt_mg_path_create(
- cim_sys.path, cim_gmm_path, access_group.name,
+ cim_sys.path, cim_gmms.path, access_group.name,
access_group.init_type)
cim_dev_mg_path = self._cim_dev_mg_path_create(
- cim_gmm_path, access_group.name, cim_vol.path, volume.id)
+ cim_gmms.path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
- cim_gmm_path, cim_init_mg.path, cim_tgt_mg_path,
+ cim_gmms.path, cim_init_mg_path, cim_tgt_mg_path,
cim_dev_mg_path, access_group.name)
# CIM_InitiatorMaskingGroup might have multiple SPC when having
# many tgt_mg. It's seldom use, but possible.
# Check whether already masked
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
# Masked.
return None
ResultClass='CIM_DeviceMaskingGroup')[0]
in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None
return self._volume_mask_old(access_group, volume, flags)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_inits = self._cim_init_of_spc(cim_spc.path)
+ cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc_path)
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
access_group.id +
"will not do volume_mask()")
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_css_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
in_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path],
+ 'ProtocolControllers': [cim_spc_path],
'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}
(rc, out) = self._c.InvokeMethod(
'ExposePaths',
- cim_css_path, **in_params)
+ cim_ccs.path, **in_params)
self._wait_invoke(rc, out)
return None
If SupportedDeviceGroupFeatures does not allow empty
DeviceMaskingGroup in SPC, we remove SPC and DeviceMaskingGroup.
"""
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_gmm_cap = self._c.Associators(
+ cim_gmms_cap = self._c.Associators(
cim_sys.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_GroupMaskingMappingCapabilities',
flag_empty_dev_in_spc = False
if dmtf.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
flag_empty_dev_in_spc = True
if ((dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedSynchronousActions']) and
+ cim_gmms_cap['SupportedSynchronousActions']) and
(dmtf.GMM_CAP_DELETE_SPC not in
raise LsmError(
ErrorNumber.NO_SUPPORT,
"volume_unmask() not supported. It requires one of these "
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(volume.system_id)
cim_spcs_path = self._c.AssociatorNames(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController')
}
(rc, out) = self._c.InvokeMethod(
'DeleteMaskingView',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None
return self._volume_unmask_old(access_group, volume)
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id,
- property_list=['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
hide_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
- (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs_path,
+ (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)
self._wait_invoke(rc, out)
return None
return True
rc = True
rc = False
return rc
- def _cim_spc_of_id(self, access_group_id, property_list=None,
- """
- Return CIMInstance of CIM_SCSIProtocolController
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- property_list = ['DeviceID']
- property_list = merge_list(property_list, ['DeviceID'])
-
- cim_spcs = self._c.EnumerateInstances(
- 'CIM_SCSIProtocolController', PropertyList=property_list)
-
- return cim_spc
-
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
"""
Return a list of CIM_SCSIProtocolController.
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_ControllerConfigurationService
|
| CIM_ConcreteDependency
v
CIM_SCSIProtocolController
"""
- cim_ccss_path = []
+ cim_ccs = None
rc_cim_spcs = []
property_list = []
- cim_ccss_path = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(system_id, raise_error=False)
error_code = tuple(ce)[0]
if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported ' +
'by this array')
- cim_ccs_path = None
- cim_ccs_path = cim_ccss_path[0]
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Got %d instance of " % len(cim_ccss_path) +
- "ControllerConfigurationService from %s" %
- cim_sys_path + " in _cim_spc_of()")
+
cim_spcs = self._c.Associators(
- cim_ccs_path,
+ cim_ccs.path,
AssocClass='CIM_ConcreteDependency',
ResultClass='CIM_SCSIProtocolController',
PropertyList=property_list)
rc_cim_spcs.append(cim_spc)
return rc_cim_spcs
- """
- Take CIM_SCSIProtocolController and return a list of
- CIM_StorageHardwareID, both are CIMInstance.
- CIM_SCSIProtocolController
- |
- | CIM_AssociatedPrivilege
- v
- CIM_StorageHardwareID
-
- CIM_SCSIProtocolController
- |
- | CIM_AuthorizedTarget
- v
- CIM_AuthorizedPrivilege
- |
- | CIM_AuthorizedSubject
- v
- CIM_StorageHardwareID
-
- Method A defined in SNIA SMIS 1.6 deprecated the Method B and Method A
- saved 1 query which provide better performance.
- Hence we try method A.
- Maybe someday, we will stop trying after knowing array's supported
- SMIS version.
- """
- cim_inits = []
- property_list = []
-
- if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_6,
- return self._c.Associators(
- cim_spc_path,
- AssocClass='CIM_AssociatedPrivilege',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
- cim_aps_path = self._c.AssociatorNames(
- cim_spc_path,
- AssocClass='CIM_AuthorizedTarget',
- ResultClass='CIM_AuthorizedPrivilege')
- cim_inits.extend(self._c.Associators(
- cim_ap_path,
- AssocClass='CIM_AuthorizedSubject',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list))
- return cim_inits
-
- """
- CIM_InitiatorMaskingGroup
- |
- | CIM_MemberOfCollection
- v
- CIM_StorageHardwareID
- """
- property_list = []
- return self._c.Associators(
- cim_init_mg_path,
- AssocClass='CIM_MemberOfCollection',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
-
@handle_cim_errors
mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vols = []
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()
# Workaround for EMC VNX/CX
mask_type = smis_cap.MASK_TYPE_MASK
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros))
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)
cim_vols = self._c.Associators(
- cim_spc.path,
+ cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
-
- return [self._new_vol(v) for v in cim_vols]
+ rc = []
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(
+ self._c, cim_vol, pool_id, sys_id))
+ return rc
@handle_cim_errors
rc = []
mask_type = smis_cap.mask_type(self._c, raise_error=True)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
# Workaround for EMC VNX/CX
cim_spc_pros = []
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
cim_spcs = self._c.Associators(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController',
PropertyList=cim_spc_pros)
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
cim_init_mgs = self._c.Associators(
cim_spc.path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, volume.system_id)
- for x in cim_init_mgs))
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, x, volume.system_id)
+ for x in cim_init_mgs))
- rc.extend(
- [self._cim_spc_to_lsm(cim_spc, volume.system_id)])
+ rc.append(
+ smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, volume.system_id))
return rc
- def _cim_init_mg_of_id(self, access_group_id, property_list=None,
- """
- Return CIMInstance of CIM_InitiatorMaskingGroup
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- property_list = ['InstanceID']
- property_list = merge_list(property_list, ['InstanceID'])
-
- cim_init_mgs = self._c.EnumerateInstances(
- 'CIM_InitiatorMaskingGroup', PropertyList=property_list)
-
- return cim_init_mg
-
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
"""
- There is no CIM_ComputerSystem association to
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_GroupMaskingMappingService
|
| CIM_ServiceAffectsElement
property_list = []
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system_id)
return self._c.Associators(
- cim_gmm_path,
+ cim_gmms.path,
AssocClass='CIM_ServiceAffectsElement',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
# Workaround for EMC VNX/CX.
system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
- cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
- for x in cim_init_mgs))
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mgs = self._cim_init_mg_of(
+ system_id, cim_init_mg_pros)
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(self._c, x, system_id)
+ for x in cim_init_mgs))
- cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
+ cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
rc.extend(
- list(self._cim_spc_to_lsm(cim_spc, system_id)
- for cim_spc in cim_spcs))
+ list(
+ smis_ag.cim_spc_to_lsm_ag(self._c, cim_spc, system_id)
+ for cim_spc in cim_spcs))
raise LsmError(ErrorNumber.PLUGIN_BUG,
"_get_cim_spc_by_id(): Got invalid mask_type: "
return search_property(rc, search_key, search_value)
"""
Check whether CIM_StorageHardwareID exists, if not, create new one.
"""
"SMI-S Plugin does not support init_type %d" %
init_type)
- return self._cim_init_path_create(
- cim_sys_path, init_id, dmtf_id_type)
+ return self._cim_init_path_create(system_id, init_id, dmtf_id_type)
"""
Create a CIM_StorageHardwareID.
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_StorageHardwareIDManagementService')
+ cim_hwms = self._c.cim_hwms_of_sys_id(system_id)
in_params = {'StorageID': init_id,
'IDType': pywbem.Uint16(dmtf_id_type)}
(rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- cim_hw_srv_path, **in_params)
+ cim_hwms.path, **in_params)
# CreateStorageHardwareID does not allow ASYNC
return self._wait_invoke(
rc, out, out_key='HardwareID',
"new initiator which is not supported by LSM yet. "
"Please do it via EMC vendor specific tools.")
- cim_init_mg = self._cim_init_mg_of_id(access_group.id)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
# Check whether already added.
return copy.deepcopy(access_group)
cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ access_group.system_id, init_id, init_type)
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
new_cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
expect_class='CIM_InitiatorMaskingGroup')
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
new_cim_init_mg = self._c.GetInstance(
new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
LocalOnly=False)
- return self._cim_init_mg_to_lsm(
- new_cim_init_mg, access_group.system_id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, new_cim_init_mg, access_group.system_id)
@handle_cim_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
"Please do it via EMC vendor specific tools. "
"EMC VNX does not support adding iSCSI IQN neither")
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_spc_path(
+ self._c, cim_spc_path)
# Check to see if we have this initiator already, if not we
# create it and then add to the view.
- self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)
+ self._cim_init_path_check_or_create(
+ access_group.system_id, init_id, init_type)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
in_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
(rc, out) = self._c.InvokeMethod('ExposePaths',
- cim_ccs_path, **in_params)
+ cim_ccs.path, **in_params)
cim_spc_path = self._wait_invoke(
rc, out, out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
cim_spc = self._c.GetInstance(
cim_spc_path, PropertyList=cim_spc_pros, LocalOnly=False)
- return self._cim_spc_to_lsm(cim_spc, access_group.system_id)
+ return smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, access_group.system_id)
"""
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True, property_list=cim_init_mg_pros)
-
- cim_init_pros = self._property_list_of_id('Initiator')
- cur_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, property_list=cim_init_pros)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
+ cur_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
cim_init = None
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
# RemoveMembers from InitiatorMaskingGroup
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init.path],
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
- return self._cim_init_mg_to_lsm(
- cim_init_mg, access_group.system_id)
+
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mg = self._c.GetInstance(
+ cim_init_mg_path, PropertyList=cim_init_mg_pros)
+
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, cim_init_mg, access_group.system_id)
@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, init_type,
@@ -2107,17 +1654,14 @@ def access_group_initiator_delete(self, access_group, init_id, init_type,
return self._ag_init_del_old(access_group, init_id)
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
hide_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
(rc, out) = self._c.InvokeMethod(
- 'HidePaths', cim_ccs_path, **hide_params)
+ 'HidePaths', cim_ccs.path, **hide_params)
self._wait_invoke(rc, out)
return None
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id,
- ['DeleteOnCompletion'])
+ cim_job = self._c.cim_job_of_job_id(job_id, ['DeleteOnCompletion'])
# See if we should delete the job
return search_property(rc, search_key, search_value)
- return ['ElementName', 'InstanceID']
-
- ag_name = cim_init_mg['ElementName']
- ag_id = md5(cim_init_mg['InstanceID'])
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
-
def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
"""
return None
- def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
+ def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
"""
This is buggy check, but it works on EMC VMAX which is only supported
@@ -2632,14 +2163,14 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
break
# Check whether cim_vol included.
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_dev_mg.path,
AssocClass='CIM_OrderedMemberOfCollection',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
return cim_dev_mg.path
# We should add this volume to found DeviceMaskingGroup
@@ -2649,7 +2180,7 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms_path, **in_params)
self._wait_invoke(rc, out)
return cim_dev_mg.path
@@ -2705,21 +2236,20 @@ def access_group_create(self, name, init_id, init_type, system,
"iSCSI IQN access group")
cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ system.id, init_id, init_type)
# Create CIM_InitiatorMaskingGroup
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system.id)
in_params = {'GroupName': name,
'Members': [cim_init_path],
'Type': dmtf.MASK_GROUP_TYPE_INIT}
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
(rc, out) = self._c.InvokeMethod(
- 'CreateGroup', cim_gmm_path, **in_params)
+ 'CreateGroup', cim_gmms.path, **in_params)
cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
@@ -2739,8 +2269,8 @@ def access_group_create(self, name, init_id, init_type, system,
- return self._cim_init_mg_to_lsm(
- exist_cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, exist_cim_init_mg, system.id)
# Name does not match.
raise LsmError(ErrorNumber.EXISTS_INITIATOR,
@@ -2753,7 +2283,7 @@ def access_group_create(self, name, init_id, init_type, system,
# Since 1) already checked whether any group containing
# requested init_id, now, it's surly a conflict.
exist_cim_init_mgs = self._cim_init_mg_of(
- cim_sys.path, property_list=['ElementName'])
+ system.id, property_list=['ElementName'])
raise LsmError(ErrorNumber.NAME_CONFLICT,
@@ -2764,7 +2294,7 @@ def access_group_create(self, name, init_id, init_type, system,
cim_init_mg = self._c.GetInstance(
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
- return self._cim_init_mg_to_lsm(cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(self._c, cim_init_mg, system.id)
@handle_cim_errors
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
raise_error=True)
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
# Check whether still have volume masked.
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')
"Access Group %s has volume masked" %
access_group.id)
- cim_gmm_path = self._c.AssociatorNames(
- cim_init_mg.path,
- AssocClass='CIM_ServiceAffectsElement',
- ResultClass='CIM_GroupMaskingMappingService')[0]
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Force': True,
}
- (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmms.path,
**in_params)
self._wait_invoke(rc, out)
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
new file mode 100644
index 0000000..3c125ef
--- /dev/null
+++ b/plugin/smispy/smis_ag.py
@@ -0,0 +1,195 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+from pywbem import CIMError, CIM_ERR_NOT_FOUND
+
+from lsm import AccessGroup, md5, LsmError, ErrorNumber
+
+from smis_common import SmisCommon
+import dmtf
+from utils import cim_path_to_path_str, path_str_to_cim_path
+
+_CIM_INIT_PROS = ['StorageID', 'IDType']
+
+
+ """
+ Retrieve AccessGroup.init_ids and AccessGroup.init_type from
+ a list of CIM_StorageHardwareID.
+ """
+ init_ids = []
+ init_type = AccessGroup.INIT_TYPE_UNKNOWN
+ init_types = []
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_WWPN)
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_ISCSI_IQN)
+ # Skip if not a iscsi initiator IQN or WWPN.
+ continue
+
+ init_type_dict = {}
+ init_type_dict[cur_init_type] = 1
+
+ init_type = init_types[0]
+ init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
+ return (init_ids, init_type)
+
+
+ """
+ Return the property of CIM_SCSIProtocolController required to gernarate
+ lsm.AccessGroup
+ 'EMCAdapterRole' is for EMC VNX only.
+ """
+ return ['DeviceID', 'ElementName', 'StorageID', 'EMCAdapterRole',
+ 'SystemName']
+
+
+ """
+ Return the property of CIM_InitiatorMaskingGroup required to gernarate
+ lsm.AccessGroup
+ """
+ return ['ElementName', 'InstanceID']
+
+
+ """
+ Return a list of CIM_StorageHardwareID associated to cim_spc.
+ Only contain ['StorageID', 'IDType'] property.
+ CIM_SCSIProtocolController
+ |
+ | CIM_AssociatedPrivilege
+ v
+ CIM_StorageHardwareID
+
+ CIM_SCSIProtocolController
+ |
+ | CIM_AuthorizedTarget
+ v
+ CIM_AuthorizedPrivilege
+ |
+ | CIM_AuthorizedSubject
+ v
+ CIM_StorageHardwareID
+ """
+ rc = []
+ if smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_6,
+ rc = smis_common.Associators(
+ cim_spc_path,
+ AssocClass='CIM_AssociatedPrivilege',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+ pass
+ raise
+
+ cim_aps_path = smis_common.AssociatorNames(
+ cim_spc_path,
+ AssocClass='CIM_AuthorizedTarget',
+ ResultClass='CIM_AuthorizedPrivilege')
+
+ rc.extend(smis_common.Associators(
+ cim_ap_path,
+ AssocClass='CIM_AuthorizedSubject',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS))
+ return rc
+
+
+ ag_id = md5(cim_spc['DeviceID'])
+ ag_name = cim_spc['ElementName']
+ ag_init_ids = []
+ cim_inits = cim_init_of_cim_spc_path(smis_common, cim_spc.path)
+ (init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_spc.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+ """
+ CIM_InitiatorMaskingGroup
+ |
+ | CIM_MemberOfCollection
+ v
+ CIM_StorageHardwareID
+ Only contain ['StorageID', 'IDType'] property.
+ """
+ return smis_common.Associators(
+ cim_init_mg_path,
+ AssocClass='CIM_MemberOfCollection',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+
+
+ ag_name = cim_init_mg['ElementName']
+ ag_id = md5(cim_init_mg['InstanceID'])
+ cim_inits = cim_init_of_cim_init_mg_path(smis_common, cim_init_mg.path)
+ (init_ids, init_type) = _cim_inits_to_lsm_init_id_and_type(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_init_mg.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_SCSIProtocolController
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.AccessGroup instance with empty plugin_data")
+ if smis_common.system_list and \
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_ag.plugin_data)
+
+
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_InitiatorMaskingGroup
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ return lsm_ag_to_cim_spc_path(smis_common, lsm_ag)
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
index 1309056..1fee9a8 100644
--- a/plugin/smispy/smis_cap.py
+++ b/plugin/smispy/smis_cap.py
@@ -23,17 +23,19 @@
MASK_TYPE_GROUP = 2
"""
Interrogate the supported features of the replication service
"""
- rs = smis_common.get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, raise_error=False)
+ cim_rs = smis_common.cim_rs_of_sys_id(system_id, raise_error=False)
rs_cap = smis_common.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_ReplicationServiceCapabilities')[0]
+ ResultClass='CIM_ReplicationServiceCapabilities',
+ PropertyList=['SupportedReplicationTypes',
+ 'SupportedAsynchronousActions',
+ 'SupportedSynchronousActions'])[0]
s_rt = rs_cap['SupportedReplicationTypes']
async_actions = rs_cap['SupportedAsynchronousActions']
# Try older storage configuration service
- rs = smis_common.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', system.id,
- raise_error=False)
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)
- rs_cap = smis_common.Associators(
- rs.path,
+ cim_sc_cap = smis_common.Associators(
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedCopyTypes'])[0]
- sct = rs_cap['SupportedCopyTypes']
+ sct = cim_sc_cap['SupportedCopyTypes']
cap.set(Capabilities.VOLUME_REPLICATE)
cap.set(Capabilities.VOLUME_REPLICATE_COPY)
"""
volumes()
volume_delete()
"""
# CIM_StorageConfigurationService is optional.
- cim_scs_path = smis_common.get_cim_service_path(
- cim_sys_path, 'CIM_StorageConfigurationService')
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)
return
# Hence we check CIM_StorageConfigurationCapabilities
# which is mandatory if CIM_StorageConfigurationService is supported.
cim_scs_cap = smis_common.Associators(
- cim_scs_path,
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_StorageConfigurationCapabilities',
PropertyList=['SupportedAsynchronousActions',
cap = Capabilities()
- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)
#TODO We need to investigate why our interrogation code doesn't
#work.
return cap
# 'Block Services Package' profile
- _bsp_cap_set(smis_common, cim_sys.path, cap)
+ _bsp_cap_set(smis_common, system.id, cap)
# 'Disk Drive Lite' profile
_disk_cap_set(smis_common, cim_sys.path, cap)
# 'FC Target Ports' and 'iSCSI Target Ports' profiles
_tgt_cap_set(smis_common, cim_sys.path, cap)
- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)
return cap
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 4a303c3..456e6bc 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -24,9 +24,12 @@
from pywbem import Uint16, CIMError
import pywbem
+import traceback
+import os
+import datetime
import dmtf
-from lsm import LsmError, ErrorNumber
+from lsm import LsmError, ErrorNumber, md5
from utils import (merge_list)
# Even many CIM_XXX_Service in DMTF shared the same return value
- # defination as SNIA do, but there is no DMTF standard metioned
+ # definition as SNIA do, but there is no DMTF standard motioned
# InvokeMethod() should follow that list of return value.
- # We use SNIA defination here.
+ # We use SNIA definition here.
# SNIA 1.6 rev4 Block book, BSP 5.5.3.12 Return Values section.
SNIA_INVOKE_OK = 0
SNIA_INVOKE_NOT_SUPPORTED = 1
def __init__(self, url, username, password,
namespace=dmtf.DEFAULT_NAMESPACE,
self._wbem_conn = None
self._profile_dict = {}
self.root_blk_cim_rp = None # For root_cim_
self._vendor_product = None # For vendor workaround codes.
self.system_list = system_list
+ self._debug_path = debug_path
namespace = dmtf.DEFAULT_NAMESPACE
@@ -201,7 +205,8 @@ def __init__(self, url, username, password,
# https://bugzilla.redhat.com/show_bug.cgi?id=1039801
pass
- self._wbem_conn.debug = debug
+ self._wbem_conn.debug = True
# Skip profile register check on MegaRAID for better performance.
return _profile_check(
self._profile_dict, profile_name, spec_ver, raise_error)
- def get_class_instance(self, class_name, prop_name, prop_value,
- """
- Gets an instance of a class that optionally matches a specific
- property name and value
- """
- instances = None
- property_list = [prop_name]
- property_list = merge_list(property_list, [prop_name])
-
- cim_xxxs = self.EnumerateInstances(
- class_name, PropertyList=property_list)
- error_code = tuple(ce)[0]
-
- if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
- return None
- raise
-
- return cim_xxx
-
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
- return None
-
- """
- Return None if not supported
- """
- cim_srvs = self.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass=class_name)
- return None
- raise
- return cim_srvs[0]
- return None
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_get_cim_service_path(): Got unexpected(not 1) "
- "count of %s from cim_sys %s: %s" %
- (class_name, cim_sys_path, cim_srvs))
-
cim_syss_path = self._wbem_conn.AssociatorNames(
return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E
+
+ return ['InstanceID']
+
+ """
+ Return CIM_ConcreteJob for given job_id.
+ """
+ property_list = SmisCommon.cim_job_pros()
+ property_list = merge_list(
+ property_list, SmisCommon.cim_job_pros())
+
+ cim_jobs = self.EnumerateInstances(
+ 'CIM_ConcreteJob',
+ PropertyList=property_list)
+ real_job_id = SmisCommon.parse_job_id(job_id)[0]
+ return cim_job
+
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_JOB,
+ "Job %s not found" % job_id)
+
+ """
+ Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
+ retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
+ SmisCommon.JOB_RETRIEVE_VOLUME or etc
+ method_data is any string a method would like store for error
+ handling by job_status().
+ """
+ md5(cim_job['InstanceID']), int(retrieve_data), str(method_data))
+
+ """
+ job_id is assembled by a md5 string, retrieve_data and method_data
+ This method will split it and return
+ (md5_str, retrieve_data, method_data)
+ """
+ md5_str = tmp_list[0]
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ method_data = None
+ retrieve_data = int(tmp_list[1])
+ method_data = tmp_list[2]
+ return (md5_str, retrieve_data, method_data)
+
+ def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
+ error_handler=None, retrieve_data=None,
+ """
+ cmd
+ 'CreateOrModifyElementFromStoragePool'
+ cim_path
+ CIM_StorageConfigurationService.path
+ in_params
+ {'ElementName': volume_name,
+ 'ElementType': dmtf_element_type,
+ 'InPool': cim_pool_path,
+ 'Size': pywbem.Uint64(size_bytes)}
+ out_handler
+ self._new_vol_from_name
+ error_handler
+ A reference to a method to handle all exceptions.
+ retrieve_data
+ SmisCommon.JOB_RETRIEVE_XXX, it will be used only
+ when a ASYNC job has been created.
+ method_data
+ A string which will be stored in job_id, it could be used by
+ job_status() to do error checking.
+ """
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ (rc, out) = self.InvokeMethod(cmd, cim_path, **in_params)
+
+ # Check to see if operation is done
+ return None, None
+ return None, out_handler(out)
+
+ # We have an async operation
+ job_id = SmisCommon._job_id_of_cim_job(
+ out['Job'], retrieve_data, method_data)
+ return job_id, None
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ 'SMI-S error code indicates operation not supported')
+ # When debugging issues with providers it's helpful to have
+ # the xml request/reply to give to provider developers.
+ os.makedirs(self._debug_path)
+
+ debug_fn = "%s_%s" % (
+ cmd, datetime.datetime.now().isoformat())
+ debug_full = os.path.join(
+ self._debug_path, debug_fn)
+
+ # Dump the request & reply to a file
+ d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
+ (self.last_request, self.last_reply))
+
+ tb = traceback.format_exc()
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= " % (cmd, str(rc))+
+ " Debug data exception: %s" % str(tb))
The format string only has one argument, but the code is supplying 2.
In addition I believe you are missing the ',' so that the third
parameter is the debug value.

I believe you want the code to be:

raise LsmError(ErrorNumber.PLUGIN_BUG,
"Error: %s rc= %s" % (cmd, str(rc)),
" Debug data exception: %s" % str(tb))
Post by Gris Ge
+
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= %s" % (cmd, str(rc)))
+
+ error_handler(self, method_data)
+ raise
+
+ property_list = ['SystemName']
+
+ cim_srvs = self.EnumerateInstances(
+ srv_name,
+ PropertyList=property_list)
+ return cim_srv
+
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Cannot find any '%s' for requested systemd ID" % srv_name)
+ return None
+
+
+ """
+ Return a CIMInstance of CIM_StorageConfigurationService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageConfigurationService', sys_id, raise_error)
+
+
+ """
+ Return a CIMInstance of CIM_ReplicationService for given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ReplicationService', sys_id, raise_error)
+
+
+ """
+ Return a CIMInstance of CIM_GroupMaskingMappingService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_GroupMaskingMappingService', sys_id, raise_error)
+
+
+ """
+ Return a CIMInstance of CIM_ControllerConfigurationService for given
+ system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ControllerConfigurationService', sys_id, raise_error)
+
+ """
+ Return a CIMInstance of CIM_StorageHardwareIDManagementService for
+ given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageHardwareIDManagementService', sys_id, raise_error)
diff --git a/plugin/smispy/smis_pool.py b/plugin/smispy/smis_pool.py
index ca0999e..c9f4345 100644
--- a/plugin/smispy/smis_pool.py
+++ b/plugin/smispy/smis_pool.py
@@ -15,11 +15,9 @@
#
-from utils import merge_list
+from utils import merge_list, path_str_to_cim_path, cim_path_to_path_str
import dmtf
from lsm import LsmError, ErrorNumber, Pool
-import json
-from pywbem import CIMInstanceName
element_type, unsupported = _pool_element_type(smis_common, cim_pool)
- plugin_data = _cim_path_to_path_str(cim_pool.path)
+ plugin_data = cim_path_to_path_str(cim_pool.path)
return Pool(pool_id, name, element_type, unsupported,
total_space, free_space,
ErrorNumber.NOT_FOUND_SYSTEM,
"System filtered in URI")
- return _path_str_to_cim_path(lsm_pool.plugin_data)
-
-
- """
- Convert CIMInstanceName to a string which could save in plugin_data
- """
- return json.dumps({
- 'classname': cim_path.classname,
- 'keybindings': dict(cim_path.keybindings),
- 'host': cim_path.host,
- 'namespace': cim_path.namespace,
- })
-
-
- """
- Convert a string into CIMInstanceName.
- """
- path_dict = json.loads(path_str)
- return CIMInstanceName(**path_dict)
+ return path_str_to_cim_path(lsm_pool.plugin_data)
diff --git a/plugin/smispy/smis_sys.py b/plugin/smispy/smis_sys.py
index 64a9723..4101137 100644
--- a/plugin/smispy/smis_sys.py
+++ b/plugin/smispy/smis_sys.py
"'Name' property: %s, %s" % (cim_sys.items(), cim_sys.path))
+ return cim_vol['SystemName']
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_id_of_cim_vol(): Got a CIM_StorageVolume does not have "
+ "'SystemName' property: %s, %s" % (cim_vol.items(), cim_vol.path))
+
+
"""
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
new file mode 100644
index 0000000..4e125b5
--- /dev/null
+++ b/plugin/smispy/smis_vol.py
@@ -0,0 +1,228 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import re
+import sys
+
+from lsm import md5, Volume, LsmError, ErrorNumber
+from utils import merge_list, cim_path_to_path_str, path_str_to_cim_path
+import dmtf
+from pywbem import CIMError
CIMError is not actually used in this file, can remove.
Post by Gris Ge
+
+
+ """
+ Return the property of CIM_StorageVolume required to generate
+ lsm.Volume.id
+ """
+ return ['SystemName', 'DeviceID']
+
+
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "vol_id_of_cim_vol(): Got cim_vol with no "
+ "SystemName or DeviceID property: %s, %s" %
+ (cim_vol.path, cim_vol.items()))
+
+ return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
+
+
+ """
+ Return the PropertyList required for creating new lsm.Volume.
+ """
+ props = ['ElementName', 'NameFormat',
+ 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
+ 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
+ 'OtherNameFormat', 'OtherNameNamespace']
+ props.extend(cim_vol_id_pros())
+ return props
+
+
+ """
+ CIM_StoragePool
+ |
+ | CIM_AllocatedFromStoragePool
+ |
+ v
+ CIM_StorageVolume
+ CIM_StorageVolume['Usage'] == dmtf.VOL_USAGE_SYS_RESERVED will be filtered
+ out.
+ Return a list of CIM_StorageVolume.
+ """
+ property_list = ['Usage']
+ property_list = merge_list(property_list, ['Usage'])
+
+ cim_vols = smis_common.Associators(
+ cim_pool_path,
+ AssocClass='CIM_AllocatedFromStoragePool',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=property_list)
+
+ rc = []
+ if 'Usage' not in cim_vol or \
+ rc.append(cim_vol)
+ return rc
+
+
+ """
+ * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
+ """
+ if not ('NameFormat' in cim_vol and
+ 'NameNamespace' in cim_vol and
+ return None
+ nf = cim_vol['NameFormat']
+ nn = cim_vol['NameNamespace']
+ name = cim_vol['Name']
+ return None
+
+ if nf == dmtf.VOL_NAME_FORMAT_NNA and \
+ return name
+
+
+ """
+ IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
+ Will return the vpd_83 value if found
+ """
+ if not ("IdentifyingDescriptions" in cim_vol and
+ return None
+
+ id_des = cim_vol["IdentifyingDescriptions"]
+ other_info = cim_vol["OtherIdentifyingInfo"]
+ if not (isinstance(cim_vol["IdentifyingDescriptions"], list) and
+ return None
+
+ index = 0
+ len_id_des = len(id_des)
+ len_other_info = len(other_info)
+ return other_info[index]
+ index += 1
+ return None
+
+
+ # workaround for NetApp, they use OtherNameNamespace and
+ # OtherNameFormat.
+ if 'OtherNameFormat' in cim_vol and \
+ cim_vol['OtherNameFormat'] == 'NAA' and \
+ 'OtherNameNamespace' in cim_vol and \
+ cim_vol['OtherNameNamespace'] == 'VPD83Type3' and \
+ 'OtherIdentifyingInfo' in cim_vol and \
+ isinstance(cim_vol["OtherIdentifyingInfo"], list) and \
+ return cim_vol['OtherIdentifyingInfo'][0]
+
+
+ vpd_83 = _vpd83_in_cim_vol_name(cim_vol)
+ vpd_83 = _vpd83_in_cim_vol_otherinfo(cim_vol)
+ vpd_83 = _vpd83_in_cim_vol_otherinfo_netapp(cim_vol)
+
+ return vpd_83.lower()
+ return ''
+
+
+ """
+ Takes a CIMInstance that represents a volume and returns a lsm Volume
+ """
+
+ # This is optional (User friendly name)
+ user_name = cim_vol["ElementName"]
+ #Better fallback value?
+ user_name = cim_vol['DeviceID']
+
+ vpd_83 = _vpd83_of_cim_vol(cim_vol)
+
+ admin_state = Volume.ADMIN_STATE_ENABLED
+
+ plugin_data = cim_path_to_path_str(cim_vol.path)
+
+ return Volume(
+ vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
+ cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
+ pool_id, plugin_data)
+
+
+ """
+ Convert lsm.Volume to CIMInstanceName of CIM_StorageVolume using
+ lsm.Volume.plugin_data
+ """
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.Volume instance with empty plugin_data")
+ if smis_common.system_list and \
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_vol.plugin_data)
+
+
+ """
+ Try to minimize time to search.
+ :param volume_name: Volume ElementName
+ :return: True if volume exists with 'name', else False
+ """
+ all_cim_vols = smis_common.EnumerateInstances(
+ 'CIM_StorageVolume', PropertyList=['ElementName'])
+ return True
+ return False
+
+
+ """
+ When we got CIMError, we check whether we got a duplicate volume name.
+ The method_data is the requested volume name.
+ """
+ raise LsmError(ErrorNumber.NAME_CONFLICT,
+ "Volume with name '%s' already exists!" % method_data)
+
+ (error_type, error_msg, error_trace) = sys.exc_info()
+ raise error_type, error_msg, error_trace
diff --git a/plugin/smispy/utils.py b/plugin/smispy/utils.py
index 95332b8..668241f 100644
--- a/plugin/smispy/utils.py
+++ b/plugin/smispy/utils.py
@@ -17,8 +17,9 @@
import traceback
from lsm import (LsmError, ErrorNumber, error)
-from pywbem import (CIMError)
+from pywbem import (CIMError, CIMInstanceName)
import pywbem
+import json
hex_str = hex_str.lower()
return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
+
+
+ """
+ Convert CIMInstanceName to a string which could save in plugin_data
+ """
+ return json.dumps({
+ 'classname': cim_path.classname,
+ 'keybindings': dict(cim_path.keybindings),
+ 'host': cim_path.host,
+ 'namespace': cim_path.namespace,
+ })
+
+
+ """
+ Convert a string into CIMInstanceName.
+ """
+ path_dict = json.loads(path_str)
+ return CIMInstanceName(**path_dict)
Thanks!

Regards,
Tony
Gris Ge
2014-11-12 13:31:19 UTC
Permalink
* New script:
1. smis_ag.py: Hold AccessGroup related methods
2. smis_vol.py: Hold Volume related methods
* Makefile and RPM SPEC file updated for new file smis_ag.py and smis_vol.py.
* Replaces smis.Smis._vol_id() with smis_vol.vol_id_of_cim_vol()
* Replaces smis.Smis._property_list_of_id('Volume') with
smis_vol.cim_vol_id_pros()
* Replace smis.Smis._cim_vol_pros() with smis_vol.cim_vol_pros()
* Replace smis.Smis._new_vol() with smis_pool.cim_vol_to_lsm_vol()
* Moved _vpd83_xxx method into smis_pool.py as it's private used by
smis_pool.cim_vol_to_lsm_vol()
* The smis_pool.cim_vol_to_lsm_vol() require caller to provide pool_id and
systemd_id as they should handled by smis_pool.py and smis_sys.py.
smis_sys.sys_id_of_cim_vol() is added for this seek.
* As these two methods will be commonly used across smis_xxx.py,
move them into utils.py file:
smis_pool._cim_path_to_path_str()
-> utils.cim_path_to_path_str()
smis_pool._path_str_to_cim_path()
- utils.path_str_to_cim_path()
* Replace smis.Smis._pi() with SmisCommon.invoke_method().
* When a exception triggered, invoke_method() will call 'error_handler'
with argument of: SmisCommon, method_data.
In this patch, smis_vol.volume_create_error_handler() is the
error_handler of volume_create(). It's stored in
smis.Smis._JOB_ERROR_HANDLER[SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
so that job_status() could use the same error handler.
* The invoke_method() also take 'out_handler' parameter which will be
called if the method finished in SYNC way.
In this patch, self._new_vol_from_name() is the out_handler of
volume_create().
* Moved job id generator and parser into smis_common.py:
smis.Smis._job_id() -> smis_common.SmisCommon.job_id_of_cim_job()
smis.Smis._parse_job_id() -> smis_common.SmisCommon.parse_job_id()
* Move duplicate volume checker method to smis_vol.py as the volume create
error handler require it while smis_vol.py cannot depend on smis.py:
smis.Smis._volume_exists -> smis_vol.volume_name_exists
smis.Smis._check_for_dupe_vol() -> smis_vol.volume_create_error_handler()
* Store cim_vol_path data in Volume.plugin_date.
* Replace
smis.Smis._get_cim_instance_by_id('Volume', volume.id)
-> smis_vol.lsm_vol_to_cim_vol_path()
* Changed smis.Smis._deal_volume_associations_netappe() and
smis.Smis._deal_volume_associations() to take cim_vol_path only.
* Replace SmisCommon.get_class_instance() and get_cim_service_path() with:
SmisCommon.cim_scs_of_sys_id() CIM_StorageConfigurationService
SmisCommon.cim_rs_of_sys_id() CIM_ReplicationService
SmisCommon.cim_gmms_of_sys_id() CIM_GroupMaskingMappingService
SmisCommon.cim_ccs_of_sys_id() CIM_ControllerConfigurationService
SmisCommon.cim_hwms_of_sys_id() CIM_StorageHardwareIDManagementService
* smis.Smis._cim_spc_of() changed to use system_id instead of cim_sys.path
to benefit this change.
* Empty smis_ag.py with license only.
* Makefile and RPM SPEC file updated.
* Removed smis._dmtf_init_type_to_lsm(). It has been merged into
smis_ag._cim_inits_to_lsm_init_id_and_type()
* Replaced these methods:
smis.Smis._cim_spc_pros()
-> smis_ag.cim_spc_pros()
smis.Smis._cim_inits_to_lsm()
-> smis_ag._cim_inits_to_lsm_init_id_and_type()
smis.Smis._cim_spc_to_lsm()
-> smis_ag.cim_spc_to_lsm_ag()
smis.Smis._cim_init_of_spc()
-> cim_init_of_cim_spc_path()
smis.Smis._cim_init_of_init_mg()
-> cim_init_of_cim_init_mg_path()
* Save cim_spc_path or cim_init_mg_path into lsm.AccessGroup.plugin_data
* Replaces these methods for converting lsm.AccessGroup to
cim_spc/cim_init_mg:
smis.Smis._cim_spc_of_id()
-> smis_ag.lsm_ag_to_cim_spc_path()
smis.Smis._cim_init_mg_of_id()
-> smis_ag.lsm_ag_to_cim_init_mg_path()
* Replace smis.Smis._cim_init_mg_pros() with
smis_ag.cim_init_mg_pros()

Changes in V2:
* Fix typo: gernarate -> generate in smis_vol.py.
* Correct document for smis_vol.volume_name_exists:
:param name: Volume ElementName
-> :param volume_name: Volume ElementName
* Fix incorrect variable name in smis_common.SmisCommon.invoke_method():
msg, datetime.datetime.now().isoformat())
-> : cmd, datetime.datetime.now().isoformat())
* Fix typo in smis_common.SmisCommon:
defination -> definition
metioned -> motioned
* Fix incorrect variable in smis.Smis._check_exist_cim_dev_mg():
cim_gmm.path, **in_params)
-> cim_gmms_path, **in_params)
* Add the missing import in smis_ag.py:
LsmError, ErrorNumber

Changes in V3:
* Fix debug_path of smis.Smis.plugin_register().
* PEP8 fix in smis.py.
* Fix traceback log displaying in SmisCommon.invoke_method().
* Pylint fix for smis_ag.py and smis_vol.py(both 10/10 point now):
1. Relative import. Use 'from lsm.plugin.smispy import smis_ag' instead of
'import smis_ag'
2. Add module docstring for smis_ag and smis_vol.
3. Remove unused parameter 'smis_common' of smis_vol.cim_vol_to_lsm_vol().
4. Renamed long method:
* smis_ag._cim_inits_to_lsm_init_id_and_type()
-> smis_ag._init_id_and_type_of()
* smis_vol._vpd83_in_cim_vol_otherinfo_netapp()
-> smis_vol._vpd83_netapp()
5. Renamed short variable name:
* smis_ag._init_id_and_type_of()
rc -> cim_inits
* smis_vol._vpd83_in_cim_vol_name()
nn -> name_space
nf -> name_format
* smis_vol.cim_vol_of_cim_pool_path()
rc -> needed_cim_vols
* smis_ag.cim_init_of_cim_spc_path()
ce -> cim_error
6. Remove unused variable 'ag_init_ids' in smis_ag.cim_spc_to_lsm_ag().
7. Add docstring to these methods:
* smis_ag.cim_init_mg_to_lsm_ag()
* smis_ag.cim_spc_to_lsm_ag()
* smis_vol.vol_id_of_cim_vol()
* smis_vol._vpd83_of_cim_vol()

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 4 +-
plugin/smispy/dmtf.py | 2 +
plugin/smispy/smis.py | 1098 +++++++++++---------------------------
plugin/smispy/smis_ag.py | 205 +++++++
plugin/smispy/smis_cap.py | 46 +-
plugin/smispy/smis_common.py | 281 +++++++---
plugin/smispy/smis_pool.py | 28 +-
plugin/smispy/smis_sys.py | 10 +
plugin/smispy/smis_vol.py | 241 +++++++++
plugin/smispy/utils.py | 23 +-
11 files changed, 1039 insertions(+), 901 deletions(-)
create mode 100644 plugin/smispy/smis_ag.py
create mode 100644 plugin/smispy/smis_vol.py

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 0ef7c16..d7f132d 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -478,6 +478,8 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
%{python_sitelib}/lsm/plugin/smispy/smis_disk.*
+%{python_sitelib}/lsm/plugin/smispy/smis_vol.*
+%{python_sitelib}/lsm/plugin/smispy/smis_ag.*
%{_bindir}/smispy_lsmplugin

%files -n %{libstoragemgmt}-netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index c3084c9..78ceb36 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -31,7 +31,9 @@ smispy_PYTHON = \
smispy/smis_cap.py \
smispy/smis_sys.py \
smispy/smis_pool.py \
- smispy/smis_disk.py
+ smispy/smis_disk.py \
+ smispy/smis_ag.py \
+ smispy/smis_vol.py

nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 576c72e..c44db2f 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -242,3 +242,5 @@ def op_status_list_conv(conv_dict, dmtf_op_status_list,
CTRL_CONF_SRV_DA_RW = Uint16(2)

VOL_OTHER_INFO_NAA_VPD83_TYPE3H = 'NAA;VPD83Type3'
+
+VOL_USAGE_SYS_RESERVED = Uint16(3)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a571d9d..5f44136 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -19,11 +19,8 @@

from string import split
import time
-import traceback
import copy
import os
-import datetime
-import sys
import re

import pywbem
@@ -32,6 +29,8 @@
import smis_sys
import smis_pool
import smis_disk
+from lsm.plugin.smispy import smis_vol
+from lsm.plugin.smispy import smis_ag
import dmtf

from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
@@ -61,8 +60,10 @@
# cim_ip CIM_IPProtocolEndpoint
# cim_eth CIM_EthernetPort
# cim_pe CIM_SCSIProtocolEndpoint
-# cim_gmm CIM_GroupMaskingMappingService
+# cim_gmms CIM_GroupMaskingMappingService
# cim_ccs CIM_ControllerConfigurationService
+# cim_rs CIM_ReplicationService
+# cim_hwms CIM_StorageHardwareIDManagementService
#
# sys Object of LSM System
# pool Object of LSM Pool
@@ -96,15 +97,6 @@ def _lsm_init_id_to_snia(lsm_init_id):
return lsm_init_id


-def _dmtf_init_type_to_lsm(cim_init):
- if 'IDType' in cim_init:
- if cim_init['IDType'] == dmtf.ID_TYPE_WWPN:
- return AccessGroup.INIT_TYPE_WWPN
- elif cim_init['IDType'] == dmtf.ID_TYPE_ISCSI:
- return AccessGroup.INIT_TYPE_ISCSI_IQN
- return AccessGroup.INIT_TYPE_UNKNOWN
-
-
def _lsm_tgt_port_type_of_cim_fc_tgt(cim_fc_tgt):
"""
We are assuming we got CIM_FCPort. Caller should make sure of that.
@@ -139,10 +131,14 @@ class Smis(IStorageAreaNetwork):
_INVOKE_MAX_LOOP_COUNT = 60
_INVOKE_CHECK_INTERVAL = 5

+ _JOB_ERROR_HANDLER = {
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
+ smis_vol.volume_create_error_handler,
+ }
+
def __init__(self):
self._c = None
self.tmo = 0
- self.debug_path = None

def _get_cim_instance_by_id(self, class_type, requested_id,
property_list=None, raise_error=True):
@@ -163,7 +159,8 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
class_name, PropertyList=property_list)
org_requested_id = requested_id
if class_type == 'Job':
- (requested_id, ignore, ignore) = Smis._parse_job_id(requested_id)
+ (requested_id, ignore, ignore) = SmisCommon.parse_job_id(
+ requested_id)
for cim_xxx in cim_xxxs:
if self._id(class_type, cim_xxx) == requested_id:
return cim_xxx
@@ -174,53 +171,6 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))

- def _pi(self, msg, retrieve_data, method_data, rc, out):
- """
- Handle the the process of invoking an operation.
- """
- # Check to see if operation is done
- if rc == SmisCommon.SNIA_INVOKE_OK:
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- return None, self._new_vol_from_name(out)
- else:
- return None, None
-
- elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
- # We have an async operation
- job_id = self._job_id(out['Job'], retrieve_data, method_data)
- return job_id, None
- elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
- raise LsmError(
- ErrorNumber.NO_SUPPORT,
- 'SMI-S error code indicates operation not supported')
- else:
- # When debugging issues with providers it's helpful to have the
- # xml request/reply to give to provider developers.
- try:
- if self.debug_path is not None:
- if not os.path.exists(self.debug_path):
- os.makedirs(self.debug_path)
-
- if os.path.isdir(self.debug_path):
- debug_fn = "%s_%s" % \
- (msg, datetime.datetime.now().isoformat())
- debug_full = os.path.join(self.debug_path, debug_fn)
-
- # Dump the request & reply to a file
- with open(debug_full, 'w') as d:
- d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
- (self._c.last_request, self._c.last_reply))
-
- except Exception:
- tb = traceback.format_exc()
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc) +
- ' Debug data exception: ' + str(tb))
-
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc))
-
@handle_cim_errors
def plugin_register(self, uri, password, timeout, flags=0):
"""
@@ -260,14 +210,13 @@ def plugin_register(self, uri, password, timeout, flags=0):
and u["parameters"]["no_ssl_verify"] == 'yes':
no_ssl_verify = True

- debug = False
+ debug_path = None
if 'debug_path' in u['parameters']:
- self.debug_path = u['parameters']['debug_path']
- debug = True
+ debug_path = u['parameters']['debug_path']

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

self.tmo = timeout

@@ -319,41 +268,53 @@ def job_status(self, job_id, flags=0):
"""
completed_item = None

- props = ['JobState', 'PercentComplete', 'ErrorDescription',
- 'OperationalStatus']
- cim_job_pros = self._property_list_of_id('Job', props)
+ error_handler = None
+
+ (ignore, retrieve_data, method_data) = SmisCommon.parse_job_id(job_id)

- cim_job = self._get_cim_instance_by_id('Job', job_id, cim_job_pros)
+ if retrieve_data in Smis._JOB_ERROR_HANDLER.keys():
+ error_handler = Smis._JOB_ERROR_HANDLER[retrieve_data]
+
+ cim_job_pros = SmisCommon.cim_job_pros()
+ cim_job_pros.extend(
+ ['JobState', 'PercentComplete', 'ErrorDescription',
+ 'OperationalStatus'])
+ cim_job = self._c.cim_job_of_job_id(job_id, cim_job_pros)

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

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

- pc = cim_job['PercentComplete']
- if pc > 100:
- percent_complete = 100
- else:
- percent_complete = pc
+ pc = cim_job['PercentComplete']
+ if pc > 100:
+ percent_complete = 100
+ else:
+ percent_complete = pc

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

- if Smis._job_completed_ok(cim_job):
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- completed_item = self._new_vol_from_job(cim_job)
+ if Smis._job_completed_ok(cim_job):
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
+ retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
+ completed_item = self._new_vol_from_job(cim_job)
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ str(cim_job['ErrorDescription']))
else:
- status = JobStatus.ERROR
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG, str(cim_job['ErrorDescription']))

- else:
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
- self._check_for_dupe_vol(method_data, None)
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- str(cim_job['ErrorDescription']))
+ except Exception:
+ if error_handler is not None:
+ error_handler(self._c, method_data)
+ else:
+ raise

return status, percent_complete, completed_item

@@ -423,25 +384,6 @@ def _sys_id_child(self, cim_xxx):
"""
return self._id('SystemChild', cim_xxx)

- def _vol_id(self, cim_vol):
- """
- Return the MD5 hash of CIM_StorageVolume['SystemName'] and
- ['DeviceID']
- """
- return self._id('Volume', cim_vol)
-
- def _job_id(self, cim_job, retrieve_data, method_data):
- """
- Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
- with '@%s' % retrieve_data
- retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
- SmisCommon.JOB_RETRIEVE_VOLUME or etc
- method_data is any string a method would like store for error
- handling by job_status().
- """
- return "%s@%d@%s" % (
- self._id('Job', cim_job), int(retrieve_data), str(method_data))
-
def _init_id(self, cim_init):
"""
Retrieve Initiator ID from CIM_StorageHardwareID
@@ -481,225 +423,41 @@ def _id(self, class_type, cim_xxx):
else:
return md5(id_str)

- @staticmethod
- def _parse_job_id(job_id):
- """
- job_id is assembled by a md5 string, retrieve_data and method_data
- This method will split it and return
- (md5_str, retrieve_data, method_data)
- """
- tmp_list = job_id.split('@', 3)
- md5_str = tmp_list[0]
- retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
- method_data = None
- if len(tmp_list) == 3:
- retrieve_data = int(tmp_list[1])
- method_data = tmp_list[2]
- return (md5_str, retrieve_data, method_data)
-
- @staticmethod
- def _get_vol_other_id_info(cv):
- other_id = None
-
- if 'OtherIdentifyingInfo' in cv \
- and cv["OtherIdentifyingInfo"] is not None \
- and len(cv["OtherIdentifyingInfo"]) > 0:
-
- other_id = cv["OtherIdentifyingInfo"]
-
- if isinstance(other_id, list):
- other_id = other_id[0]
-
- # This is not what we are looking for if the field has this value
- if other_id is not None and other_id == "VPD83Type3":
- other_id = None
-
- return other_id
-
- def _cim_vol_pros(self):
- """
- Return the PropertyList required for creating new LSM Volume.
- """
- props = ['ElementName', 'NameFormat',
- 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
- 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
- 'OtherNameFormat', 'OtherNameNamespace']
- cim_vol_pros = self._property_list_of_id("Volume", props)
- return cim_vol_pros
-
- def _new_vol(self, cv, pool_id=None, sys_id=None):
- """
- Takes a CIMInstance that represents a volume and returns a lsm Volume
- """
-
- # This is optional (User friendly name)
- if 'ElementName' in cv:
- user_name = cv["ElementName"]
- else:
- #Better fallback value?
- user_name = cv['DeviceID']
-
- vpd_83 = Smis._vpd83_in_cv_name(cv)
- if vpd_83 is None:
- vpd_83 = Smis._vpd83_in_cv_otherinfo(cv)
- if vpd_83 is None:
- vpd_83 = Smis._vpd83_in_cv_otherinfo_netapp(cv)
-
- if vpd_83 and re.match('^[a-fA-F0-9]{32}$', vpd_83) and \
- vpd_83[0] == '6':
- vpd_83 = vpd_83.lower()
- else:
- vpd_83 = ''
-
- #This is a fairly expensive operation, so it's in our best interest
- #to not call this very often.
- if pool_id is None:
- #Go an retrieve the pool id
- pool_id = smis_pool.pool_id_of_cim_vol(self._c, cv.path)
-
- if sys_id is None:
- sys_id = cv['SystemName']
-
- admin_state = Volume.ADMIN_STATE_ENABLED
-
- return Volume(self._vol_id(cv), user_name, vpd_83, cv["BlockSize"],
- cv["NumberOfBlocks"], admin_state, sys_id, pool_id)
-
- @staticmethod
- def _vpd83_in_cv_name(cv):
- """
- We require NAA Type 3 VPD83 address:
- Only this is allowed when storing VPD83 in cv["Name"]:
- * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
- """
- if not ('NameFormat' in cv and
- 'NameNamespace' in cv and
- 'Name' in cv):
- return None
- nf = cv['NameFormat']
- nn = cv['NameNamespace']
- name = cv['Name']
- if not (nf and nn and name):
- return None
-
- if nf == dmtf.VOL_NAME_FORMAT_NNA and \
- nn == dmtf.VOL_NAME_SPACE_VPD83_TYPE3:
- return name
-
- @staticmethod
- def _vpd83_in_cv_otherinfo(cv):
- """
- IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
- Will return the vpd_83 value if found
- """
- if not ("IdentifyingDescriptions" in cv and
- "OtherIdentifyingInfo" in cv):
- return None
-
- id_des = cv["IdentifyingDescriptions"]
- other_info = cv["OtherIdentifyingInfo"]
- if not (isinstance(cv["IdentifyingDescriptions"], list) and
- isinstance(cv["OtherIdentifyingInfo"], list)):
- return None
-
- index = 0
- len_id_des = len(id_des)
- len_other_info = len(other_info)
- while index < min(len_id_des, len_other_info):
- if dmtf.VOL_OTHER_INFO_NAA_VPD83_TYPE3H == id_des[index]:
- return other_info[index]
- index += 1
- return None
-
- @staticmethod
- def _vpd83_in_cv_otherinfo_netapp(cv):
- # workaround for NetApp, they use OtherNameNamespace and
- # OtherNameFormat.
- if 'OtherNameFormat' in cv and \
- cv['OtherNameFormat'] == 'NAA' and \
- 'OtherNameNamespace' in cv and \
- cv['OtherNameNamespace'] == 'VPD83Type3' and \
- 'OtherIdentifyingInfo' in cv and \
- isinstance(cv["OtherIdentifyingInfo"], list) and \
- len(cv['OtherIdentifyingInfo']) == 1:
- return cv['OtherIdentifyingInfo'][0]
-
def _new_vol_from_name(self, out):
"""
Given a volume by CIMInstanceName, return a lsm Volume object
"""
- instance = None
+ cim_vol = None
+ cim_vol_pros = smis_vol.cim_vol_pros()

if 'TheElement' in out:
- instance = self._c.GetInstance(out['TheElement'],
- LocalOnly=False)
+ cim_vol = self._c.GetInstance(
+ out['TheElement'],
+ PropertyList=cim_vol_pros)
elif 'TargetElement' in out:
- instance = self._c.GetInstance(out['TargetElement'],
- LocalOnly=False)
-
- return self._new_vol(instance)
-
- def _cim_spc_pros(self):
- """
- Return a list of properties required to build new AccessGroup.
- """
- cim_spc_pros = ['DeviceID']
- cim_spc_pros.extend(self._property_list_of_id('SystemChild'))
- cim_spc_pros.extend(['ElementName', 'StorageID'])
- cim_spc_pros.extend(['EMCAdapterRole']) # EMC specific, used to
- # filter out the mapping SPC.
- return cim_spc_pros
-
- def _cim_inits_to_lsm(self, cim_inits):
- """
- Retrieve AccessGroup.init_ids and AccessGroup.init_type from
- a list of CIM_StorageHardwareID.
- """
- init_ids = []
- init_type = AccessGroup.INIT_TYPE_UNKNOWN
- init_types = []
- for cim_init in cim_inits:
- init_type = _dmtf_init_type_to_lsm(cim_init)
- if init_type == AccessGroup.INIT_TYPE_WWPN:
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- elif init_type == AccessGroup.INIT_TYPE_ISCSI_IQN:
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- # Skip if not a iscsi initiator IQN or WWPN.
- continue
-
- init_type_dict = {}
- for cur_init_type in init_types:
- init_type_dict[cur_init_type] = 1
-
- if len(init_type_dict) == 1:
- init_type = init_types[0]
- elif len(init_type_dict) == 2:
- init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
- return (init_ids, init_type)
-
- def _cim_spc_to_lsm(self, cim_spc, system_id=None):
- if system_id is None:
- system_id = self._sys_id_child(cim_spc)
- ag_id = md5(cim_spc['DeviceID'])
- ag_name = cim_spc['ElementName']
- ag_init_ids = []
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- sys_id = self._sys_id_child(cim_spc)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, sys_id)
+ cim_vol = self._c.GetInstance(
+ out['TargetElement'],
+ PropertyList=cim_vol_pros)
+
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+
+ return smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id)

def _new_vol_from_job(self, job):
"""
Given a concrete job instance, return referenced volume as lsm volume
"""
- for a in self._c.Associators(job.path,
- AssocClass='CIM_AffectedJobElement',
- ResultClass='CIM_StorageVolume'):
- return self._new_vol(self._c.GetInstance(a.path, LocalOnly=False))
+ cim_vol_pros = smis_vol.cim_vol_pros()
+ cim_vols = self._c.Associators(
+ job.path,
+ AssocClass='CIM_AffectedJobElement',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=cim_vol_pros)
+ for cim_vol in cim_vols:
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ return smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id)
return None

@handle_cim_errors
@@ -726,7 +484,7 @@ def volumes(self, search_key=None, search_value=None, flags=0):
rc = []
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()
for cim_sys in cim_syss:
sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
pool_pros = smis_pool.cim_pool_id_pros()
@@ -734,20 +492,11 @@ def volumes(self, search_key=None, search_value=None, flags=0):
self._c, cim_sys.path, pool_pros)
for cim_pool in cim_pools:
pool_id = smis_pool.pool_id_of_cim_pool(cim_pool)
- cim_vols = self._c.Associators(
- cim_pool.path,
- AssocClass='CIM_AllocatedFromStoragePool',
- ResultClass='CIM_StorageVolume',
- PropertyList=cim_vol_pros)
+ cim_vols = smis_vol.cim_vol_of_cim_pool_path(
+ self._c, cim_pool.path, cim_vol_pros)
for cim_vol in cim_vols:
- # Exclude those volumes which are reserved for system
- if 'Usage' in cim_vol:
- if cim_vol['Usage'] != 3:
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
- else:
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id))
return search_property(rc, search_key, search_value)

@handle_cim_errors
@@ -789,51 +538,6 @@ def systems(self, flags=0):

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

- def _volume_exists(self, name):
- """
- Try to minimize time to search.
- :param name: Volume ElementName
- :return: True if volume exists with 'name', else False
- """
- all_cim_vols = self._c.EnumerateInstances(
- 'CIM_StorageVolume', PropertyList=['ElementName'])
- for exist_cim_vol in all_cim_vols:
- if name == exist_cim_vol['ElementName']:
- return True
- return False
-
- def _check_for_dupe_vol(self, volume_name, original_exception):
- """
- Throw original exception or NAME_CONFLICT if volume name found
- :param volume_name: Volume to check for
- :original_exception Info grabbed from sys.exec_info
- :return:
- if original_exception == None, will not raise any error if not
- NAME_CONFLICT, just return None.
- """
- report_original = True
-
- # Check to see if we already have a volume with this name. If we
- # do we will assume that this is the cause of it. We will hide
- # any errors that happen during this check and just report the
- # original error if we can't determine if we have a duplicate
- # name.
-
- try:
- report_original = not self._volume_exists(volume_name)
- except Exception:
- # Don't report anything here on a failing
- pass
-
- if report_original:
- if original_exception is None:
- return
- raise original_exception[1], None, original_exception[2]
- else:
- raise LsmError(ErrorNumber.NAME_CONFLICT,
- "Volume with name '%s' already exists!" %
- volume_name)
-
@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
flags=0):
@@ -860,8 +564,8 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
if provisioning == Volume.PROVISION_FULL and \
Pool.ELEMENT_TYPE_VOLUME_FULL & pool.element_type:
dmtf_element_type = dmtf.ELEMENT_THICK_VOLUME
- elif provisioning == Volume.PROVISION_THIN and \
- Pool.ELEMENT_TYPE_VOLUME_THIN & pool.element_type:
+ elif (provisioning == Volume.PROVISION_THIN and
+ Pool.ELEMENT_TYPE_VOLUME_THIN & pool.element_type):
dmtf_element_type = dmtf.ELEMENT_THIN_VOLUME
else:
raise LsmError(
@@ -870,8 +574,8 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
"requested provisioning type")

# Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(pool.system_id)
+
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
self._c, pool)

@@ -880,15 +584,16 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
'InPool': cim_pool_path,
'Size': pywbem.Uint64(size_bytes)}

- try:
- return self._pi("volume_create",
- SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
- volume_name,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
- except CIMError:
- self._check_for_dupe_vol(volume_name, sys.exc_info())
+ error_handler = Smis._JOB_ERROR_HANDLER[
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
+
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params,
+ out_handler=self._new_vol_from_name,
+ error_handler=error_handler,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
+ method_data=volume_name)

def _poll(self, msg, job):
if job:
@@ -907,18 +612,13 @@ def _poll(self, msg, job):

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

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

- job_id = self._pi("_detach",
- SmisCommon.JOB_RETRIEVE_NONE,
- None,
- *(self._c.InvokeMethod(
- 'ModifySynchronization', scs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifySynchronization', cim_scs.path, in_params)[0]

self._poll("ModifySynchronization, detach", job_id)

@@ -926,17 +626,14 @@ def _detach(self, vol, sync):
if self._c.is_netappe():
return self._detach_netapp_e(vol, sync)

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

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

- job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE, None,
- *(self._c.InvokeMethod(
- 'ModifyReplicaSynchronization', rs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifyReplicaSynchronization', cim_rs.path, in_params)[0]

self._poll("ModifyReplicaSynchronization, detach", job_id)

@@ -950,15 +647,14 @@ def _cim_name_match(a, b):
else:
return False

- def _deal_volume_associations_netappe(self, vol, lun):
+ def _deal_volume_associations_netappe(self, vol, cim_vol_path):
"""
Check a volume to see if it has any associations with other
volumes.
"""
rc = False
- lun_path = lun.path

- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')

if len(ss):
@@ -966,31 +662,29 @@ def _deal_volume_associations_netappe(self, vol, lun):
if 'SyncedElement' in s:
item = s['SyncedElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)
rc = True

if 'SystemElement' in s:
item = s['SystemElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)
rc = True

return rc

- def _deal_volume_associations(self, vol, lun):
+ def _deal_volume_associations(self, vol, cim_vol_path):
"""
Check a volume to see if it has any associations with other
volumes and deal with them.
"""
if self._c.is_netappe():
- return self._deal_volume_associations_netappe(vol, lun)
-
- lun_path = lun.path
+ return self._deal_volume_associations_netappe(vol, cim_vol_path)

try:
- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')
except pywbem.CIMError as e:
if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
@@ -1021,38 +715,35 @@ def _deal_volume_associations(self, vol, lun):
if 'SyncedElement' in s:
item = s['SyncedElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)

if 'SystemElement' in s:
item = s['SystemElement']

- if Smis._cim_name_match(item, lun_path):
+ if Smis._cim_name_match(item, cim_vol_path):
self._detach(vol, s)

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

#If we actually have an association to delete, the volume will be
#deleted with the association, no need to call ReturnToStoragePool
- if not self._deal_volume_associations(volume, lun):
- in_params = {'TheElement': lun.path}
+ if not self._deal_volume_associations(volume, cim_vol_path):
+ in_params = {'TheElement': cim_vol_path}

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

#Loop to check to see if volume is actually gone yet!
try:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
- while lun is not None:
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=[])
+ while cim_vol is not None:
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=[])
time.sleep(0.125)
- except LsmError as e:
+ except (LsmError, CIMError) as e:
pass

@handle_cim_errors
@@ -1060,37 +751,34 @@ def volume_delete(self, volume, flags=0):
"""
Delete a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

- self._deal_volume_associations(volume, lun)
+ self._deal_volume_associations(volume, cim_vol_path)

- in_params = {'TheElement': lun.path}
+ in_params = {'TheElement': cim_vol_path}

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

@handle_cim_errors
def volume_resize(self, volume, new_size_bytes, flags=0):
"""
Re-size a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

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

- return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params, retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

def _get_supported_sync_and_mode(self, system_id, rep_type):
"""
@@ -1100,12 +788,11 @@ def _get_supported_sync_and_mode(self, system_id, rep_type):
"""
rc = [None, None]

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

- if rs:
+ if cim_rs:
rs_cap = self._c.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_ReplicationServiceCapabilities')[0]

@@ -1152,13 +839,12 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
or rep_type == Volume.REPLICATE_MIRROR_SYNC:
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")

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

# Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
# ElementName, we have to do pre-check here.
- if self._volume_exists(name):
+ if smis_vol.volume_name_exists(self._c, name):
raise LsmError(ErrorNumber.NAME_CONFLICT,
"Volume with name '%s' already exists!" % name)

@@ -1166,9 +852,10 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
if pool is not None:
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)

- lun = self._get_cim_instance_by_id('Volume', volume_src.id)
+ src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
+ self._c, volume_src)

- if rs:
+ if cim_rs:
method = 'CreateElementReplica'

sync, mode = self._get_supported_sync_and_mode(
@@ -1177,7 +864,7 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
in_params = {'ElementName': name,
'SyncType': sync,
#'Mode': mode,
- 'SourceElement': lun.path,
+ 'SourceElement': src_cim_vol_path,
'WaitForCopyState': dmtf.COPY_STATE_SYNC}

else:
@@ -1186,9 +873,8 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
method = 'CreateReplica'

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

ct = Volume.REPLICATE_CLONE
if rep_type == Volume.REPLICATE_CLONE:
@@ -1202,21 +888,20 @@ def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):

in_params = {'ElementName': name,
'CopyType': ct,
- 'SourceElement': lun.path}
- if rs:
+ 'SourceElement': src_cim_vol_path}
+ if cim_rs:

if cim_pool_path is not None:
in_params['TargetPool'] = cim_pool_path

- return self._pi("volume_replicate",
- SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(method,
- rs.path, **in_params)))
+ return self._c.invoke_method(
+ method, cim_rs.path, in_params,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)

raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")

- def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
+ def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
vol_id):
rc = SmisCommon.SNIA_INVOKE_FAILED
out = None
@@ -1228,12 +913,12 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,

cim_dev_mg_path = None
try:
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
except CIMError as ce:
if ce[0] == pywbem.CIM_ERR_FAILED:
cim_dev_mg_path = self._check_exist_cim_dev_mg(
- name, cim_gmm_path, cim_vol_path, vol_id)
+ name, cim_gmms_path, cim_vol_path, vol_id)
if cim_dev_mg_path is None:
raise
else:
@@ -1245,7 +930,7 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,

return cim_dev_mg_path

- def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
+ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
init_type):
"""
Create CIM_TargetMaskingGroup
@@ -1276,7 +961,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,

cim_tgt_mg_path = None
try:
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
except CIMError as ce:
if ce[0] == pywbem.CIM_ERR_FAILED:
@@ -1293,7 +978,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,

return cim_tgt_mg_path

- def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
+ def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
cim_tgt_mg_path, cim_dev_mg_path, name):
in_params = {
'ElementName': name,
@@ -1302,7 +987,7 @@ def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
'DeviceMaskingGroup': cim_dev_mg_path,
}

- (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmms_path,
**in_params)

return self._wait_invoke(
@@ -1324,10 +1009,11 @@ def _volume_mask_group(self, access_group, volume, flags=0):
"""
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)

- cim_init_mg = self._cim_init_mg_of_id(access_group.id,
- raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path)
+ cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
@@ -1342,42 +1028,39 @@ def _volume_mask_group(self, access_group, volume, flags=0):
"access group init_type: %d" %
access_group.init_type)

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'],
- raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

if len(cim_spcs_path) == 0:
# We have to create the SPC and dev_mg now.
cim_tgt_mg_path = self._cim_tgt_mg_path_create(
- cim_sys.path, cim_gmm_path, access_group.name,
+ cim_sys.path, cim_gmms.path, access_group.name,
access_group.init_type)
cim_dev_mg_path = self._cim_dev_mg_path_create(
- cim_gmm_path, access_group.name, cim_vol.path, volume.id)
+ cim_gmms.path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
- cim_gmm_path, cim_init_mg.path, cim_tgt_mg_path,
+ cim_gmms.path, cim_init_mg_path, cim_tgt_mg_path,
cim_dev_mg_path, access_group.name)
else:
# CIM_InitiatorMaskingGroup might have multiple SPC when having
# many tgt_mg. It's seldom use, but possible.
for cim_spc_path in cim_spcs_path:
# Check whether already masked
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
for cur_cim_vol in cim_vols:
- if self._vol_id(cur_cim_vol) == volume.id:
+ if smis_vol.vol_id_of_cim_vol(cur_cim_vol) == volume.id:
# Masked.
return None

@@ -1388,11 +1071,11 @@ def _volume_mask_group(self, access_group, volume, flags=0):
ResultClass='CIM_DeviceMaskingGroup')[0]
in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None

@@ -1413,30 +1096,27 @@ def volume_mask(self, access_group, volume, flags=0):
return self._volume_mask_old(access_group, volume, flags)

def _volume_mask_old(self, access_group, volume, flags):
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_inits = self._cim_init_of_spc(cim_spc.path)
+ cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc_path)
if len(cim_inits) == 0:
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
access_group.id +
"will not do volume_mask()")

- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_css_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

in_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path],
+ 'ProtocolControllers': [cim_spc_path],
'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}

(rc, out) = self._c.InvokeMethod(
'ExposePaths',
- cim_css_path, **in_params)
+ cim_ccs.path, **in_params)
self._wait_invoke(rc, out)
return None

@@ -1447,11 +1127,10 @@ def _volume_unmask_group(self, access_group, volume):
If SupportedDeviceGroupFeatures does not allow empty
DeviceMaskingGroup in SPC, we remove SPC and DeviceMaskingGroup.
"""
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)

- cim_gmm_cap = self._c.Associators(
+ cim_gmms_cap = self._c.Associators(
cim_sys.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_GroupMaskingMappingCapabilities',
@@ -1462,14 +1141,14 @@ def _volume_unmask_group(self, access_group, volume):
flag_empty_dev_in_spc = False

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

if flag_empty_dev_in_spc is False:
if ((dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedSynchronousActions']) and
+ cim_gmms_cap['SupportedSynchronousActions']) and
(dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedAsynchronousActions'])):
+ cim_gmms_cap['SupportedAsynchronousActions'])):
raise LsmError(
ErrorNumber.NO_SUPPORT,
"volume_unmask() not supported. It requires one of these "
@@ -1477,11 +1156,10 @@ def _volume_unmask_group(self, access_group, volume):
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(volume.system_id)

cim_spcs_path = self._c.AssociatorNames(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController')
if len(cim_spcs_path) == 0:
@@ -1524,16 +1202,16 @@ def _volume_unmask_group(self, access_group, volume):
}
(rc, out) = self._c.InvokeMethod(
'DeleteMaskingView',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)

in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)

return None
@@ -1552,27 +1230,24 @@ def volume_unmask(self, access_group, volume, flags=0):
return self._volume_unmask_old(access_group, volume)

def _volume_unmask_old(self, access_group, volume):
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)

- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id,
- property_list=['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

hide_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}

- (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs_path,
+ (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)
self._wait_invoke(rc, out)

return None

def _is_access_group(self, cim_spc):
- if self._c.is_netappe:
+ if self._c.is_netappe():
return True

rc = True
@@ -1588,55 +1263,24 @@ def _is_access_group(self, cim_spc):
rc = False
return rc

- def _cim_spc_of_id(self, access_group_id, property_list=None,
- raise_error=False):
- """
- Return CIMInstance of CIM_SCSIProtocolController
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- if property_list is None:
- property_list = ['DeviceID']
- else:
- property_list = merge_list(property_list, ['DeviceID'])
-
- cim_spcs = self._c.EnumerateInstances(
- 'CIM_SCSIProtocolController', PropertyList=property_list)
-
- for cim_spc in cim_spcs:
- if md5(cim_spc['DeviceID']) == access_group_id:
- return cim_spc
-
- if raise_error is True:
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
- def _cim_spc_of(self, cim_sys_path, property_list=None):
+ def _cim_spc_of(self, system_id, property_list=None):
"""
Return a list of CIM_SCSIProtocolController.
Following SNIA SMIS 'Masking and Mapping Profile':
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_ControllerConfigurationService
|
| CIM_ConcreteDependency
v
CIM_SCSIProtocolController
"""
- cim_ccss_path = []
+ cim_ccs = None
rc_cim_spcs = []

if property_list is None:
property_list = []

try:
- cim_ccss_path = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(system_id, raise_error=False)
except CIMError as ce:
error_code = tuple(ce)[0]
if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
@@ -1644,19 +1288,12 @@ def _cim_spc_of(self, cim_sys_path, property_list=None):
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported ' +
'by this array')
- cim_ccs_path = None
- if len(cim_ccss_path) == 1:
- cim_ccs_path = cim_ccss_path[0]
- elif len(cim_ccss_path) == 0:
+ if cim_ccs is None:
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Got %d instance of " % len(cim_ccss_path) +
- "ControllerConfigurationService from %s" %
- cim_sys_path + " in _cim_spc_of()")
+
cim_spcs = self._c.Associators(
- cim_ccs_path,
+ cim_ccs.path,
AssocClass='CIM_ConcreteDependency',
ResultClass='CIM_SCSIProtocolController',
PropertyList=property_list)
@@ -1665,82 +1302,11 @@ def _cim_spc_of(self, cim_sys_path, property_list=None):
rc_cim_spcs.append(cim_spc)
return rc_cim_spcs

- def _cim_init_of_spc(self, cim_spc_path, property_list=None):
- """
- Take CIM_SCSIProtocolController and return a list of
- CIM_StorageHardwareID, both are CIMInstance.
- Two ways to get StorageHardwareID from SCSIProtocolController:
- * Method A (defined in SNIA SMIS 1.6):
- CIM_SCSIProtocolController
- |
- | CIM_AssociatedPrivilege
- v
- CIM_StorageHardwareID
-
- * Method B (defined in SNIA SMIS 1.3, 1.4, 1.5 and 1.6):
- CIM_SCSIProtocolController
- |
- | CIM_AuthorizedTarget
- v
- CIM_AuthorizedPrivilege
- |
- | CIM_AuthorizedSubject
- v
- CIM_StorageHardwareID
-
- Method A defined in SNIA SMIS 1.6 deprecated the Method B and Method A
- saved 1 query which provide better performance.
- Hence we try method A.
- Maybe someday, we will stop trying after knowing array's supported
- SMIS version.
- """
- cim_inits = []
- if property_list is None:
- property_list = []
-
- if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_6,
- raise_error=False):
- return self._c.Associators(
- cim_spc_path,
- AssocClass='CIM_AssociatedPrivilege',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
- else:
- cim_aps_path = self._c.AssociatorNames(
- cim_spc_path,
- AssocClass='CIM_AuthorizedTarget',
- ResultClass='CIM_AuthorizedPrivilege')
- for cim_ap_path in cim_aps_path:
- cim_inits.extend(self._c.Associators(
- cim_ap_path,
- AssocClass='CIM_AuthorizedSubject',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list))
- return cim_inits
-
- def _cim_init_of_init_mg(self, cim_init_mg_path, property_list=None):
- """
- Use this association:
- CIM_InitiatorMaskingGroup
- |
- | CIM_MemberOfCollection
- v
- CIM_StorageHardwareID
- """
- if property_list is None:
- property_list = []
- return self._c.Associators(
- cim_init_mg_path,
- AssocClass='CIM_MemberOfCollection',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
-
@handle_cim_errors
def volumes_accessible_by_access_group(self, access_group, flags=0):
mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vols = []
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
@@ -1750,11 +1316,11 @@ def volumes_accessible_by_access_group(self, access_group, flags=0):
mask_type = smis_cap.MASK_TYPE_MASK

if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

@@ -1766,21 +1332,26 @@ def volumes_accessible_by_access_group(self, access_group, flags=0):
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros))
else:
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)
cim_vols = self._c.Associators(
- cim_spc.path,
+ cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
-
- return [self._new_vol(v) for v in cim_vols]
+ rc = []
+ for cim_vol in cim_vols:
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id))
+ return rc

@handle_cim_errors
def access_groups_granted_to_volume(self, volume, flags=0):
rc = []
mask_type = smis_cap.mask_type(self._c, raise_error=True)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)

# Workaround for EMC VNX/CX
if mask_type == smis_cap.MASK_TYPE_GROUP:
@@ -1792,64 +1363,39 @@ def access_groups_granted_to_volume(self, volume, flags=0):
if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_spc_pros = []
else:
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()

cim_spcs = self._c.Associators(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController',
PropertyList=cim_spc_pros)

if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
for cim_spc in cim_spcs:
cim_init_mgs = self._c.Associators(
cim_spc.path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, volume.system_id)
- for x in cim_init_mgs))
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, x, volume.system_id)
+ for x in cim_init_mgs))
else:
for cim_spc in cim_spcs:
if self._is_access_group(cim_spc):
- rc.extend(
- [self._cim_spc_to_lsm(cim_spc, volume.system_id)])
+ rc.append(
+ smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, volume.system_id))

return rc

- def _cim_init_mg_of_id(self, access_group_id, property_list=None,
- raise_error=False):
- """
- Return CIMInstance of CIM_InitiatorMaskingGroup
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- if property_list is None:
- property_list = ['InstanceID']
- else:
- property_list = merge_list(property_list, ['InstanceID'])
-
- cim_init_mgs = self._c.EnumerateInstances(
- 'CIM_InitiatorMaskingGroup', PropertyList=property_list)
-
- for cim_init_mg in cim_init_mgs:
- if md5(cim_init_mg['InstanceID']) == access_group_id:
- return cim_init_mg
-
- if raise_error is True:
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
- def _cim_init_mg_of(self, cim_sys_path, property_list=None):
+ def _cim_init_mg_of(self, system_id, property_list=None):
"""
- There is no CIM_ComputerSystem association to
- CIM_InitiatorMaskingGroup, we use this association:
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
+ We use this association to get all CIM_InitiatorMaskingGroup:
CIM_GroupMaskingMappingService
|
| CIM_ServiceAffectsElement
@@ -1859,11 +1405,10 @@ def _cim_init_mg_of(self, cim_sys_path, property_list=None):
if property_list is None:
property_list = []

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system_id)

return self._c.Associators(
- cim_gmm_path,
+ cim_gmms.path,
AssocClass='CIM_ServiceAffectsElement',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)
@@ -1876,7 +1421,7 @@ def access_groups(self, search_key=None, search_value=None, flags=0):
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)

- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
for cim_sys in cim_syss:
if cim_sys.path.classname == 'Clar_StorageSystem':
# Workaround for EMC VNX/CX.
@@ -1886,16 +1431,19 @@ def access_groups(self, search_key=None, search_value=None, flags=0):

system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
if mask_type == smis_cap.MASK_TYPE_GROUP:
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
- cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
- for x in cim_init_mgs))
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mgs = self._cim_init_mg_of(
+ system_id, cim_init_mg_pros)
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(self._c, x, system_id)
+ for x in cim_init_mgs))
elif mask_type == smis_cap.MASK_TYPE_MASK:
- cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
+ cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
rc.extend(
- list(self._cim_spc_to_lsm(cim_spc, system_id)
- for cim_spc in cim_spcs))
+ list(
+ smis_ag.cim_spc_to_lsm_ag(self._c, cim_spc, system_id)
+ for cim_spc in cim_spcs))
else:
raise LsmError(ErrorNumber.PLUGIN_BUG,
"_get_cim_spc_by_id(): Got invalid mask_type: "
@@ -1903,7 +1451,7 @@ def access_groups(self, search_key=None, search_value=None, flags=0):

return search_property(rc, search_key, search_value)

- def _cim_init_path_check_or_create(self, cim_sys_path, init_id, init_type):
+ def _cim_init_path_check_or_create(self, system_id, init_id, init_type):
"""
Check whether CIM_StorageHardwareID exists, if not, create new one.
"""
@@ -1920,23 +1468,21 @@ def _cim_init_path_check_or_create(self, cim_sys_path, init_id, init_type):
"SMI-S Plugin does not support init_type %d" %
init_type)

- return self._cim_init_path_create(
- cim_sys_path, init_id, dmtf_id_type)
+ return self._cim_init_path_create(system_id, init_id, dmtf_id_type)

- def _cim_init_path_create(self, cim_sys_path, init_id, dmtf_id_type):
+ def _cim_init_path_create(self, system_id, init_id, dmtf_id_type):
"""
Create a CIM_StorageHardwareID.
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_StorageHardwareIDManagementService')
+ cim_hwms = self._c.cim_hwms_of_sys_id(system_id)

in_params = {'StorageID': init_id,
'IDType': pywbem.Uint16(dmtf_id_type)}

(rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- cim_hw_srv_path, **in_params)
+ cim_hwms.path, **in_params)
# CreateStorageHardwareID does not allow ASYNC
return self._wait_invoke(
rc, out, out_key='HardwareID',
@@ -1951,12 +1497,11 @@ def _ag_init_add_group(self, access_group, init_id, init_type):
"new initiator which is not supported by LSM yet. "
"Please do it via EMC vendor specific tools.")

- cim_init_mg = self._cim_init_mg_of_id(access_group.id)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)

# Check whether already added.
for exist_cim_init in exist_cim_inits:
@@ -1964,27 +1509,26 @@ def _ag_init_add_group(self, access_group, init_id, init_type):
return copy.deepcopy(access_group)

cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ access_group.system_id, init_id, init_type)

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)

new_cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
expect_class='CIM_InitiatorMaskingGroup')
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
new_cim_init_mg = self._c.GetInstance(
new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
LocalOnly=False)
- return self._cim_init_mg_to_lsm(
- new_cim_init_mg, access_group.system_id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, new_cim_init_mg, access_group.system_id)

@handle_cim_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
@@ -2009,11 +1553,11 @@ def _ag_init_add_old(self, access_group, init_id, init_type):
"Please do it via EMC vendor specific tools. "
"EMC VNX does not support adding iSCSI IQN neither")

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)

- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_spc_path(
+ self._c, cim_spc_path)

for exist_cim_init in exist_cim_inits:
if self._init_id(exist_cim_init) == init_id:
@@ -2022,39 +1566,35 @@ def _ag_init_add_old(self, access_group, init_id, init_type):
# Check to see if we have this initiator already, if not we
# create it and then add to the view.

- self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)
+ self._cim_init_path_check_or_create(
+ access_group.system_id, init_id, init_type)

- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

in_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}

(rc, out) = self._c.InvokeMethod('ExposePaths',
- cim_ccs_path, **in_params)
+ cim_ccs.path, **in_params)
cim_spc_path = self._wait_invoke(
rc, out, out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')

- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
cim_spc = self._c.GetInstance(
cim_spc_path, PropertyList=cim_spc_pros, LocalOnly=False)
- return self._cim_spc_to_lsm(cim_spc, access_group.system_id)
+ return smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, access_group.system_id)

def _ag_init_del_group(self, access_group, init_id):
"""
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True, property_list=cim_init_mg_pros)
-
- cim_init_pros = self._property_list_of_id('Initiator')
- cur_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, property_list=cim_init_pros)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
+ cur_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)

cim_init = None
for cur_cim_init in cur_cim_inits:
@@ -2072,21 +1612,25 @@ def _ag_init_del_group(self, access_group, init_id):
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")

- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

# RemoveMembers from InitiatorMaskingGroup
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init.path],
}

(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
- return self._cim_init_mg_to_lsm(
- cim_init_mg, access_group.system_id)
+
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mg = self._c.GetInstance(
+ cim_init_mg_path, PropertyList=cim_init_mg_pros)
+
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, cim_init_mg, access_group.system_id)

@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, init_type,
@@ -2107,17 +1651,14 @@ def access_group_initiator_delete(self, access_group, init_id, init_type,
return self._ag_init_del_old(access_group, init_id)

def _ag_init_del_old(self, access_group, init_id):
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)

- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)

hide_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
(rc, out) = self._c.InvokeMethod(
- 'HidePaths', cim_ccs_path, **hide_params)
+ 'HidePaths', cim_ccs.path, **hide_params)

self._wait_invoke(rc, out)
return None
@@ -2127,8 +1668,7 @@ def job_free(self, job_id, flags=0):
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id,
- ['DeleteOnCompletion'])
+ cim_job = self._c.cim_job_of_job_id(job_id, ['DeleteOnCompletion'])

# See if we should delete the job
if not cim_job['DeleteOnCompletion']:
@@ -2509,18 +2049,6 @@ def target_ports(self, search_key=None, search_value=None, flags=0):

return search_property(rc, search_key, search_value)

- def _cim_init_mg_pros(self):
- return ['ElementName', 'InstanceID']
-
- def _cim_init_mg_to_lsm(self, cim_init_mg, system_id):
- ag_name = cim_init_mg['ElementName']
- ag_id = md5(cim_init_mg['InstanceID'])
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
-
def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
flag_out_array=False,):
"""
@@ -2615,7 +2143,7 @@ def _check_exist_cim_tgt_mg(self, name):

return None

- def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
+ def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
vol_id):
"""
This is buggy check, but it works on EMC VMAX which is only supported
@@ -2632,14 +2160,14 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
break
if cim_dev_mg:
# Check whether cim_vol included.
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_dev_mg.path,
AssocClass='CIM_OrderedMemberOfCollection',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
for cim_vol in cim_vols:
- if self._vol_id(cim_vol) == vol_id:
+ if smis_vol.vol_id_of_cim_vol(cim_vol) == vol_id:
return cim_dev_mg.path

# We should add this volume to found DeviceMaskingGroup
@@ -2649,7 +2177,7 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms_path, **in_params)
self._wait_invoke(rc, out)
return cim_dev_mg.path

@@ -2705,21 +2233,20 @@ def access_group_create(self, name, init_id, init_type, system,
"iSCSI IQN access group")

cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ system.id, init_id, init_type)

# Create CIM_InitiatorMaskingGroup
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system.id)

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

- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()

try:
(rc, out) = self._c.InvokeMethod(
- 'CreateGroup', cim_gmm_path, **in_params)
+ 'CreateGroup', cim_gmms.path, **in_params)

cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
@@ -2739,8 +2266,8 @@ def access_group_create(self, name, init_id, init_type, system,
if len(exist_cim_init_mgs) != 0:
for exist_cim_init_mg in exist_cim_init_mgs:
if exist_cim_init_mg['ElementName'] == name:
- return self._cim_init_mg_to_lsm(
- exist_cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, exist_cim_init_mg, system.id)

# Name does not match.
raise LsmError(ErrorNumber.EXISTS_INITIATOR,
@@ -2753,7 +2280,7 @@ def access_group_create(self, name, init_id, init_type, system,
# Since 1) already checked whether any group containing
# requested init_id, now, it's surly a conflict.
exist_cim_init_mgs = self._cim_init_mg_of(
- cim_sys.path, property_list=['ElementName'])
+ system.id, property_list=['ElementName'])
for exist_cim_init_mg in exist_cim_init_mgs:
if exist_cim_init_mg['ElementName'] == name:
raise LsmError(ErrorNumber.NAME_CONFLICT,
@@ -2764,7 +2291,7 @@ def access_group_create(self, name, init_id, init_type, system,

cim_init_mg = self._c.GetInstance(
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
- return self._cim_init_mg_to_lsm(cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(self._c, cim_init_mg, system.id)

@handle_cim_errors
def access_group_delete(self, access_group, flags=0):
@@ -2772,12 +2299,12 @@ def access_group_delete(self, access_group, flags=0):
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
raise_error=True)

- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)

# Check whether still have volume masked.
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')

@@ -2790,17 +2317,14 @@ def access_group_delete(self, access_group, flags=0):
"Access Group %s has volume masked" %
access_group.id)

- cim_gmm_path = self._c.AssociatorNames(
- cim_init_mg.path,
- AssocClass='CIM_ServiceAffectsElement',
- ResultClass='CIM_GroupMaskingMappingService')[0]
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)

in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Force': True,
}

- (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmms.path,
**in_params)

self._wait_invoke(rc, out)
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
new file mode 100644
index 0000000..43aa7ac
--- /dev/null
+++ b/plugin/smispy/smis_ag.py
@@ -0,0 +1,205 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author: Gris Ge <***@redhat.com>
+
+"""
+This module intend to provide independent methods for lsm.AccessGroup and
+volume masking/unmasking.
+"""
+
+from pywbem import CIMError, CIM_ERR_NOT_FOUND
+
+from lsm import AccessGroup, md5, LsmError, ErrorNumber
+
+from lsm.plugin.smispy.smis_common import SmisCommon
+from lsm.plugin.smispy import dmtf
+from lsm.plugin.smispy.utils import cim_path_to_path_str, path_str_to_cim_path
+
+_CIM_INIT_PROS = ['StorageID', 'IDType']
+
+
+def _init_id_and_type_of(cim_inits):
+ """
+ Retrieve AccessGroup.init_ids and AccessGroup.init_type from
+ a list of CIM_StorageHardwareID.
+ """
+ init_ids = []
+ init_type = AccessGroup.INIT_TYPE_UNKNOWN
+ init_types = []
+ for cim_init in cim_inits:
+ if cim_init['IDType'] == dmtf.ID_TYPE_WWPN:
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_WWPN)
+ if cim_init['IDType'] == dmtf.ID_TYPE_ISCSI:
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_ISCSI_IQN)
+ # Skip if not a iscsi initiator IQN or WWPN.
+ continue
+
+ init_type_dict = {}
+ for cur_init_type in init_types:
+ init_type_dict[cur_init_type] = 1
+
+ if len(init_type_dict) == 1:
+ init_type = init_types[0]
+ elif len(init_type_dict) == 2:
+ init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
+ return (init_ids, init_type)
+
+
+def cim_spc_pros():
+ """
+ Return the property of CIM_SCSIProtocolController required to gernarate
+ lsm.AccessGroup
+ 'EMCAdapterRole' is for EMC VNX only.
+ """
+ return ['DeviceID', 'ElementName', 'StorageID', 'EMCAdapterRole',
+ 'SystemName']
+
+
+def cim_init_mg_pros():
+ """
+ Return the property of CIM_InitiatorMaskingGroup required to gernarate
+ lsm.AccessGroup
+ """
+ return ['ElementName', 'InstanceID']
+
+
+def cim_init_of_cim_spc_path(smis_common, cim_spc_path):
+ """
+ Return a list of CIM_StorageHardwareID associated to cim_spc.
+ Only contain ['StorageID', 'IDType'] property.
+ Two ways to get StorageHardwareID from SCSIProtocolController:
+ * Method A (defined in SNIA SMIS 1.6):
+ CIM_SCSIProtocolController
+ |
+ | CIM_AssociatedPrivilege
+ v
+ CIM_StorageHardwareID
+
+ * Method B (defined in SNIA SMIS 1.3, 1.4, 1.5 and 1.6):
+ CIM_SCSIProtocolController
+ |
+ | CIM_AuthorizedTarget
+ v
+ CIM_AuthorizedPrivilege
+ |
+ | CIM_AuthorizedSubject
+ v
+ CIM_StorageHardwareID
+ """
+ cim_inits = []
+ if smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_6,
+ raise_error=False):
+ try:
+ cim_inits = smis_common.Associators(
+ cim_spc_path,
+ AssocClass='CIM_AssociatedPrivilege',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+ except CIMError as cim_error:
+ if cim_error[0] == CIM_ERR_NOT_FOUND:
+ pass
+ else:
+ raise
+
+ if len(cim_inits) == 0:
+ cim_aps_path = smis_common.AssociatorNames(
+ cim_spc_path,
+ AssocClass='CIM_AuthorizedTarget',
+ ResultClass='CIM_AuthorizedPrivilege')
+
+ for cim_ap_path in cim_aps_path:
+ cim_inits.extend(smis_common.Associators(
+ cim_ap_path,
+ AssocClass='CIM_AuthorizedSubject',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS))
+ return cim_inits
+
+
+def cim_spc_to_lsm_ag(smis_common, cim_spc, system_id):
+ """
+ Convert CIM_SCSIProtocolController to lsm.AccessGroup
+ """
+ ag_id = md5(cim_spc['DeviceID'])
+ ag_name = cim_spc['ElementName']
+ cim_inits = cim_init_of_cim_spc_path(smis_common, cim_spc.path)
+ (init_ids, init_type) = _init_id_and_type_of(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_spc.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+def cim_init_of_cim_init_mg_path(smis_common, cim_init_mg_path):
+ """
+ Use this association to get a list of CIM_StorageHardwareID:
+ CIM_InitiatorMaskingGroup
+ |
+ | CIM_MemberOfCollection
+ v
+ CIM_StorageHardwareID
+ Only contain ['StorageID', 'IDType'] property.
+ """
+ return smis_common.Associators(
+ cim_init_mg_path,
+ AssocClass='CIM_MemberOfCollection',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+
+
+def cim_init_mg_to_lsm_ag(smis_common, cim_init_mg, system_id):
+ """
+ Convert CIM_InitiatorMaskingGroup to lsm.AccessGroup
+ """
+ ag_name = cim_init_mg['ElementName']
+ ag_id = md5(cim_init_mg['InstanceID'])
+ cim_inits = cim_init_of_cim_init_mg_path(smis_common, cim_init_mg.path)
+ (init_ids, init_type) = _init_id_and_type_of(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_init_mg.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+def lsm_ag_to_cim_spc_path(smis_common, lsm_ag):
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_SCSIProtocolController
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ if not lsm_ag.plugin_data:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.AccessGroup instance with empty plugin_data")
+ if smis_common.system_list and \
+ lsm_ag.system_id not in smis_common.system_list:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_ag.plugin_data)
+
+
+def lsm_ag_to_cim_init_mg_path(smis_common, lsm_ag):
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_InitiatorMaskingGroup
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ return lsm_ag_to_cim_spc_path(smis_common, lsm_ag)
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
index 1309056..1fee9a8 100644
--- a/plugin/smispy/smis_cap.py
+++ b/plugin/smispy/smis_cap.py
@@ -23,17 +23,19 @@
MASK_TYPE_GROUP = 2


-def _rs_supported_capabilities(smis_common, system, cap):
+def _rs_supported_capabilities(smis_common, system_id, cap):
"""
Interrogate the supported features of the replication service
"""
- rs = smis_common.get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, raise_error=False)
- if rs:
+ cim_rs = smis_common.cim_rs_of_sys_id(system_id, raise_error=False)
+ if cim_rs:
rs_cap = smis_common.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_ReplicationServiceCapabilities')[0]
+ ResultClass='CIM_ReplicationServiceCapabilities',
+ PropertyList=['SupportedReplicationTypes',
+ 'SupportedAsynchronousActions',
+ 'SupportedSynchronousActions'])[0]

s_rt = rs_cap['SupportedReplicationTypes']
async_actions = rs_cap['SupportedAsynchronousActions']
@@ -55,18 +57,17 @@ def _rs_supported_capabilities(smis_common, system, cap):
else:
# Try older storage configuration service

- rs = smis_common.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', system.id,
- raise_error=False)
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)

- if rs:
- rs_cap = smis_common.Associators(
- rs.path,
+ if cim_scs:
+ cim_sc_cap = smis_common.Associators(
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedCopyTypes'])[0]

- if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
- sct = rs_cap['SupportedCopyTypes']
+ if cim_sc_cap is not None and 'SupportedCopyTypes' in cim_sc_cap:
+ sct = cim_sc_cap['SupportedCopyTypes']

if sct and len(sct):
cap.set(Capabilities.VOLUME_REPLICATE)
@@ -78,7 +79,7 @@ def _rs_supported_capabilities(smis_common, system, cap):
cap.set(Capabilities.VOLUME_REPLICATE_COPY)


-def _bsp_cap_set(smis_common, cim_sys_path, cap):
+def _bsp_cap_set(smis_common, system_id, cap):
"""
Set capabilities for these methods:
volumes()
@@ -87,10 +88,9 @@ def _bsp_cap_set(smis_common, cim_sys_path, cap):
volume_delete()
"""
# CIM_StorageConfigurationService is optional.
- cim_scs_path = smis_common.get_cim_service_path(
- cim_sys_path, 'CIM_StorageConfigurationService')
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)

- if cim_scs_path is None:
+ if cim_scs is None:
return

# These methods are mandatory for CIM_StorageConfigurationService:
@@ -101,7 +101,7 @@ def _bsp_cap_set(smis_common, cim_sys_path, cap):
# Hence we check CIM_StorageConfigurationCapabilities
# which is mandatory if CIM_StorageConfigurationService is supported.
cim_scs_cap = smis_common.Associators(
- cim_scs_path,
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_StorageConfigurationCapabilities',
PropertyList=['SupportedAsynchronousActions',
@@ -353,7 +353,7 @@ def get(smis_common, cim_sys, system):
cap = Capabilities()

if smis_common.is_netappe():
- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)

#TODO We need to investigate why our interrogation code doesn't
#work.
@@ -362,7 +362,7 @@ def get(smis_common, cim_sys, system):
return cap

# 'Block Services Package' profile
- _bsp_cap_set(smis_common, cim_sys.path, cap)
+ _bsp_cap_set(smis_common, system.id, cap)

# 'Disk Drive Lite' profile
_disk_cap_set(smis_common, cim_sys.path, cap)
@@ -380,5 +380,5 @@ def get(smis_common, cim_sys, system):
# 'FC Target Ports' and 'iSCSI Target Ports' profiles
_tgt_cap_set(smis_common, cim_sys.path, cap)

- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)
return cap
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 4a303c3..80d08d6 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -24,9 +24,12 @@

from pywbem import Uint16, CIMError
import pywbem
+import traceback
+import os
+import datetime

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


@@ -143,9 +146,9 @@ def _profile_spec_ver_to_num(spec_ver_str):

class SmisCommon(object):
# Even many CIM_XXX_Service in DMTF shared the same return value
- # defination as SNIA do, but there is no DMTF standard metioned
+ # definition as SNIA do, but there is no DMTF standard motioned
# InvokeMethod() should follow that list of return value.
- # We use SNIA defination here.
+ # We use SNIA definition here.
# SNIA 1.6 rev4 Block book, BSP 5.5.3.12 Return Values section.
SNIA_INVOKE_OK = 0
SNIA_INVOKE_NOT_SUPPORTED = 1
@@ -179,12 +182,13 @@ class SmisCommon(object):

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

if namespace is None:
namespace = dmtf.DEFAULT_NAMESPACE
@@ -201,7 +205,8 @@ def __init__(self, url, username, password,
# https://bugzilla.redhat.com/show_bug.cgi?id=1039801
pass

- self._wbem_conn.debug = debug
+ if debug_path is not None:
+ self._wbem_conn.debug = True

if namespace.lower() == SmisCommon._MEGARAID_NAMESPACE.lower():
# Skip profile register check on MegaRAID for better performance.
@@ -247,65 +252,6 @@ def profile_check(self, profile_name, spec_ver, raise_error=False):
return _profile_check(
self._profile_dict, profile_name, spec_ver, raise_error)

- def get_class_instance(self, class_name, prop_name, prop_value,
- raise_error=True, property_list=None):
- """
- Gets an instance of a class that optionally matches a specific
- property name and value
- """
- instances = None
- if property_list is None:
- property_list = [prop_name]
- else:
- property_list = merge_list(property_list, [prop_name])
-
- try:
- cim_xxxs = self.EnumerateInstances(
- class_name, PropertyList=property_list)
- except CIMError as ce:
- error_code = tuple(ce)[0]
-
- if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
- raise_error is False:
- return None
- else:
- raise
-
- for cim_xxx in cim_xxxs:
- if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
- return cim_xxx
-
- if raise_error:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
- return None
-
- def get_cim_service_path(self, cim_sys_path, class_name):
- """
- Return None if not supported
- """
- try:
- cim_srvs = self.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass=class_name)
- except CIMError as ce:
- if ce[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
- return None
- else:
- raise
- if len(cim_srvs) == 1:
- return cim_srvs[0]
- elif len(cim_srvs) == 0:
- return None
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_get_cim_service_path(): Got unexpected(not 1) "
- "count of %s from cim_sys %s: %s" %
- (class_name, cim_sys_path, cim_srvs))
-
def _vendor_namespace(self):
if self.root_blk_cim_rp:
cim_syss_path = self._wbem_conn.AssociatorNames(
@@ -372,3 +318,210 @@ def is_megaraid(self):

def is_netappe(self):
return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E
+
+ @staticmethod
+ def cim_job_pros():
+ return ['InstanceID']
+
+ def cim_job_of_job_id(self, job_id, property_list=None):
+ """
+ Return CIM_ConcreteJob for given job_id.
+ """
+ if property_list is None:
+ property_list = SmisCommon.cim_job_pros()
+ else:
+ property_list = merge_list(
+ property_list, SmisCommon.cim_job_pros())
+
+ cim_jobs = self.EnumerateInstances(
+ 'CIM_ConcreteJob',
+ PropertyList=property_list)
+ real_job_id = SmisCommon.parse_job_id(job_id)[0]
+ for cim_job in cim_jobs:
+ if md5(cim_job['InstanceID']) == real_job_id:
+ return cim_job
+
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_JOB,
+ "Job %s not found" % job_id)
+
+ @staticmethod
+ def _job_id_of_cim_job(cim_job, retrieve_data, method_data):
+ """
+ Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
+ with '@%s' % retrieve_data
+ retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
+ SmisCommon.JOB_RETRIEVE_VOLUME or etc
+ method_data is any string a method would like store for error
+ handling by job_status().
+ """
+ return "%s@%d@%s" % (
+ md5(cim_job['InstanceID']), int(retrieve_data), str(method_data))
+
+ @staticmethod
+ def parse_job_id(job_id):
+ """
+ job_id is assembled by a md5 string, retrieve_data and method_data
+ This method will split it and return
+ (md5_str, retrieve_data, method_data)
+ """
+ tmp_list = job_id.split('@', 3)
+ md5_str = tmp_list[0]
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ method_data = None
+ if len(tmp_list) == 3:
+ retrieve_data = int(tmp_list[1])
+ method_data = tmp_list[2]
+ return (md5_str, retrieve_data, method_data)
+
+ def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
+ error_handler=None, retrieve_data=None,
+ method_data=None):
+ """
+ cmd
+ A string of command, example:
+ 'CreateOrModifyElementFromStoragePool'
+ cim_path
+ the CIMInstanceName, example:
+ CIM_StorageConfigurationService.path
+ in_params
+ A dictionary of input parameter, example:
+ {'ElementName': volume_name,
+ 'ElementType': dmtf_element_type,
+ 'InPool': cim_pool_path,
+ 'Size': pywbem.Uint64(size_bytes)}
+ out_handler
+ A reference to a method to parse output, example:
+ self._new_vol_from_name
+ error_handler
+ A reference to a method to handle all exceptions.
+ retrieve_data
+ SmisCommon.JOB_RETRIEVE_XXX, it will be used only
+ when a ASYNC job has been created.
+ method_data
+ A string which will be stored in job_id, it could be used by
+ job_status() to do error checking.
+ """
+ if retrieve_data is None:
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ try:
+ (rc, out) = self.InvokeMethod(cmd, cim_path, **in_params)
+
+ # Check to see if operation is done
+ if rc == SmisCommon.SNIA_INVOKE_OK:
+ if out_handler is None:
+ return None, None
+ else:
+ return None, out_handler(out)
+
+ elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
+ # We have an async operation
+ job_id = SmisCommon._job_id_of_cim_job(
+ out['Job'], retrieve_data, method_data)
+ return job_id, None
+ elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ 'SMI-S error code indicates operation not supported')
+ else:
+ # When debugging issues with providers it's helpful to have
+ # the xml request/reply to give to provider developers.
+ try:
+ if self._debug_path is not None:
+ if not os.path.exists(self._debug_path):
+ os.makedirs(self._debug_path)
+
+ if os.path.isdir(self._debug_path):
+ debug_fn = "%s_%s" % (
+ cmd, datetime.datetime.now().isoformat())
+ debug_full = os.path.join(
+ self._debug_path, debug_fn)
+
+ # Dump the request & reply to a file
+ with open(debug_full, 'w') as d:
+ d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
+ (self.last_request, self.last_reply))
+
+ except Exception:
+ tb = traceback.format_exc()
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= %s" % (cmd, str(rc))+
+ " Debug data exception: %s" % str(tb))
+
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= %s" % (cmd, str(rc)))
+
+ except Exception:
+ if error_handler is not None:
+ error_handler(self, method_data)
+ else:
+ raise
+
+ def _cim_srv_of_sys_id(self, srv_name, sys_id, raise_error):
+ property_list = ['SystemName']
+
+ cim_srvs = self.EnumerateInstances(
+ srv_name,
+ PropertyList=property_list)
+ for cim_srv in cim_srvs:
+ if cim_srv['SystemName'] == sys_id:
+ return cim_srv
+
+ if raise_error:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Cannot find any '%s' for requested systemd ID" % srv_name)
+ return None
+
+
+ def cim_scs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_StorageConfigurationService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageConfigurationService', sys_id, raise_error)
+
+
+ def cim_rs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_ReplicationService for given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ReplicationService', sys_id, raise_error)
+
+
+ def cim_gmms_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_GroupMaskingMappingService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_GroupMaskingMappingService', sys_id, raise_error)
+
+
+ def cim_ccs_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_ControllerConfigurationService for given
+ system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ControllerConfigurationService', sys_id, raise_error)
+
+ def cim_hwms_of_sys_id(self, sys_id, raise_error=True):
+ """
+ Return a CIMInstance of CIM_StorageHardwareIDManagementService for
+ given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageHardwareIDManagementService', sys_id, raise_error)
diff --git a/plugin/smispy/smis_pool.py b/plugin/smispy/smis_pool.py
index ca0999e..c9f4345 100644
--- a/plugin/smispy/smis_pool.py
+++ b/plugin/smispy/smis_pool.py
@@ -15,11 +15,9 @@
#
# Author: Gris Ge <***@redhat.com>

-from utils import merge_list
+from utils import merge_list, path_str_to_cim_path, cim_path_to_path_str
import dmtf
from lsm import LsmError, ErrorNumber, Pool
-import json
-from pywbem import CIMInstanceName


def cim_pools_of_cim_sys_path(smis_common, cim_sys_path, property_list=None):
@@ -226,7 +224,7 @@ def cim_pool_to_lsm_pool(smis_common, cim_pool, system_id):

element_type, unsupported = _pool_element_type(smis_common, cim_pool)

- plugin_data = _cim_path_to_path_str(cim_pool.path)
+ plugin_data = cim_path_to_path_str(cim_pool.path)

return Pool(pool_id, name, element_type, unsupported,
total_space, free_space,
@@ -248,27 +246,7 @@ def lsm_pool_to_cim_pool_path(smis_common, lsm_pool):
ErrorNumber.NOT_FOUND_SYSTEM,
"System filtered in URI")

- return _path_str_to_cim_path(lsm_pool.plugin_data)
-
-
-def _cim_path_to_path_str(cim_path):
- """
- Convert CIMInstanceName to a string which could save in plugin_data
- """
- return json.dumps({
- 'classname': cim_path.classname,
- 'keybindings': dict(cim_path.keybindings),
- 'host': cim_path.host,
- 'namespace': cim_path.namespace,
- })
-
-
-def _path_str_to_cim_path(path_str):
- """
- Convert a string into CIMInstanceName.
- """
- path_dict = json.loads(path_str)
- return CIMInstanceName(**path_dict)
+ return path_str_to_cim_path(lsm_pool.plugin_data)


def pool_id_of_cim_vol(smis_common, cim_vol_path):
diff --git a/plugin/smispy/smis_sys.py b/plugin/smispy/smis_sys.py
index 64a9723..4101137 100644
--- a/plugin/smispy/smis_sys.py
+++ b/plugin/smispy/smis_sys.py
@@ -38,6 +38,16 @@ def sys_id_of_cim_sys(cim_sys):
"'Name' property: %s, %s" % (cim_sys.items(), cim_sys.path))


+def sys_id_of_cim_vol(cim_vol):
+ if 'SystemName' in cim_vol:
+ return cim_vol['SystemName']
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_id_of_cim_vol(): Got a CIM_StorageVolume does not have "
+ "'SystemName' property: %s, %s" % (cim_vol.items(), cim_vol.path))
+
+
def root_cim_sys(smis_common, property_list=None):
"""
Use this association to find out the root CIM_ComputerSystem:
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
new file mode 100644
index 0000000..fa52c88
--- /dev/null
+++ b/plugin/smispy/smis_vol.py
@@ -0,0 +1,241 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Author: Gris Ge <***@redhat.com>
+
+"""
+This module intends to provide independent methods related to lsm.Volume and
+CIM_StorageVolume.
+"""
+
+import re
+import sys
+
+from lsm import md5, Volume, LsmError, ErrorNumber
+from lsm.plugin.smispy.utils import (
+ merge_list, cim_path_to_path_str, path_str_to_cim_path)
+from lsm.plugin.smispy import dmtf
+
+def cim_vol_id_pros():
+ """
+ Return the property of CIM_StorageVolume required to generate
+ lsm.Volume.id
+ """
+ return ['SystemName', 'DeviceID']
+
+
+def vol_id_of_cim_vol(cim_vol):
+ """
+ Get lsm.Volume.id from CIM_StorageVolume['DeviceID'] and ['SystemName']
+ """
+ if 'SystemName' not in cim_vol or 'DeviceID' not in cim_vol:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "vol_id_of_cim_vol(): Got cim_vol with no "
+ "SystemName or DeviceID property: %s, %s" %
+ (cim_vol.path, cim_vol.items()))
+
+ return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
+
+
+def cim_vol_pros():
+ """
+ Return the PropertyList required for creating new lsm.Volume.
+ """
+ props = ['ElementName', 'NameFormat',
+ 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
+ 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
+ 'OtherNameFormat', 'OtherNameNamespace']
+ props.extend(cim_vol_id_pros())
+ return props
+
+
+def cim_vol_of_cim_pool_path(smis_common, cim_pool_path, property_list=None):
+ """
+ Use this association to get a list of CIM_StorageVolume:
+ CIM_StoragePool
+ |
+ | CIM_AllocatedFromStoragePool
+ |
+ v
+ CIM_StorageVolume
+ CIM_StorageVolume['Usage'] == dmtf.VOL_USAGE_SYS_RESERVED will be filtered
+ out.
+ Return a list of CIM_StorageVolume.
+ """
+ if property_list is None:
+ property_list = ['Usage']
+ else:
+ property_list = merge_list(property_list, ['Usage'])
+
+ cim_vols = smis_common.Associators(
+ cim_pool_path,
+ AssocClass='CIM_AllocatedFromStoragePool',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=property_list)
+
+ needed_cim_vols = []
+ for cim_vol in cim_vols:
+ if 'Usage' not in cim_vol or \
+ cim_vol['Usage'] != dmtf.VOL_USAGE_SYS_RESERVED:
+ needed_cim_vols.append(cim_vol)
+ return needed_cim_vols
+
+
+def _vpd83_in_cim_vol_name(cim_vol):
+ """
+ We require NAA Type 3 VPD83 address:
+ Only this is allowed when storing VPD83 in cim_vol["Name"]:
+ * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
+ """
+ if not ('NameFormat' in cim_vol and
+ 'NameNamespace' in cim_vol and
+ 'Name' in cim_vol):
+ return None
+ name_format = cim_vol['NameFormat']
+ name_space = cim_vol['NameNamespace']
+ name = cim_vol['Name']
+ if not (name_format and name_space and name):
+ return None
+
+ if name_format == dmtf.VOL_NAME_FORMAT_NNA and \
+ name_space == dmtf.VOL_NAME_SPACE_VPD83_TYPE3:
+ return name
+
+
+def _vpd83_in_cim_vol_otherinfo(cim_vol):
+ """
+ IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
+ Will return the vpd_83 value if found
+ """
+ if not ("IdentifyingDescriptions" in cim_vol and
+ "OtherIdentifyingInfo" in cim_vol):
+ return None
+
+ id_des = cim_vol["IdentifyingDescriptions"]
+ other_info = cim_vol["OtherIdentifyingInfo"]
+ if not (isinstance(cim_vol["IdentifyingDescriptions"], list) and
+ isinstance(cim_vol["OtherIdentifyingInfo"], list)):
+ return None
+
+ index = 0
+ len_id_des = len(id_des)
+ len_other_info = len(other_info)
+ while index < min(len_id_des, len_other_info):
+ if dmtf.VOL_OTHER_INFO_NAA_VPD83_TYPE3H == id_des[index]:
+ return other_info[index]
+ index += 1
+ return None
+
+
+def _vpd83_netapp(cim_vol):
+ """
+ Workaround for NetApp, they use OtherNameNamespace and
+ OtherNameFormat.
+ """
+ if 'OtherNameFormat' in cim_vol and \
+ cim_vol['OtherNameFormat'] == 'NAA' and \
+ 'OtherNameNamespace' in cim_vol and \
+ cim_vol['OtherNameNamespace'] == 'VPD83Type3' and \
+ 'OtherIdentifyingInfo' in cim_vol and \
+ isinstance(cim_vol["OtherIdentifyingInfo"], list) and \
+ len(cim_vol['OtherIdentifyingInfo']) == 1:
+ return cim_vol['OtherIdentifyingInfo'][0]
+
+
+def _vpd83_of_cim_vol(cim_vol):
+ """
+ Extract VPD83 string from CIMInstanceName and convert to LSM format:
+ ^6[a-f0-9]{31}$
+ """
+ vpd_83 = _vpd83_in_cim_vol_name(cim_vol)
+ if vpd_83 is None:
+ vpd_83 = _vpd83_in_cim_vol_otherinfo(cim_vol)
+ if vpd_83 is None:
+ vpd_83 = _vpd83_netapp(cim_vol)
+
+ if vpd_83 and re.match('^6[a-fA-F0-9]{31}$', vpd_83):
+ return vpd_83.lower()
+ else:
+ return ''
+
+
+def cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id):
+ """
+ Takes a CIMInstance that represents a volume and returns a lsm Volume
+ """
+
+ # This is optional (User friendly name)
+ if 'ElementName' in cim_vol:
+ user_name = cim_vol["ElementName"]
+ else:
+ #Better fallback value?
+ user_name = cim_vol['DeviceID']
+
+ vpd_83 = _vpd83_of_cim_vol(cim_vol)
+
+ admin_state = Volume.ADMIN_STATE_ENABLED
+
+ plugin_data = cim_path_to_path_str(cim_vol.path)
+
+ return Volume(
+ vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
+ cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
+ pool_id, plugin_data)
+
+
+def lsm_vol_to_cim_vol_path(smis_common, lsm_vol):
+ """
+ Convert lsm.Volume to CIMInstanceName of CIM_StorageVolume using
+ lsm.Volume.plugin_data
+ """
+ if not lsm_vol.plugin_data:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.Volume instance with empty plugin_data")
+ if smis_common.system_list and \
+ lsm_vol.system_id not in smis_common.system_list:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_vol.plugin_data)
+
+
+def volume_name_exists(smis_common, volume_name):
+ """
+ Try to minimize time to search.
+ :param volume_name: Volume ElementName
+ :return: True if volume exists with 'name', else False
+ """
+ all_cim_vols = smis_common.EnumerateInstances(
+ 'CIM_StorageVolume', PropertyList=['ElementName'])
+ for exist_cim_vol in all_cim_vols:
+ if volume_name == exist_cim_vol['ElementName']:
+ return True
+ return False
+
+
+def volume_create_error_handler(smis_common, method_data):
+ """
+ When we got CIMError, we check whether we got a duplicate volume name.
+ The method_data is the requested volume name.
+ """
+ if volume_name_exists(smis_common, method_data):
+ raise LsmError(ErrorNumber.NAME_CONFLICT,
+ "Volume with name '%s' already exists!" % method_data)
+
+ (error_type, error_msg, error_trace) = sys.exc_info()
+ raise error_type, error_msg, error_trace
diff --git a/plugin/smispy/utils.py b/plugin/smispy/utils.py
index 95332b8..668241f 100644
--- a/plugin/smispy/utils.py
+++ b/plugin/smispy/utils.py
@@ -17,8 +17,9 @@

import traceback
from lsm import (LsmError, ErrorNumber, error)
-from pywbem import (CIMError)
+from pywbem import (CIMError, CIMInstanceName)
import pywbem
+import json


def merge_list(list_a, list_b):
@@ -66,3 +67,23 @@ def cim_wrapper(*args, **kwargs):
def hex_string_format(hex_str, length, every):
hex_str = hex_str.lower()
return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
+
+
+def cim_path_to_path_str(cim_path):
+ """
+ Convert CIMInstanceName to a string which could save in plugin_data
+ """
+ return json.dumps({
+ 'classname': cim_path.classname,
+ 'keybindings': dict(cim_path.keybindings),
+ 'host': cim_path.host,
+ 'namespace': cim_path.namespace,
+ })
+
+
+def path_str_to_cim_path(path_str):
+ """
+ Convert a string into CIMInstanceName.
+ """
+ path_dict = json.loads(path_str)
+ return CIMInstanceName(**path_dict)
--
1.8.3.1
Tony Asleson
2014-11-12 22:03:29 UTC
Permalink
Hi Gris,
From a code review, things look good. However, I ran the patch across
all the arrays in the SNIA lab and the I'm seeing new failures on the
3Par and Fujitsu array.

Please take a look:
http://redhat-vm3.snia.net/developer_test/20141112-13:32/results.html

Thanks,
Tony
1. smis_ag.py: Hold AccessGroup related methods
2. smis_vol.py: Hold Volume related methods
* Makefile and RPM SPEC file updated for new file smis_ag.py and smis_vol.py.
* Replaces smis.Smis._vol_id() with smis_vol.vol_id_of_cim_vol()
* Replaces smis.Smis._property_list_of_id('Volume') with
smis_vol.cim_vol_id_pros()
* Replace smis.Smis._cim_vol_pros() with smis_vol.cim_vol_pros()
* Replace smis.Smis._new_vol() with smis_pool.cim_vol_to_lsm_vol()
* Moved _vpd83_xxx method into smis_pool.py as it's private used by
smis_pool.cim_vol_to_lsm_vol()
* The smis_pool.cim_vol_to_lsm_vol() require caller to provide pool_id and
systemd_id as they should handled by smis_pool.py and smis_sys.py.
smis_sys.sys_id_of_cim_vol() is added for this seek.
* As these two methods will be commonly used across smis_xxx.py,
smis_pool._cim_path_to_path_str()
-> utils.cim_path_to_path_str()
smis_pool._path_str_to_cim_path()
- utils.path_str_to_cim_path()
* Replace smis.Smis._pi() with SmisCommon.invoke_method().
* When a exception triggered, invoke_method() will call 'error_handler'
with argument of: SmisCommon, method_data.
In this patch, smis_vol.volume_create_error_handler() is the
error_handler of volume_create(). It's stored in
smis.Smis._JOB_ERROR_HANDLER[SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
so that job_status() could use the same error handler.
* The invoke_method() also take 'out_handler' parameter which will be
called if the method finished in SYNC way.
In this patch, self._new_vol_from_name() is the out_handler of
volume_create().
smis.Smis._job_id() -> smis_common.SmisCommon.job_id_of_cim_job()
smis.Smis._parse_job_id() -> smis_common.SmisCommon.parse_job_id()
* Move duplicate volume checker method to smis_vol.py as the volume create
smis.Smis._volume_exists -> smis_vol.volume_name_exists
smis.Smis._check_for_dupe_vol() -> smis_vol.volume_create_error_handler()
* Store cim_vol_path data in Volume.plugin_date.
* Replace
smis.Smis._get_cim_instance_by_id('Volume', volume.id)
-> smis_vol.lsm_vol_to_cim_vol_path()
* Changed smis.Smis._deal_volume_associations_netappe() and
smis.Smis._deal_volume_associations() to take cim_vol_path only.
SmisCommon.cim_scs_of_sys_id() CIM_StorageConfigurationService
SmisCommon.cim_rs_of_sys_id() CIM_ReplicationService
SmisCommon.cim_gmms_of_sys_id() CIM_GroupMaskingMappingService
SmisCommon.cim_ccs_of_sys_id() CIM_ControllerConfigurationService
SmisCommon.cim_hwms_of_sys_id() CIM_StorageHardwareIDManagementService
* smis.Smis._cim_spc_of() changed to use system_id instead of cim_sys.path
to benefit this change.
* Empty smis_ag.py with license only.
* Makefile and RPM SPEC file updated.
* Removed smis._dmtf_init_type_to_lsm(). It has been merged into
smis_ag._cim_inits_to_lsm_init_id_and_type()
smis.Smis._cim_spc_pros()
-> smis_ag.cim_spc_pros()
smis.Smis._cim_inits_to_lsm()
-> smis_ag._cim_inits_to_lsm_init_id_and_type()
smis.Smis._cim_spc_to_lsm()
-> smis_ag.cim_spc_to_lsm_ag()
smis.Smis._cim_init_of_spc()
-> cim_init_of_cim_spc_path()
smis.Smis._cim_init_of_init_mg()
-> cim_init_of_cim_init_mg_path()
* Save cim_spc_path or cim_init_mg_path into lsm.AccessGroup.plugin_data
* Replaces these methods for converting lsm.AccessGroup to
smis.Smis._cim_spc_of_id()
-> smis_ag.lsm_ag_to_cim_spc_path()
smis.Smis._cim_init_mg_of_id()
-> smis_ag.lsm_ag_to_cim_init_mg_path()
* Replace smis.Smis._cim_init_mg_pros() with
smis_ag.cim_init_mg_pros()
* Fix typo: gernarate -> generate in smis_vol.py.
:param name: Volume ElementName
-> :param volume_name: Volume ElementName
msg, datetime.datetime.now().isoformat())
-> : cmd, datetime.datetime.now().isoformat())
defination -> definition
metioned -> motioned
cim_gmm.path, **in_params)
-> cim_gmms_path, **in_params)
LsmError, ErrorNumber
* Fix debug_path of smis.Smis.plugin_register().
* PEP8 fix in smis.py.
* Fix traceback log displaying in SmisCommon.invoke_method().
1. Relative import. Use 'from lsm.plugin.smispy import smis_ag' instead of
'import smis_ag'
2. Add module docstring for smis_ag and smis_vol.
3. Remove unused parameter 'smis_common' of smis_vol.cim_vol_to_lsm_vol().
* smis_ag._cim_inits_to_lsm_init_id_and_type()
-> smis_ag._init_id_and_type_of()
* smis_vol._vpd83_in_cim_vol_otherinfo_netapp()
-> smis_vol._vpd83_netapp()
* smis_ag._init_id_and_type_of()
rc -> cim_inits
* smis_vol._vpd83_in_cim_vol_name()
nn -> name_space
nf -> name_format
* smis_vol.cim_vol_of_cim_pool_path()
rc -> needed_cim_vols
* smis_ag.cim_init_of_cim_spc_path()
ce -> cim_error
6. Remove unused variable 'ag_init_ids' in smis_ag.cim_spc_to_lsm_ag().
* smis_ag.cim_init_mg_to_lsm_ag()
* smis_ag.cim_spc_to_lsm_ag()
* smis_vol.vol_id_of_cim_vol()
* smis_vol._vpd83_of_cim_vol()
---
packaging/libstoragemgmt.spec.in | 2 +
plugin/Makefile.am | 4 +-
plugin/smispy/dmtf.py | 2 +
plugin/smispy/smis.py | 1098 +++++++++++---------------------------
plugin/smispy/smis_ag.py | 205 +++++++
plugin/smispy/smis_cap.py | 46 +-
plugin/smispy/smis_common.py | 281 +++++++---
plugin/smispy/smis_pool.py | 28 +-
plugin/smispy/smis_sys.py | 10 +
plugin/smispy/smis_vol.py | 241 +++++++++
plugin/smispy/utils.py | 23 +-
11 files changed, 1039 insertions(+), 901 deletions(-)
create mode 100644 plugin/smispy/smis_ag.py
create mode 100644 plugin/smispy/smis_vol.py
diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 0ef7c16..d7f132d 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -478,6 +478,8 @@ fi
%{python_sitelib}/lsm/plugin/smispy/smis_sys.*
%{python_sitelib}/lsm/plugin/smispy/smis_pool.*
%{python_sitelib}/lsm/plugin/smispy/smis_disk.*
+%{python_sitelib}/lsm/plugin/smispy/smis_vol.*
+%{python_sitelib}/lsm/plugin/smispy/smis_ag.*
%{_bindir}/smispy_lsmplugin
%files -n %{libstoragemgmt}-netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index c3084c9..78ceb36 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -31,7 +31,9 @@ smispy_PYTHON = \
smispy/smis_cap.py \
smispy/smis_sys.py \
smispy/smis_pool.py \
- smispy/smis_disk.py
+ smispy/smis_disk.py \
+ smispy/smis_ag.py \
+ smispy/smis_vol.py
nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/dmtf.py b/plugin/smispy/dmtf.py
index 576c72e..c44db2f 100644
--- a/plugin/smispy/dmtf.py
+++ b/plugin/smispy/dmtf.py
@@ -242,3 +242,5 @@ def op_status_list_conv(conv_dict, dmtf_op_status_list,
CTRL_CONF_SRV_DA_RW = Uint16(2)
VOL_OTHER_INFO_NAA_VPD83_TYPE3H = 'NAA;VPD83Type3'
+
+VOL_USAGE_SYS_RESERVED = Uint16(3)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a571d9d..5f44136 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -19,11 +19,8 @@
from string import split
import time
-import traceback
import copy
import os
-import datetime
-import sys
import re
import pywbem
@@ -32,6 +29,8 @@
import smis_sys
import smis_pool
import smis_disk
+from lsm.plugin.smispy import smis_vol
+from lsm.plugin.smispy import smis_ag
import dmtf
from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
@@ -61,8 +60,10 @@
# cim_ip CIM_IPProtocolEndpoint
# cim_eth CIM_EthernetPort
# cim_pe CIM_SCSIProtocolEndpoint
-# cim_gmm CIM_GroupMaskingMappingService
+# cim_gmms CIM_GroupMaskingMappingService
# cim_ccs CIM_ControllerConfigurationService
+# cim_rs CIM_ReplicationService
+# cim_hwms CIM_StorageHardwareIDManagementService
#
# sys Object of LSM System
# pool Object of LSM Pool
return lsm_init_id
- return AccessGroup.INIT_TYPE_WWPN
- return AccessGroup.INIT_TYPE_ISCSI_IQN
- return AccessGroup.INIT_TYPE_UNKNOWN
-
-
"""
We are assuming we got CIM_FCPort. Caller should make sure of that.
_INVOKE_MAX_LOOP_COUNT = 60
_INVOKE_CHECK_INTERVAL = 5
+ _JOB_ERROR_HANDLER = {
+ smis_vol.volume_create_error_handler,
+ }
+
self._c = None
self.tmo = 0
- self.debug_path = None
def _get_cim_instance_by_id(self, class_type, requested_id,
@@ -163,7 +159,8 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
class_name, PropertyList=property_list)
org_requested_id = requested_id
- (requested_id, ignore, ignore) = Smis._parse_job_id(requested_id)
+ (requested_id, ignore, ignore) = SmisCommon.parse_job_id(
+ requested_id)
return cim_xxx
@@ -174,53 +171,6 @@ def _get_cim_instance_by_id(self, class_type, requested_id,
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))
- """
- Handle the the process of invoking an operation.
- """
- # Check to see if operation is done
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- return None, self._new_vol_from_name(out)
- return None, None
-
- # We have an async operation
- job_id = self._job_id(out['Job'], retrieve_data, method_data)
- return job_id, None
- raise LsmError(
- ErrorNumber.NO_SUPPORT,
- 'SMI-S error code indicates operation not supported')
- # When debugging issues with providers it's helpful to have the
- # xml request/reply to give to provider developers.
- os.makedirs(self.debug_path)
-
- debug_fn = "%s_%s" % \
- (msg, datetime.datetime.now().isoformat())
- debug_full = os.path.join(self.debug_path, debug_fn)
-
- # Dump the request & reply to a file
- d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
- (self._c.last_request, self._c.last_reply))
-
- tb = traceback.format_exc()
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc) +
- ' Debug data exception: ' + str(tb))
-
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- 'Error: ' + msg + " rc= " + str(rc))
-
@handle_cim_errors
"""
no_ssl_verify = True
- debug = False
+ debug_path = None
- self.debug_path = u['parameters']['debug_path']
- debug = True
+ debug_path = u['parameters']['debug_path']
self._c = SmisCommon(
- url, u['username'], password, namespace, no_ssl_verify, debug,
- system_list)
+ url, u['username'], password, namespace, no_ssl_verify,
+ debug_path, system_list)
self.tmo = timeout
"""
completed_item = None
- props = ['JobState', 'PercentComplete', 'ErrorDescription',
- 'OperationalStatus']
- cim_job_pros = self._property_list_of_id('Job', props)
+ error_handler = None
+
+ (ignore, retrieve_data, method_data) = SmisCommon.parse_job_id(job_id)
- cim_job = self._get_cim_instance_by_id('Job', job_id, cim_job_pros)
+ error_handler = Smis._JOB_ERROR_HANDLER[retrieve_data]
+
+ cim_job_pros = SmisCommon.cim_job_pros()
+ cim_job_pros.extend(
+ ['JobState', 'PercentComplete', 'ErrorDescription',
+ 'OperationalStatus'])
+ cim_job = self._c.cim_job_of_job_id(job_id, cim_job_pros)
job_state = cim_job['JobState']
- (ignore, retrieve_data, method_data) = self._parse_job_id(job_id)
- if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
- status = JobStatus.INPROGRESS
+ if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
+ status = JobStatus.INPROGRESS
- pc = cim_job['PercentComplete']
- percent_complete = 100
- percent_complete = pc
+ pc = cim_job['PercentComplete']
+ percent_complete = 100
+ percent_complete = pc
- status = JobStatus.COMPLETE
- percent_complete = 100
+ status = JobStatus.COMPLETE
+ percent_complete = 100
- if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
- completed_item = self._new_vol_from_job(cim_job)
+ if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
+ completed_item = self._new_vol_from_job(cim_job)
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ str(cim_job['ErrorDescription']))
- status = JobStatus.ERROR
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG, str(cim_job['ErrorDescription']))
- self._check_for_dupe_vol(method_data, None)
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- str(cim_job['ErrorDescription']))
+ error_handler(self._c, method_data)
+ raise
return status, percent_complete, completed_item
"""
return self._id('SystemChild', cim_xxx)
- """
- Return the MD5 hash of CIM_StorageVolume['SystemName'] and
- ['DeviceID']
- """
- return self._id('Volume', cim_vol)
-
- """
- Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
- retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
- SmisCommon.JOB_RETRIEVE_VOLUME or etc
- method_data is any string a method would like store for error
- handling by job_status().
- """
- self._id('Job', cim_job), int(retrieve_data), str(method_data))
-
"""
Retrieve Initiator ID from CIM_StorageHardwareID
return md5(id_str)
- """
- job_id is assembled by a md5 string, retrieve_data and method_data
- This method will split it and return
- (md5_str, retrieve_data, method_data)
- """
- md5_str = tmp_list[0]
- retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
- method_data = None
- retrieve_data = int(tmp_list[1])
- method_data = tmp_list[2]
- return (md5_str, retrieve_data, method_data)
-
- other_id = None
-
- if 'OtherIdentifyingInfo' in cv \
- and cv["OtherIdentifyingInfo"] is not None \
-
- other_id = cv["OtherIdentifyingInfo"]
-
- other_id = other_id[0]
-
- # This is not what we are looking for if the field has this value
- other_id = None
-
- return other_id
-
- """
- Return the PropertyList required for creating new LSM Volume.
- """
- props = ['ElementName', 'NameFormat',
- 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
- 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
- 'OtherNameFormat', 'OtherNameNamespace']
- cim_vol_pros = self._property_list_of_id("Volume", props)
- return cim_vol_pros
-
- """
- Takes a CIMInstance that represents a volume and returns a lsm Volume
- """
-
- # This is optional (User friendly name)
- user_name = cv["ElementName"]
- #Better fallback value?
- user_name = cv['DeviceID']
-
- vpd_83 = Smis._vpd83_in_cv_name(cv)
- vpd_83 = Smis._vpd83_in_cv_otherinfo(cv)
- vpd_83 = Smis._vpd83_in_cv_otherinfo_netapp(cv)
-
- if vpd_83 and re.match('^[a-fA-F0-9]{32}$', vpd_83) and \
- vpd_83 = vpd_83.lower()
- vpd_83 = ''
-
- #This is a fairly expensive operation, so it's in our best interest
- #to not call this very often.
- #Go an retrieve the pool id
- pool_id = smis_pool.pool_id_of_cim_vol(self._c, cv.path)
-
- sys_id = cv['SystemName']
-
- admin_state = Volume.ADMIN_STATE_ENABLED
-
- return Volume(self._vol_id(cv), user_name, vpd_83, cv["BlockSize"],
- cv["NumberOfBlocks"], admin_state, sys_id, pool_id)
-
- """
- * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
- """
- if not ('NameFormat' in cv and
- 'NameNamespace' in cv and
- return None
- nf = cv['NameFormat']
- nn = cv['NameNamespace']
- name = cv['Name']
- return None
-
- if nf == dmtf.VOL_NAME_FORMAT_NNA and \
- return name
-
- """
- IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
- Will return the vpd_83 value if found
- """
- if not ("IdentifyingDescriptions" in cv and
- return None
-
- id_des = cv["IdentifyingDescriptions"]
- other_info = cv["OtherIdentifyingInfo"]
- if not (isinstance(cv["IdentifyingDescriptions"], list) and
- return None
-
- index = 0
- len_id_des = len(id_des)
- len_other_info = len(other_info)
- return other_info[index]
- index += 1
- return None
-
- # workaround for NetApp, they use OtherNameNamespace and
- # OtherNameFormat.
- if 'OtherNameFormat' in cv and \
- cv['OtherNameFormat'] == 'NAA' and \
- 'OtherNameNamespace' in cv and \
- cv['OtherNameNamespace'] == 'VPD83Type3' and \
- 'OtherIdentifyingInfo' in cv and \
- isinstance(cv["OtherIdentifyingInfo"], list) and \
- return cv['OtherIdentifyingInfo'][0]
-
"""
Given a volume by CIMInstanceName, return a lsm Volume object
"""
- instance = None
+ cim_vol = None
+ cim_vol_pros = smis_vol.cim_vol_pros()
- instance = self._c.GetInstance(out['TheElement'],
- LocalOnly=False)
+ cim_vol = self._c.GetInstance(
+ out['TheElement'],
+ PropertyList=cim_vol_pros)
- instance = self._c.GetInstance(out['TargetElement'],
- LocalOnly=False)
-
- return self._new_vol(instance)
-
- """
- Return a list of properties required to build new AccessGroup.
- """
- cim_spc_pros = ['DeviceID']
- cim_spc_pros.extend(self._property_list_of_id('SystemChild'))
- cim_spc_pros.extend(['ElementName', 'StorageID'])
- cim_spc_pros.extend(['EMCAdapterRole']) # EMC specific, used to
- # filter out the mapping SPC.
- return cim_spc_pros
-
- """
- Retrieve AccessGroup.init_ids and AccessGroup.init_type from
- a list of CIM_StorageHardwareID.
- """
- init_ids = []
- init_type = AccessGroup.INIT_TYPE_UNKNOWN
- init_types = []
- init_type = _dmtf_init_type_to_lsm(cim_init)
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- init_ids.append(self._init_id(cim_init))
- init_types.append(init_type)
- # Skip if not a iscsi initiator IQN or WWPN.
- continue
-
- init_type_dict = {}
- init_type_dict[cur_init_type] = 1
-
- init_type = init_types[0]
- init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
- return (init_ids, init_type)
-
- system_id = self._sys_id_child(cim_spc)
- ag_id = md5(cim_spc['DeviceID'])
- ag_name = cim_spc['ElementName']
- ag_init_ids = []
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- sys_id = self._sys_id_child(cim_spc)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, sys_id)
+ cim_vol = self._c.GetInstance(
+ out['TargetElement'],
+ PropertyList=cim_vol_pros)
+
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+
+ return smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id)
"""
Given a concrete job instance, return referenced volume as lsm volume
"""
- for a in self._c.Associators(job.path,
- AssocClass='CIM_AffectedJobElement',
- return self._new_vol(self._c.GetInstance(a.path, LocalOnly=False))
+ cim_vol_pros = smis_vol.cim_vol_pros()
+ cim_vols = self._c.Associators(
+ job.path,
+ AssocClass='CIM_AffectedJobElement',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=cim_vol_pros)
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ return smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id)
return None
@handle_cim_errors
rc = []
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()
sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
pool_pros = smis_pool.cim_pool_id_pros()
self._c, cim_sys.path, pool_pros)
pool_id = smis_pool.pool_id_of_cim_pool(cim_pool)
- cim_vols = self._c.Associators(
- cim_pool.path,
- AssocClass='CIM_AllocatedFromStoragePool',
- ResultClass='CIM_StorageVolume',
- PropertyList=cim_vol_pros)
+ cim_vols = smis_vol.cim_vol_of_cim_pool_path(
+ self._c, cim_pool.path, cim_vol_pros)
- # Exclude those volumes which are reserved for system
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
- vol = self._new_vol(cim_vol, pool_id, sys_id)
- rc.extend([vol])
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id))
return search_property(rc, search_key, search_value)
@handle_cim_errors
return [smis_sys.cim_sys_to_lsm_sys(s) for s in cim_syss]
- """
- Try to minimize time to search.
- :param name: Volume ElementName
- :return: True if volume exists with 'name', else False
- """
- all_cim_vols = self._c.EnumerateInstances(
- 'CIM_StorageVolume', PropertyList=['ElementName'])
- return True
- return False
-
- """
- Throw original exception or NAME_CONFLICT if volume name found
- :param volume_name: Volume to check for
- :original_exception Info grabbed from sys.exec_info
- if original_exception == None, will not raise any error if not
- NAME_CONFLICT, just return None.
- """
- report_original = True
-
- # Check to see if we already have a volume with this name. If we
- # do we will assume that this is the cause of it. We will hide
- # any errors that happen during this check and just report the
- # original error if we can't determine if we have a duplicate
- # name.
-
- report_original = not self._volume_exists(volume_name)
- # Don't report anything here on a failing
- pass
-
- return
- raise original_exception[1], None, original_exception[2]
- raise LsmError(ErrorNumber.NAME_CONFLICT,
- "Volume with name '%s' already exists!" %
- volume_name)
-
@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
@@ -860,8 +564,8 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
if provisioning == Volume.PROVISION_FULL and \
dmtf_element_type = dmtf.ELEMENT_THICK_VOLUME
- elif provisioning == Volume.PROVISION_THIN and \
+ elif (provisioning == Volume.PROVISION_THIN and
dmtf_element_type = dmtf.ELEMENT_THIN_VOLUME
raise LsmError(
@@ -870,8 +574,8 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
"requested provisioning type")
# Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(pool.system_id)
+
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
self._c, pool)
@@ -880,15 +584,16 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
'InPool': cim_pool_path,
'Size': pywbem.Uint64(size_bytes)}
- return self._pi("volume_create",
- SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
- volume_name,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
- self._check_for_dupe_vol(volume_name, sys.exc_info())
+ error_handler = Smis._JOB_ERROR_HANDLER[
+ SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
+
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params,
+ out_handler=self._new_vol_from_name,
+ error_handler=error_handler,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
+ method_data=volume_name)
#Get the Configuration service for the system we are interested in.
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', vol.system_id)
+ cim_scs = self._c.cim_scs_of_sys_id(vol.system_id)
in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}
- job_id = self._pi("_detach",
- SmisCommon.JOB_RETRIEVE_NONE,
- None,
- *(self._c.InvokeMethod(
- 'ModifySynchronization', scs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifySynchronization', cim_scs.path, in_params)[0]
self._poll("ModifySynchronization, detach", job_id)
return self._detach_netapp_e(vol, sync)
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- vol.system_id, raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(vol.system_id, raise_error=False)
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}
- job_id = self._pi("_detach", SmisCommon.JOB_RETRIEVE_NONE, None,
- *(self._c.InvokeMethod(
- 'ModifyReplicaSynchronization', rs.path,
- **in_params)))[0]
+ job_id = self._c.invoke_method(
+ 'ModifyReplicaSynchronization', cim_rs.path, in_params)[0]
self._poll("ModifyReplicaSynchronization, detach", job_id)
return False
"""
Check a volume to see if it has any associations with other
volumes.
"""
rc = False
- lun_path = lun.path
- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')
item = s['SyncedElement']
self._detach(vol, s)
rc = True
item = s['SystemElement']
self._detach(vol, s)
rc = True
return rc
"""
Check a volume to see if it has any associations with other
volumes and deal with them.
"""
- return self._deal_volume_associations_netappe(vol, lun)
-
- lun_path = lun.path
+ return self._deal_volume_associations_netappe(vol, cim_vol_path)
- ss = self._c.References(lun_path,
+ ss = self._c.References(cim_vol_path,
ResultClass='CIM_StorageSynchronized')
item = s['SyncedElement']
self._detach(vol, s)
item = s['SystemElement']
self._detach(vol, s)
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
#If we actually have an association to delete, the volume will be
#deleted with the association, no need to call ReturnToStoragePool
- in_params = {'TheElement': lun.path}
+ in_params = {'TheElement': cim_vol_path}
#Delete returns None or Job number
- return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE,
- None,
- *(self._c.InvokeMethod('ReturnToStoragePool',
- scs.path, **in_params)))[0]
+ return self._c.invoke_method(
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]
#Loop to check to see if volume is actually gone yet!
- lun = self._get_cim_instance_by_id('Volume', volume.id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=[])
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=[])
time.sleep(0.125)
pass
@handle_cim_errors
"""
Delete a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
- self._deal_volume_associations(volume, lun)
+ self._deal_volume_associations(volume, cim_vol_path)
- in_params = {'TheElement': lun.path}
+ in_params = {'TheElement': cim_vol_path}
# Delete returns None or Job number
- return self._pi("volume_delete", SmisCommon.JOB_RETRIEVE_NONE, None,
- *(self._c.InvokeMethod('ReturnToStoragePool',
- scs.path,
- **in_params)))[0]
+ return self._c.invoke_method(
+ 'ReturnToStoragePool', cim_scs.path, in_params)[0]
@handle_cim_errors
"""
Re-size a volume
"""
- scs = self._c.get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
+
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
in_params = {'ElementType': pywbem.Uint16(2),
- 'TheElement': lun.path,
+ 'TheElement': cim_vol_path,
'Size': pywbem.Uint64(new_size_bytes)}
- return self._pi("volume_resize", SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- scs.path, **in_params)))
+ return self._c.invoke_method(
+ 'CreateOrModifyElementFromStoragePool', cim_scs.path,
+ in_params, retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
"""
"""
rc = [None, None]
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- system_id, raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(system_id, raise_error=False)
rs_cap = self._c.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_ReplicationServiceCapabilities')[0]
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")
- rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
- volume_src.system_id,
- raise_error=False)
+ cim_rs = self._c.cim_rs_of_sys_id(
+ volume_src.system_id, raise_error=False)
# Some (EMC VMAX, Dot hill) SMI-S Provider allow duplicated
# ElementName, we have to do pre-check here.
raise LsmError(ErrorNumber.NAME_CONFLICT,
"Volume with name '%s' already exists!" % name)
cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)
- lun = self._get_cim_instance_by_id('Volume', volume_src.id)
+ src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
+ self._c, volume_src)
method = 'CreateElementReplica'
sync, mode = self._get_supported_sync_and_mode(
in_params = {'ElementName': name,
'SyncType': sync,
#'Mode': mode,
- 'SourceElement': lun.path,
+ 'SourceElement': src_cim_vol_path,
'WaitForCopyState': dmtf.COPY_STATE_SYNC}
method = 'CreateReplica'
# Check for storage configuration service
- rs = self._c.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', volume_src.system_id,
- raise_error=False)
+ cim_rs = self._c.cim_scs_of_sys_id(
+ volume_src.system_id, raise_error=False)
ct = Volume.REPLICATE_CLONE
in_params = {'ElementName': name,
'CopyType': ct,
- 'SourceElement': lun.path}
+ 'SourceElement': src_cim_vol_path}
in_params['TargetPool'] = cim_pool_path
- return self._pi("volume_replicate",
- SmisCommon.JOB_RETRIEVE_VOLUME, None,
- *(self._c.InvokeMethod(method,
- rs.path, **in_params)))
+ return self._c.invoke_method(
+ method, cim_rs.path, in_params,
+ retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")
- def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
+ def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
rc = SmisCommon.SNIA_INVOKE_FAILED
out = None
@@ -1228,12 +913,12 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
cim_dev_mg_path = None
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
cim_dev_mg_path = self._check_exist_cim_dev_mg(
- name, cim_gmm_path, cim_vol_path, vol_id)
+ name, cim_gmms_path, cim_vol_path, vol_id)
raise
@@ -1245,7 +930,7 @@ def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
return cim_dev_mg_path
- def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
+ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
"""
Create CIM_TargetMaskingGroup
@@ -1276,7 +961,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
cim_tgt_mg_path = None
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
@@ -1293,7 +978,7 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmm_path, name,
return cim_tgt_mg_path
- def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
+ def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
in_params = {
'ElementName': name,
@@ -1302,7 +987,7 @@ def _cim_spc_path_create(self, cim_gmm_path, cim_init_mg_path,
'DeviceMaskingGroup': cim_dev_mg_path,
}
- (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmms_path,
**in_params)
return self._wait_invoke(
"""
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_init_mg = self._cim_init_mg_of_id(access_group.id,
- raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path)
+ cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
"access group init_type: %d" %
access_group.init_type)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'],
- raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')
# We have to create the SPC and dev_mg now.
cim_tgt_mg_path = self._cim_tgt_mg_path_create(
- cim_sys.path, cim_gmm_path, access_group.name,
+ cim_sys.path, cim_gmms.path, access_group.name,
access_group.init_type)
cim_dev_mg_path = self._cim_dev_mg_path_create(
- cim_gmm_path, access_group.name, cim_vol.path, volume.id)
+ cim_gmms.path, access_group.name, cim_vol_path, volume.id)
# Done when SPC created.
self._cim_spc_path_create(
- cim_gmm_path, cim_init_mg.path, cim_tgt_mg_path,
+ cim_gmms.path, cim_init_mg_path, cim_tgt_mg_path,
cim_dev_mg_path, access_group.name)
# CIM_InitiatorMaskingGroup might have multiple SPC when having
# many tgt_mg. It's seldom use, but possible.
# Check whether already masked
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
# Masked.
return None
ResultClass='CIM_DeviceMaskingGroup')[0]
in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None
return self._volume_mask_old(access_group, volume, flags)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_inits = self._cim_init_of_spc(cim_spc.path)
+ cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc_path)
raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
"Access group %s is empty(no member), " %
access_group.id +
"will not do volume_mask()")
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_css_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, ['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
in_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path],
+ 'ProtocolControllers': [cim_spc_path],
'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}
(rc, out) = self._c.InvokeMethod(
'ExposePaths',
- cim_css_path, **in_params)
+ cim_ccs.path, **in_params)
self._wait_invoke(rc, out)
return None
If SupportedDeviceGroupFeatures does not allow empty
DeviceMaskingGroup in SPC, we remove SPC and DeviceMaskingGroup.
"""
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
- cim_gmm_cap = self._c.Associators(
+ cim_gmms_cap = self._c.Associators(
cim_sys.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_GroupMaskingMappingCapabilities',
flag_empty_dev_in_spc = False
if dmtf.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
flag_empty_dev_in_spc = True
if ((dmtf.GMM_CAP_DELETE_SPC not in
- cim_gmm_cap['SupportedSynchronousActions']) and
+ cim_gmms_cap['SupportedSynchronousActions']) and
(dmtf.GMM_CAP_DELETE_SPC not in
raise LsmError(
ErrorNumber.NO_SUPPORT,
"volume_unmask() not supported. It requires one of these "
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(volume.system_id)
cim_spcs_path = self._c.AssociatorNames(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController')
}
(rc, out) = self._c.InvokeMethod(
'DeleteMaskingView',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
in_params = {
'MaskingGroup': cim_dev_mg_path,
- 'Members': [cim_vol.path],
+ 'Members': [cim_vol_path],
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
return None
return self._volume_unmask_old(access_group, volume)
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id,
- property_list=['Name'], raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
+ cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
hide_params = {'LUNames': [cim_vol['Name']],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
- (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs_path,
+ (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)
self._wait_invoke(rc, out)
return None
return True
rc = True
rc = False
return rc
- def _cim_spc_of_id(self, access_group_id, property_list=None,
- """
- Return CIMInstance of CIM_SCSIProtocolController
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- property_list = ['DeviceID']
- property_list = merge_list(property_list, ['DeviceID'])
-
- cim_spcs = self._c.EnumerateInstances(
- 'CIM_SCSIProtocolController', PropertyList=property_list)
-
- return cim_spc
-
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
"""
Return a list of CIM_SCSIProtocolController.
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_ControllerConfigurationService
|
| CIM_ConcreteDependency
v
CIM_SCSIProtocolController
"""
- cim_ccss_path = []
+ cim_ccs = None
rc_cim_spcs = []
property_list = []
- cim_ccss_path = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(system_id, raise_error=False)
error_code = tuple(ce)[0]
if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported ' +
'by this array')
- cim_ccs_path = None
- cim_ccs_path = cim_ccss_path[0]
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Got %d instance of " % len(cim_ccss_path) +
- "ControllerConfigurationService from %s" %
- cim_sys_path + " in _cim_spc_of()")
+
cim_spcs = self._c.Associators(
- cim_ccs_path,
+ cim_ccs.path,
AssocClass='CIM_ConcreteDependency',
ResultClass='CIM_SCSIProtocolController',
PropertyList=property_list)
rc_cim_spcs.append(cim_spc)
return rc_cim_spcs
- """
- Take CIM_SCSIProtocolController and return a list of
- CIM_StorageHardwareID, both are CIMInstance.
- CIM_SCSIProtocolController
- |
- | CIM_AssociatedPrivilege
- v
- CIM_StorageHardwareID
-
- CIM_SCSIProtocolController
- |
- | CIM_AuthorizedTarget
- v
- CIM_AuthorizedPrivilege
- |
- | CIM_AuthorizedSubject
- v
- CIM_StorageHardwareID
-
- Method A defined in SNIA SMIS 1.6 deprecated the Method B and Method A
- saved 1 query which provide better performance.
- Hence we try method A.
- Maybe someday, we will stop trying after knowing array's supported
- SMIS version.
- """
- cim_inits = []
- property_list = []
-
- if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_6,
- return self._c.Associators(
- cim_spc_path,
- AssocClass='CIM_AssociatedPrivilege',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
- cim_aps_path = self._c.AssociatorNames(
- cim_spc_path,
- AssocClass='CIM_AuthorizedTarget',
- ResultClass='CIM_AuthorizedPrivilege')
- cim_inits.extend(self._c.Associators(
- cim_ap_path,
- AssocClass='CIM_AuthorizedSubject',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list))
- return cim_inits
-
- """
- CIM_InitiatorMaskingGroup
- |
- | CIM_MemberOfCollection
- v
- CIM_StorageHardwareID
- """
- property_list = []
- return self._c.Associators(
- cim_init_mg_path,
- AssocClass='CIM_MemberOfCollection',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=property_list)
-
@handle_cim_errors
mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vols = []
- cim_vol_pros = self._cim_vol_pros()
+ cim_vol_pros = smis_vol.cim_vol_pros()
# Workaround for EMC VNX/CX
mask_type = smis_cap.MASK_TYPE_MASK
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros))
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)
cim_vols = self._c.Associators(
- cim_spc.path,
+ cim_spc_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
-
- return [self._new_vol(v) for v in cim_vols]
+ rc = []
+ pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
+ sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
+ rc.append(
+ smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id))
+ return rc
@handle_cim_errors
rc = []
mask_type = smis_cap.mask_type(self._c, raise_error=True)
- cim_vol = self._get_cim_instance_by_id(
- 'Volume', volume.id, raise_error=True)
+ cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
# Workaround for EMC VNX/CX
cim_spc_pros = []
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
cim_spcs = self._c.Associators(
- cim_vol.path,
+ cim_vol_path,
AssocClass='CIM_ProtocolControllerForUnit',
ResultClass='CIM_SCSIProtocolController',
PropertyList=cim_spc_pros)
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
cim_init_mgs = self._c.Associators(
cim_spc.path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, volume.system_id)
- for x in cim_init_mgs))
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, x, volume.system_id)
+ for x in cim_init_mgs))
- rc.extend(
- [self._cim_spc_to_lsm(cim_spc, volume.system_id)])
+ rc.append(
+ smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, volume.system_id))
return rc
- def _cim_init_mg_of_id(self, access_group_id, property_list=None,
- """
- Return CIMInstance of CIM_InitiatorMaskingGroup
- Return None if not found.
- Raise error if not found and raise_error is True
- """
- property_list = ['InstanceID']
- property_list = merge_list(property_list, ['InstanceID'])
-
- cim_init_mgs = self._c.EnumerateInstances(
- 'CIM_InitiatorMaskingGroup', PropertyList=property_list)
-
- return cim_init_mg
-
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "AccessGroup %s not found" % access_group_id)
- return None
-
"""
- There is no CIM_ComputerSystem association to
- CIM_ComputerSystem
- |
- | CIM_HostedService
- v
CIM_GroupMaskingMappingService
|
| CIM_ServiceAffectsElement
property_list = []
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system_id)
return self._c.Associators(
- cim_gmm_path,
+ cim_gmms.path,
AssocClass='CIM_ServiceAffectsElement',
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)
cim_sys_pros = smis_sys.cim_sys_id_pros()
cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
# Workaround for EMC VNX/CX.
system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
- cim_init_mg_pros)
- rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
- for x in cim_init_mgs))
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mgs = self._cim_init_mg_of(
+ system_id, cim_init_mg_pros)
+ rc.extend(
+ list(
+ smis_ag.cim_init_mg_to_lsm_ag(self._c, x, system_id)
+ for x in cim_init_mgs))
- cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
+ cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
rc.extend(
- list(self._cim_spc_to_lsm(cim_spc, system_id)
- for cim_spc in cim_spcs))
+ list(
+ smis_ag.cim_spc_to_lsm_ag(self._c, cim_spc, system_id)
+ for cim_spc in cim_spcs))
raise LsmError(ErrorNumber.PLUGIN_BUG,
"_get_cim_spc_by_id(): Got invalid mask_type: "
return search_property(rc, search_key, search_value)
"""
Check whether CIM_StorageHardwareID exists, if not, create new one.
"""
"SMI-S Plugin does not support init_type %d" %
init_type)
- return self._cim_init_path_create(
- cim_sys_path, init_id, dmtf_id_type)
+ return self._cim_init_path_create(system_id, init_id, dmtf_id_type)
"""
Create a CIM_StorageHardwareID.
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._c.get_cim_service_path(
- cim_sys_path, 'CIM_StorageHardwareIDManagementService')
+ cim_hwms = self._c.cim_hwms_of_sys_id(system_id)
in_params = {'StorageID': init_id,
'IDType': pywbem.Uint16(dmtf_id_type)}
(rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- cim_hw_srv_path, **in_params)
+ cim_hwms.path, **in_params)
# CreateStorageHardwareID does not allow ASYNC
return self._wait_invoke(
rc, out, out_key='HardwareID',
"new initiator which is not supported by LSM yet. "
"Please do it via EMC vendor specific tools.")
- cim_init_mg = self._cim_init_mg_of_id(access_group.id)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
# Check whether already added.
return copy.deepcopy(access_group)
cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ access_group.system_id, init_id, init_type)
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
new_cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
expect_class='CIM_InitiatorMaskingGroup')
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
new_cim_init_mg = self._c.GetInstance(
new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
LocalOnly=False)
- return self._cim_init_mg_to_lsm(
- new_cim_init_mg, access_group.system_id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, new_cim_init_mg, access_group.system_id)
@handle_cim_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
"Please do it via EMC vendor specific tools. "
"EMC VNX does not support adding iSCSI IQN neither")
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
+ self._c, access_group)
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- exist_cim_inits = self._cim_init_of_spc(cim_spc.path, cim_init_pros)
+ exist_cim_inits = smis_ag.cim_init_of_cim_spc_path(
+ self._c, cim_spc_path)
# Check to see if we have this initiator already, if not we
# create it and then add to the view.
- self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)
+ self._cim_init_path_check_or_create(
+ access_group.system_id, init_id, init_type)
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
in_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
(rc, out) = self._c.InvokeMethod('ExposePaths',
- cim_ccs_path, **in_params)
+ cim_ccs.path, **in_params)
cim_spc_path = self._wait_invoke(
rc, out, out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')
- cim_spc_pros = self._cim_spc_pros()
+ cim_spc_pros = smis_ag.cim_spc_pros()
cim_spc = self._c.GetInstance(
cim_spc_path, PropertyList=cim_spc_pros, LocalOnly=False)
- return self._cim_spc_to_lsm(cim_spc, access_group.system_id)
+ return smis_ag.cim_spc_to_lsm_ag(
+ self._c, cim_spc, access_group.system_id)
"""
Call CIM_GroupMaskingMappingService.RemoveMembers() against
CIM_InitiatorMaskingGroup.
"""
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
-
- cim_init_mg_pros = self._cim_init_mg_pros()
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True, property_list=cim_init_mg_pros)
-
- cim_init_pros = self._property_list_of_id('Initiator')
- cur_cim_inits = self._cim_init_of_init_mg(
- cim_init_mg.path, property_list=cim_init_pros)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
+ cur_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
+ self._c, cim_init_mg_path)
cim_init = None
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
# RemoveMembers from InitiatorMaskingGroup
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Members': [cim_init.path],
}
(rc, out) = self._c.InvokeMethod(
'RemoveMembers',
- cim_gmm_path, **in_params)
+ cim_gmms.path, **in_params)
self._wait_invoke(rc, out)
- return self._cim_init_mg_to_lsm(
- cim_init_mg, access_group.system_id)
+
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
+ cim_init_mg = self._c.GetInstance(
+ cim_init_mg_path, PropertyList=cim_init_mg_pros)
+
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, cim_init_mg, access_group.system_id)
@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, init_type,
@@ -2107,17 +1651,14 @@ def access_group_initiator_delete(self, access_group, init_id, init_type,
return self._ag_init_del_old(access_group, init_id)
- cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
+ cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
- cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
-
- cim_ccs_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_ControllerConfigurationService')
+ cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
hide_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [cim_spc.path]}
+ 'ProtocolControllers': [cim_spc_path]}
(rc, out) = self._c.InvokeMethod(
- 'HidePaths', cim_ccs_path, **hide_params)
+ 'HidePaths', cim_ccs.path, **hide_params)
self._wait_invoke(rc, out)
return None
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id,
- ['DeleteOnCompletion'])
+ cim_job = self._c.cim_job_of_job_id(job_id, ['DeleteOnCompletion'])
# See if we should delete the job
return search_property(rc, search_key, search_value)
- return ['ElementName', 'InstanceID']
-
- ag_name = cim_init_mg['ElementName']
- ag_id = md5(cim_init_mg['InstanceID'])
- cim_init_pros = self._property_list_of_id('Initiator')
- cim_init_pros.extend(['IDType'])
- cim_inits = self._cim_init_of_init_mg(cim_init_mg.path, cim_init_pros)
- (init_ids, init_type) = self._cim_inits_to_lsm(cim_inits)
- return AccessGroup(ag_id, ag_name, init_ids, init_type, system_id)
-
def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
"""
return None
- def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
+ def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
"""
This is buggy check, but it works on EMC VMAX which is only supported
@@ -2632,14 +2160,14 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
break
# Check whether cim_vol included.
- cim_vol_pros = self._property_list_of_id('Volume')
+ cim_vol_pros = smis_vol.cim_vol_id_pros()
cim_vols = self._c.Associators(
cim_dev_mg.path,
AssocClass='CIM_OrderedMemberOfCollection',
ResultClass='CIM_StorageVolume',
PropertyList=cim_vol_pros)
return cim_dev_mg.path
# We should add this volume to found DeviceMaskingGroup
@@ -2649,7 +2177,7 @@ def _check_exist_cim_dev_mg(self, name, cim_gmm_path, cim_vol_path,
}
(rc, out) = self._c.InvokeMethod(
'AddMembers',
- cim_gmm_path, **in_params)
+ cim_gmms_path, **in_params)
self._wait_invoke(rc, out)
return cim_dev_mg.path
@@ -2705,21 +2233,20 @@ def access_group_create(self, name, init_id, init_type, system,
"iSCSI IQN access group")
cim_init_path = self._cim_init_path_check_or_create(
- cim_sys.path, init_id, init_type)
+ system.id, init_id, init_type)
# Create CIM_InitiatorMaskingGroup
- cim_gmm_path = self._c.get_cim_service_path(
- cim_sys.path, 'CIM_GroupMaskingMappingService')
+ cim_gmms = self._c.cim_gmms_of_sys_id(system.id)
in_params = {'GroupName': name,
'Members': [cim_init_path],
'Type': dmtf.MASK_GROUP_TYPE_INIT}
- cim_init_mg_pros = self._cim_init_mg_pros()
+ cim_init_mg_pros = smis_ag.cim_init_mg_pros()
(rc, out) = self._c.InvokeMethod(
- 'CreateGroup', cim_gmm_path, **in_params)
+ 'CreateGroup', cim_gmms.path, **in_params)
cim_init_mg_path = self._wait_invoke(
rc, out, out_key='MaskingGroup',
@@ -2739,8 +2266,8 @@ def access_group_create(self, name, init_id, init_type, system,
- return self._cim_init_mg_to_lsm(
- exist_cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(
+ self._c, exist_cim_init_mg, system.id)
# Name does not match.
raise LsmError(ErrorNumber.EXISTS_INITIATOR,
@@ -2753,7 +2280,7 @@ def access_group_create(self, name, init_id, init_type, system,
# Since 1) already checked whether any group containing
# requested init_id, now, it's surly a conflict.
exist_cim_init_mgs = self._cim_init_mg_of(
- cim_sys.path, property_list=['ElementName'])
+ system.id, property_list=['ElementName'])
raise LsmError(ErrorNumber.NAME_CONFLICT,
@@ -2764,7 +2291,7 @@ def access_group_create(self, name, init_id, init_type, system,
cim_init_mg = self._c.GetInstance(
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
- return self._cim_init_mg_to_lsm(cim_init_mg, system.id)
+ return smis_ag.cim_init_mg_to_lsm_ag(self._c, cim_init_mg, system.id)
@handle_cim_errors
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
raise_error=True)
- cim_init_mg = self._cim_init_mg_of_id(
- access_group.id, raise_error=True)
+ cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
+ self._c, access_group)
# Check whether still have volume masked.
cim_spcs_path = self._c.AssociatorNames(
- cim_init_mg.path,
+ cim_init_mg_path,
AssocClass='CIM_AssociatedInitiatorMaskingGroup',
ResultClass='CIM_SCSIProtocolController')
"Access Group %s has volume masked" %
access_group.id)
- cim_gmm_path = self._c.AssociatorNames(
- cim_init_mg.path,
- AssocClass='CIM_ServiceAffectsElement',
- ResultClass='CIM_GroupMaskingMappingService')[0]
+ cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
in_params = {
- 'MaskingGroup': cim_init_mg.path,
+ 'MaskingGroup': cim_init_mg_path,
'Force': True,
}
- (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmm_path,
+ (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmms.path,
**in_params)
self._wait_invoke(rc, out)
diff --git a/plugin/smispy/smis_ag.py b/plugin/smispy/smis_ag.py
new file mode 100644
index 0000000..43aa7ac
--- /dev/null
+++ b/plugin/smispy/smis_ag.py
@@ -0,0 +1,205 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+"""
+This module intend to provide independent methods for lsm.AccessGroup and
+volume masking/unmasking.
+"""
+
+from pywbem import CIMError, CIM_ERR_NOT_FOUND
+
+from lsm import AccessGroup, md5, LsmError, ErrorNumber
+
+from lsm.plugin.smispy.smis_common import SmisCommon
+from lsm.plugin.smispy import dmtf
+from lsm.plugin.smispy.utils import cim_path_to_path_str, path_str_to_cim_path
+
+_CIM_INIT_PROS = ['StorageID', 'IDType']
+
+
+ """
+ Retrieve AccessGroup.init_ids and AccessGroup.init_type from
+ a list of CIM_StorageHardwareID.
+ """
+ init_ids = []
+ init_type = AccessGroup.INIT_TYPE_UNKNOWN
+ init_types = []
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_WWPN)
+ init_ids.append(cim_init['StorageID'])
+ init_types.append(AccessGroup.INIT_TYPE_ISCSI_IQN)
+ # Skip if not a iscsi initiator IQN or WWPN.
+ continue
+
+ init_type_dict = {}
+ init_type_dict[cur_init_type] = 1
+
+ init_type = init_types[0]
+ init_type = AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED
+ return (init_ids, init_type)
+
+
+ """
+ Return the property of CIM_SCSIProtocolController required to gernarate
+ lsm.AccessGroup
+ 'EMCAdapterRole' is for EMC VNX only.
+ """
+ return ['DeviceID', 'ElementName', 'StorageID', 'EMCAdapterRole',
+ 'SystemName']
+
+
+ """
+ Return the property of CIM_InitiatorMaskingGroup required to gernarate
+ lsm.AccessGroup
+ """
+ return ['ElementName', 'InstanceID']
+
+
+ """
+ Return a list of CIM_StorageHardwareID associated to cim_spc.
+ Only contain ['StorageID', 'IDType'] property.
+ CIM_SCSIProtocolController
+ |
+ | CIM_AssociatedPrivilege
+ v
+ CIM_StorageHardwareID
+
+ CIM_SCSIProtocolController
+ |
+ | CIM_AuthorizedTarget
+ v
+ CIM_AuthorizedPrivilege
+ |
+ | CIM_AuthorizedSubject
+ v
+ CIM_StorageHardwareID
+ """
+ cim_inits = []
+ if smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_6,
+ cim_inits = smis_common.Associators(
+ cim_spc_path,
+ AssocClass='CIM_AssociatedPrivilege',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+ pass
+ raise
+
+ cim_aps_path = smis_common.AssociatorNames(
+ cim_spc_path,
+ AssocClass='CIM_AuthorizedTarget',
+ ResultClass='CIM_AuthorizedPrivilege')
+
+ cim_inits.extend(smis_common.Associators(
+ cim_ap_path,
+ AssocClass='CIM_AuthorizedSubject',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS))
+ return cim_inits
+
+
+ """
+ Convert CIM_SCSIProtocolController to lsm.AccessGroup
+ """
+ ag_id = md5(cim_spc['DeviceID'])
+ ag_name = cim_spc['ElementName']
+ cim_inits = cim_init_of_cim_spc_path(smis_common, cim_spc.path)
+ (init_ids, init_type) = _init_id_and_type_of(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_spc.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+ """
+ CIM_InitiatorMaskingGroup
+ |
+ | CIM_MemberOfCollection
+ v
+ CIM_StorageHardwareID
+ Only contain ['StorageID', 'IDType'] property.
+ """
+ return smis_common.Associators(
+ cim_init_mg_path,
+ AssocClass='CIM_MemberOfCollection',
+ ResultClass='CIM_StorageHardwareID',
+ PropertyList=_CIM_INIT_PROS)
+
+
+ """
+ Convert CIM_InitiatorMaskingGroup to lsm.AccessGroup
+ """
+ ag_name = cim_init_mg['ElementName']
+ ag_id = md5(cim_init_mg['InstanceID'])
+ cim_inits = cim_init_of_cim_init_mg_path(smis_common, cim_init_mg.path)
+ (init_ids, init_type) = _init_id_and_type_of(cim_inits)
+ plugin_data = cim_path_to_path_str(cim_init_mg.path)
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, system_id, plugin_data)
+
+
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_SCSIProtocolController
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.AccessGroup instance with empty plugin_data")
+ if smis_common.system_list and \
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_ag.plugin_data)
+
+
+ """
+ Convert lsm.AccessGroup to CIMInstanceName of CIM_InitiatorMaskingGroup
+ using lsm.AccessGroup.plugin_data.
+ This method does not check whether plugin_data is cim_spc or cim_init_mg,
+ caller should make sure that.
+ """
+ return lsm_ag_to_cim_spc_path(smis_common, lsm_ag)
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
index 1309056..1fee9a8 100644
--- a/plugin/smispy/smis_cap.py
+++ b/plugin/smispy/smis_cap.py
@@ -23,17 +23,19 @@
MASK_TYPE_GROUP = 2
"""
Interrogate the supported features of the replication service
"""
- rs = smis_common.get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, raise_error=False)
+ cim_rs = smis_common.cim_rs_of_sys_id(system_id, raise_error=False)
rs_cap = smis_common.Associators(
- rs.path,
+ cim_rs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_ReplicationServiceCapabilities')[0]
+ ResultClass='CIM_ReplicationServiceCapabilities',
+ PropertyList=['SupportedReplicationTypes',
+ 'SupportedAsynchronousActions',
+ 'SupportedSynchronousActions'])[0]
s_rt = rs_cap['SupportedReplicationTypes']
async_actions = rs_cap['SupportedAsynchronousActions']
# Try older storage configuration service
- rs = smis_common.get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', system.id,
- raise_error=False)
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)
- rs_cap = smis_common.Associators(
- rs.path,
+ cim_sc_cap = smis_common.Associators(
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedCopyTypes'])[0]
- sct = rs_cap['SupportedCopyTypes']
+ sct = cim_sc_cap['SupportedCopyTypes']
cap.set(Capabilities.VOLUME_REPLICATE)
cap.set(Capabilities.VOLUME_REPLICATE_COPY)
"""
volumes()
volume_delete()
"""
# CIM_StorageConfigurationService is optional.
- cim_scs_path = smis_common.get_cim_service_path(
- cim_sys_path, 'CIM_StorageConfigurationService')
+ cim_scs = smis_common.cim_scs_of_sys_id(system_id, raise_error=False)
return
# Hence we check CIM_StorageConfigurationCapabilities
# which is mandatory if CIM_StorageConfigurationService is supported.
cim_scs_cap = smis_common.Associators(
- cim_scs_path,
+ cim_scs.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_StorageConfigurationCapabilities',
PropertyList=['SupportedAsynchronousActions',
cap = Capabilities()
- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)
#TODO We need to investigate why our interrogation code doesn't
#work.
return cap
# 'Block Services Package' profile
- _bsp_cap_set(smis_common, cim_sys.path, cap)
+ _bsp_cap_set(smis_common, system.id, cap)
# 'Disk Drive Lite' profile
_disk_cap_set(smis_common, cim_sys.path, cap)
# 'FC Target Ports' and 'iSCSI Target Ports' profiles
_tgt_cap_set(smis_common, cim_sys.path, cap)
- _rs_supported_capabilities(smis_common, system, cap)
+ _rs_supported_capabilities(smis_common, system.id, cap)
return cap
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 4a303c3..80d08d6 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -24,9 +24,12 @@
from pywbem import Uint16, CIMError
import pywbem
+import traceback
+import os
+import datetime
import dmtf
-from lsm import LsmError, ErrorNumber
+from lsm import LsmError, ErrorNumber, md5
from utils import (merge_list)
# Even many CIM_XXX_Service in DMTF shared the same return value
- # defination as SNIA do, but there is no DMTF standard metioned
+ # definition as SNIA do, but there is no DMTF standard motioned
# InvokeMethod() should follow that list of return value.
- # We use SNIA defination here.
+ # We use SNIA definition here.
# SNIA 1.6 rev4 Block book, BSP 5.5.3.12 Return Values section.
SNIA_INVOKE_OK = 0
SNIA_INVOKE_NOT_SUPPORTED = 1
def __init__(self, url, username, password,
namespace=dmtf.DEFAULT_NAMESPACE,
self._wbem_conn = None
self._profile_dict = {}
self.root_blk_cim_rp = None # For root_cim_
self._vendor_product = None # For vendor workaround codes.
self.system_list = system_list
+ self._debug_path = debug_path
namespace = dmtf.DEFAULT_NAMESPACE
@@ -201,7 +205,8 @@ def __init__(self, url, username, password,
# https://bugzilla.redhat.com/show_bug.cgi?id=1039801
pass
- self._wbem_conn.debug = debug
+ self._wbem_conn.debug = True
# Skip profile register check on MegaRAID for better performance.
return _profile_check(
self._profile_dict, profile_name, spec_ver, raise_error)
- def get_class_instance(self, class_name, prop_name, prop_value,
- """
- Gets an instance of a class that optionally matches a specific
- property name and value
- """
- instances = None
- property_list = [prop_name]
- property_list = merge_list(property_list, [prop_name])
-
- cim_xxxs = self.EnumerateInstances(
- class_name, PropertyList=property_list)
- error_code = tuple(ce)[0]
-
- if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
- return None
- raise
-
- return cim_xxx
-
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
- return None
-
- """
- Return None if not supported
- """
- cim_srvs = self.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass=class_name)
- return None
- raise
- return cim_srvs[0]
- return None
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_get_cim_service_path(): Got unexpected(not 1) "
- "count of %s from cim_sys %s: %s" %
- (class_name, cim_sys_path, cim_srvs))
-
cim_syss_path = self._wbem_conn.AssociatorNames(
return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E
+
+ return ['InstanceID']
+
+ """
+ Return CIM_ConcreteJob for given job_id.
+ """
+ property_list = SmisCommon.cim_job_pros()
+ property_list = merge_list(
+ property_list, SmisCommon.cim_job_pros())
+
+ cim_jobs = self.EnumerateInstances(
+ 'CIM_ConcreteJob',
+ PropertyList=property_list)
+ real_job_id = SmisCommon.parse_job_id(job_id)[0]
+ return cim_job
+
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_JOB,
+ "Job %s not found" % job_id)
+
+ """
+ Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction
+ retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or
+ SmisCommon.JOB_RETRIEVE_VOLUME or etc
+ method_data is any string a method would like store for error
+ handling by job_status().
+ """
+ md5(cim_job['InstanceID']), int(retrieve_data), str(method_data))
+
+ """
+ job_id is assembled by a md5 string, retrieve_data and method_data
+ This method will split it and return
+ (md5_str, retrieve_data, method_data)
+ """
+ md5_str = tmp_list[0]
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ method_data = None
+ retrieve_data = int(tmp_list[1])
+ method_data = tmp_list[2]
+ return (md5_str, retrieve_data, method_data)
+
+ def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
+ error_handler=None, retrieve_data=None,
+ """
+ cmd
+ 'CreateOrModifyElementFromStoragePool'
+ cim_path
+ CIM_StorageConfigurationService.path
+ in_params
+ {'ElementName': volume_name,
+ 'ElementType': dmtf_element_type,
+ 'InPool': cim_pool_path,
+ 'Size': pywbem.Uint64(size_bytes)}
+ out_handler
+ self._new_vol_from_name
+ error_handler
+ A reference to a method to handle all exceptions.
+ retrieve_data
+ SmisCommon.JOB_RETRIEVE_XXX, it will be used only
+ when a ASYNC job has been created.
+ method_data
+ A string which will be stored in job_id, it could be used by
+ job_status() to do error checking.
+ """
+ retrieve_data = SmisCommon.JOB_RETRIEVE_NONE
+ (rc, out) = self.InvokeMethod(cmd, cim_path, **in_params)
+
+ # Check to see if operation is done
+ return None, None
+ return None, out_handler(out)
+
+ # We have an async operation
+ job_id = SmisCommon._job_id_of_cim_job(
+ out['Job'], retrieve_data, method_data)
+ return job_id, None
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ 'SMI-S error code indicates operation not supported')
+ # When debugging issues with providers it's helpful to have
+ # the xml request/reply to give to provider developers.
+ os.makedirs(self._debug_path)
+
+ debug_fn = "%s_%s" % (
+ cmd, datetime.datetime.now().isoformat())
+ debug_full = os.path.join(
+ self._debug_path, debug_fn)
+
+ # Dump the request & reply to a file
+ d.write("REQ:\n%s\n\nREPLY:\n%s\n" %
+ (self.last_request, self.last_reply))
+
+ tb = traceback.format_exc()
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= %s" % (cmd, str(rc))+
+ " Debug data exception: %s" % str(tb))
+
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Error: %s rc= %s" % (cmd, str(rc)))
+
+ error_handler(self, method_data)
+ raise
+
+ property_list = ['SystemName']
+
+ cim_srvs = self.EnumerateInstances(
+ srv_name,
+ PropertyList=property_list)
+ return cim_srv
+
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Cannot find any '%s' for requested systemd ID" % srv_name)
+ return None
+
+
+ """
+ Return a CIMInstance of CIM_StorageConfigurationService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageConfigurationService', sys_id, raise_error)
+
+
+ """
+ Return a CIMInstance of CIM_ReplicationService for given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ReplicationService', sys_id, raise_error)
+
+
+ """
+ Return a CIMInstance of CIM_GroupMaskingMappingService for given system
+ id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_GroupMaskingMappingService', sys_id, raise_error)
+
+
+ """
+ Return a CIMInstance of CIM_ControllerConfigurationService for given
+ system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_ControllerConfigurationService', sys_id, raise_error)
+
+ """
+ Return a CIMInstance of CIM_StorageHardwareIDManagementService for
+ given system id.
+ Using 'SystemName' property as system id of a service which is defined
+ by DMTF CIM_Service.
+ """
+ return self._cim_srv_of_sys_id(
+ 'CIM_StorageHardwareIDManagementService', sys_id, raise_error)
diff --git a/plugin/smispy/smis_pool.py b/plugin/smispy/smis_pool.py
index ca0999e..c9f4345 100644
--- a/plugin/smispy/smis_pool.py
+++ b/plugin/smispy/smis_pool.py
@@ -15,11 +15,9 @@
#
-from utils import merge_list
+from utils import merge_list, path_str_to_cim_path, cim_path_to_path_str
import dmtf
from lsm import LsmError, ErrorNumber, Pool
-import json
-from pywbem import CIMInstanceName
element_type, unsupported = _pool_element_type(smis_common, cim_pool)
- plugin_data = _cim_path_to_path_str(cim_pool.path)
+ plugin_data = cim_path_to_path_str(cim_pool.path)
return Pool(pool_id, name, element_type, unsupported,
total_space, free_space,
ErrorNumber.NOT_FOUND_SYSTEM,
"System filtered in URI")
- return _path_str_to_cim_path(lsm_pool.plugin_data)
-
-
- """
- Convert CIMInstanceName to a string which could save in plugin_data
- """
- return json.dumps({
- 'classname': cim_path.classname,
- 'keybindings': dict(cim_path.keybindings),
- 'host': cim_path.host,
- 'namespace': cim_path.namespace,
- })
-
-
- """
- Convert a string into CIMInstanceName.
- """
- path_dict = json.loads(path_str)
- return CIMInstanceName(**path_dict)
+ return path_str_to_cim_path(lsm_pool.plugin_data)
diff --git a/plugin/smispy/smis_sys.py b/plugin/smispy/smis_sys.py
index 64a9723..4101137 100644
--- a/plugin/smispy/smis_sys.py
+++ b/plugin/smispy/smis_sys.py
"'Name' property: %s, %s" % (cim_sys.items(), cim_sys.path))
+ return cim_vol['SystemName']
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "sys_id_of_cim_vol(): Got a CIM_StorageVolume does not have "
+ "'SystemName' property: %s, %s" % (cim_vol.items(), cim_vol.path))
+
+
"""
diff --git a/plugin/smispy/smis_vol.py b/plugin/smispy/smis_vol.py
new file mode 100644
index 0000000..fa52c88
--- /dev/null
+++ b/plugin/smispy/smis_vol.py
@@ -0,0 +1,241 @@
+## Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+"""
+This module intends to provide independent methods related to lsm.Volume and
+CIM_StorageVolume.
+"""
+
+import re
+import sys
+
+from lsm import md5, Volume, LsmError, ErrorNumber
+from lsm.plugin.smispy.utils import (
+ merge_list, cim_path_to_path_str, path_str_to_cim_path)
+from lsm.plugin.smispy import dmtf
+
+ """
+ Return the property of CIM_StorageVolume required to generate
+ lsm.Volume.id
+ """
+ return ['SystemName', 'DeviceID']
+
+
+ """
+ Get lsm.Volume.id from CIM_StorageVolume['DeviceID'] and ['SystemName']
+ """
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "vol_id_of_cim_vol(): Got cim_vol with no "
+ "SystemName or DeviceID property: %s, %s" %
+ (cim_vol.path, cim_vol.items()))
+
+ return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
+
+
+ """
+ Return the PropertyList required for creating new lsm.Volume.
+ """
+ props = ['ElementName', 'NameFormat',
+ 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
+ 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
+ 'OtherNameFormat', 'OtherNameNamespace']
+ props.extend(cim_vol_id_pros())
+ return props
+
+
+ """
+ CIM_StoragePool
+ |
+ | CIM_AllocatedFromStoragePool
+ |
+ v
+ CIM_StorageVolume
+ CIM_StorageVolume['Usage'] == dmtf.VOL_USAGE_SYS_RESERVED will be filtered
+ out.
+ Return a list of CIM_StorageVolume.
+ """
+ property_list = ['Usage']
+ property_list = merge_list(property_list, ['Usage'])
+
+ cim_vols = smis_common.Associators(
+ cim_pool_path,
+ AssocClass='CIM_AllocatedFromStoragePool',
+ ResultClass='CIM_StorageVolume',
+ PropertyList=property_list)
+
+ needed_cim_vols = []
+ if 'Usage' not in cim_vol or \
+ needed_cim_vols.append(cim_vol)
+ return needed_cim_vols
+
+
+ """
+ * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
+ """
+ if not ('NameFormat' in cim_vol and
+ 'NameNamespace' in cim_vol and
+ return None
+ name_format = cim_vol['NameFormat']
+ name_space = cim_vol['NameNamespace']
+ name = cim_vol['Name']
+ return None
+
+ if name_format == dmtf.VOL_NAME_FORMAT_NNA and \
+ return name
+
+
+ """
+ IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
+ Will return the vpd_83 value if found
+ """
+ if not ("IdentifyingDescriptions" in cim_vol and
+ return None
+
+ id_des = cim_vol["IdentifyingDescriptions"]
+ other_info = cim_vol["OtherIdentifyingInfo"]
+ if not (isinstance(cim_vol["IdentifyingDescriptions"], list) and
+ return None
+
+ index = 0
+ len_id_des = len(id_des)
+ len_other_info = len(other_info)
+ return other_info[index]
+ index += 1
+ return None
+
+
+ """
+ Workaround for NetApp, they use OtherNameNamespace and
+ OtherNameFormat.
+ """
+ if 'OtherNameFormat' in cim_vol and \
+ cim_vol['OtherNameFormat'] == 'NAA' and \
+ 'OtherNameNamespace' in cim_vol and \
+ cim_vol['OtherNameNamespace'] == 'VPD83Type3' and \
+ 'OtherIdentifyingInfo' in cim_vol and \
+ isinstance(cim_vol["OtherIdentifyingInfo"], list) and \
+ return cim_vol['OtherIdentifyingInfo'][0]
+
+
+ """
+ ^6[a-f0-9]{31}$
+ """
+ vpd_83 = _vpd83_in_cim_vol_name(cim_vol)
+ vpd_83 = _vpd83_in_cim_vol_otherinfo(cim_vol)
+ vpd_83 = _vpd83_netapp(cim_vol)
+
+ return vpd_83.lower()
+ return ''
+
+
+ """
+ Takes a CIMInstance that represents a volume and returns a lsm Volume
+ """
+
+ # This is optional (User friendly name)
+ user_name = cim_vol["ElementName"]
+ #Better fallback value?
+ user_name = cim_vol['DeviceID']
+
+ vpd_83 = _vpd83_of_cim_vol(cim_vol)
+
+ admin_state = Volume.ADMIN_STATE_ENABLED
+
+ plugin_data = cim_path_to_path_str(cim_vol.path)
+
+ return Volume(
+ vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
+ cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
+ pool_id, plugin_data)
+
+
+ """
+ Convert lsm.Volume to CIMInstanceName of CIM_StorageVolume using
+ lsm.Volume.plugin_data
+ """
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "Got lsm.Volume instance with empty plugin_data")
+ if smis_common.system_list and \
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System filtered in URI")
+
+ return path_str_to_cim_path(lsm_vol.plugin_data)
+
+
+ """
+ Try to minimize time to search.
+ :param volume_name: Volume ElementName
+ :return: True if volume exists with 'name', else False
+ """
+ all_cim_vols = smis_common.EnumerateInstances(
+ 'CIM_StorageVolume', PropertyList=['ElementName'])
+ return True
+ return False
+
+
+ """
+ When we got CIMError, we check whether we got a duplicate volume name.
+ The method_data is the requested volume name.
+ """
+ raise LsmError(ErrorNumber.NAME_CONFLICT,
+ "Volume with name '%s' already exists!" % method_data)
+
+ (error_type, error_msg, error_trace) = sys.exc_info()
+ raise error_type, error_msg, error_trace
diff --git a/plugin/smispy/utils.py b/plugin/smispy/utils.py
index 95332b8..668241f 100644
--- a/plugin/smispy/utils.py
+++ b/plugin/smispy/utils.py
@@ -17,8 +17,9 @@
import traceback
from lsm import (LsmError, ErrorNumber, error)
-from pywbem import (CIMError)
+from pywbem import (CIMError, CIMInstanceName)
import pywbem
+import json
hex_str = hex_str.lower()
return ':'.join(hex_str[i:i + every] for i in range(0, length, every))
+
+
+ """
+ Convert CIMInstanceName to a string which could save in plugin_data
+ """
+ return json.dumps({
+ 'classname': cim_path.classname,
+ 'keybindings': dict(cim_path.keybindings),
+ 'host': cim_path.host,
+ 'namespace': cim_path.namespace,
+ })
+
+
+ """
+ Convert a string into CIMInstanceName.
+ """
+ path_dict = json.loads(path_str)
+ return CIMInstanceName(**path_dict)
Gris Ge
2014-11-12 13:40:06 UTC
Permalink
Post by Tony Asleson
Hi Gris,
Note: For this patch set and any that are already posted, you don't need
to go back and redo, but please try to do things outlined below for
future patch submissions. I will document this stuff on the wiki. We
haven't had much requirements on commits in the past, but I would like
to do so moving forward.
* Each commit should leave the code tree in a working state. This
* Using bisect to find when bugs are introduced
* Allowing cherry-pick to be used for specific commits (typically
bug fixes)
* Take parts of patch set while other later parts are being reworked
- When moving code (add new files if needed), move the code and fix-up
references in one commit. Don't do other changes at the same time
(change signatures of methods, change moved code structure etc.)
- WS & spelling corrections in separate commit
- Use the plugin_test.py across as many arrays the plug-in supports for
every change
- Python, run the pep8 checks
- Run make distcheck
Thanks!
Regards,
Tony
Hi Tony,
It's good to have this note down and restricting every coming patch.
Just a small addition, the 'pylint' is also a good tool to enforce
code style, how about we request coming patch pass pylint
test(ideally, all pass, but convention or refactor message are also
acceptable)?

Thank you.
Best regards.
--
Gris Ge
Tony Asleson
2014-11-12 19:04:51 UTC
Permalink
Post by Gris Ge
Just a small addition, the 'pylint' is also a good tool to enforce
code style, how about we request coming patch pass pylint
test(ideally, all pass, but convention or refactor message are also
acceptable)?
Well before we add that as a requirement we should probably fix up the
existing code where we can. Unfortunately if something is incorrect,
but it's part of the public API it cannot be fixed.

Maybe we should publish a pylint config file too?

Regards,
Tony
Loading...