There is quite a bit of code which is used to determine
what capabilities an array supports. Move this into
a separate file of related functionality.
To make this work we needed to move:
- get_class_instance
- get_cim_service_path
To smis_common.py
I also moved the MASK_* constants to the new file too.
Updated:
- Rename file to smis_cap.py
- Change from class to functions instead
Signed-off-by: Tony Asleson <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
plugin/Makefile.am | 3 +-
plugin/smispy/smis.py | 556 +++++----------------------------------
plugin/smispy/smis_cap.py | 398 ++++++++++++++++++++++++++++
plugin/smispy/smis_common.py | 61 +++++
plugin/smispy/smis_constants.py | 5 +-
6 files changed, 532 insertions(+), 492 deletions(-)
create mode 100644 plugin/smispy/smis_cap.py
diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 5bae9cc..ef39361 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -317,6 +317,7 @@ fi
%{python_sitelib}/lsm/plugin/smispy/utils.*
%{python_sitelib}/lsm/plugin/smispy/smis_constants.*
%{python_sitelib}/lsm/plugin/smispy/smis_common.*
+%{python_sitelib}/lsm/plugin/smispy/smis_cap.*
%{_bindir}/smispy_lsmplugin
%files netapp-plugin
diff --git a/plugin/Makefile.am b/plugin/Makefile.am
index 0ad032b..30b4ea5 100644
--- a/plugin/Makefile.am
+++ b/plugin/Makefile.am
@@ -28,7 +28,8 @@ smispy_PYTHON = \
smispy/utils.py \
smispy/smis_constants.py \
smispy/smis_common.py \
- smispy/dmtf.py
+ smispy/dmtf.py \
+ smispy/smis_cap.py
nstordir = $(plugindir)/nstor
nstor_PYTHON = \
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 15499a7..84537bc 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -29,10 +29,11 @@ import re
import pywbem
from pywbem import CIMError
from smis_constants import *
+import smis_cap
from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
JobStatus, md5, Volume, AccessGroup,
- Capabilities, VERSION, TargetPort,
+ VERSION, TargetPort,
search_property)
from dmtf import *
@@ -172,41 +173,6 @@ class Smis(IStorageAreaNetwork):
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))
- def _get_class_instance(self, class_name, prop_name, prop_value,
- raise_error=True, property_list=None):
- """
- Gets an instance of a class that optionally matches a specific
- property name and value
- """
- instances = None
- if property_list is None:
- property_list = [prop_name]
- else:
- property_list = merge_list(property_list, [prop_name])
-
- try:
- cim_xxxs = self._c.EnumerateInstances(
- class_name, PropertyList=property_list)
- except CIMError as ce:
- error_code = tuple(ce)[0]
-
- if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
- raise_error is False:
- return None
- else:
- raise
-
- for cim_xxx in cim_xxxs:
- if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
- return cim_xxx
-
- if raise_error:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
- return None
-
def _pi(self, msg, retrieve_data, rc, out):
"""
Handle the the process of invoking an operation.
@@ -304,312 +270,23 @@ class Smis(IStorageAreaNetwork):
self.tmo = timeout
+ @handle_cim_errors
def time_out_set(self, ms, flags=0):
self.tmo = ms
+ @handle_cim_errors
def time_out_get(self, flags=0):
return self.tmo
+ @handle_cim_errors
def plugin_unregister(self, flags=0):
self._c = None
- def _bsp_cap_set(self, cim_sys_path, cap):
- """
- Set capabilities for these methods:
- volumes()
- volume_create()
- volume_resize()
- volume_delete()
- """
- # CIM_StorageConfigurationService is optional.
- cim_scs_path = self._get_cim_service_path(
- cim_sys_path, 'CIM_StorageConfigurationService')
-
- if cim_scs_path is None:
- return
-
- # These methods are mandatory for CIM_StorageConfigurationService:
- # CreateOrModifyElementFromStoragePool()
- # ReturnToStoragePool()
- # But SNIA never defined which function of
- # CreateOrModifyElementFromStoragePool() is mandatory.
- # Hence we check CIM_StorageConfigurationCapabilities
- # which is mandatory if CIM_StorageConfigurationService is supported.
- cim_scs_cap = self._c.Associators(
- cim_scs_path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities',
- PropertyList=['SupportedAsynchronousActions',
- 'SupportedSynchronousActions',
- 'SupportedStorageElementTypes'])[0]
-
- element_types = cim_scs_cap['SupportedStorageElementTypes']
- sup_actions = []
-
- if 'SupportedSynchronousActions' in cim_scs_cap:
- if cim_scs_cap['SupportedSynchronousActions']:
- sup_actions.extend(cim_scs_cap['SupportedSynchronousActions'])
-
- if 'SupportedAsynchronousActions' in cim_scs_cap:
- if cim_scs_cap['SupportedAsynchronousActions']:
- sup_actions.extend(cim_scs_cap['SupportedAsynchronousActions'])
-
- if DMTF.SCS_CAP_SUP_ST_VOLUME in element_types or \
- DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
- cap.set(Capabilities.VOLUMES)
- if DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
- cap.set(Capabilities.VOLUME_THIN)
-
- if DMTF.SCS_CAP_VOLUME_CREATE in sup_actions:
- cap.set(Capabilities.VOLUME_CREATE)
-
- if DMTF.SCS_CAP_VOLUME_DELETE in sup_actions:
- cap.set(Capabilities.VOLUME_DELETE)
-
- if DMTF.SCS_CAP_VOLUME_MODIFY in sup_actions:
- cap.set(Capabilities.VOLUME_RESIZE)
-
- return
-
- def _disk_cap_set(self, cim_sys_path, cap):
- if not self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return
-
- cap.set(Capabilities.DISKS)
- return
-
- def _rs_supported_capabilities(self, system, cap):
- """
- Interrogate the supported features of the replication service
- """
- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, raise_error=False)
- if rs:
- rs_cap = self._c.Associators(
- rs.path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_ReplicationServiceCapabilities')[0]
-
- s_rt = rs_cap['SupportedReplicationTypes']
-
- if RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt or \
- RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt:
- cap.set(Capabilities.VOLUME_REPLICATE)
-
- # Mirror support is not working and is not supported at this time.
- # if self.RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
- # cap.set(Capabilities.DeviceID)
-
- # if self.RepSvc.RepTypes.ASYNC_MIRROR_LOCAL \
- # in s_rt:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
-
- if RepSvc.RepTypes.SYNC_SNAPSHOT_LOCAL in s_rt or \
- RepSvc.RepTypes.ASYNC_SNAPSHOT_LOCAL in s_rt:
- cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
-
- if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt or \
- RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
- cap.set(Capabilities.VOLUME_REPLICATE_COPY)
- else:
- # Try older storage configuration service
-
- rs = self._get_class_instance("CIM_StorageConfigurationService",
- 'SystemName',
- system.id, raise_error=False)
-
- if rs:
- rs_cap = self._c.Associators(
- rs.path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
-
- if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
- sct = rs_cap['SupportedCopyTypes']
-
- if sct and len(sct):
- cap.set(Capabilities.VOLUME_REPLICATE)
-
- # Mirror support is not working and is not supported at
- # this time.
-
- # if Smis.CopyTypes.ASYNC in sct:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
-
- # if Smis.CopyTypes.SYNC in sct:
- # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_SYNC)
-
- if CopyTypes.UNSYNCASSOC in sct:
- cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
-
- if CopyTypes.UNSYNCUNASSOC in sct:
- cap.set(Capabilities.VOLUME_REPLICATE_COPY)
-
- def _mask_map_cap_set(self, cim_sys_path, cap):
- """
- In SNIA SMI-S 1.4rev6 'Masking and Mapping' profile:
- CIM_ControllerConfigurationService is mandatory
- and it's ExposePaths() and HidePaths() are mandatory
- """
- if not self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return
-
- cap.set(Capabilities.ACCESS_GROUPS)
- cap.set(Capabilities.VOLUME_MASK)
- cap.set(Capabilities.VOLUME_UNMASK)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
- cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
- cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
-
- # EMC VNX does not support CreateStorageHardwareID for iSCSI
- # and require WWNN for WWPN. Hence both are not supported.
- if cim_sys_path.classname == 'Clar_StorageSystem':
- return
-
- if self._fc_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
- if self._iscsi_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
- return
-
- def _common_capabilities(self, system):
- cap = Capabilities()
-
- self._rs_supported_capabilities(system, cap)
- return cap
-
- def _tgt_cap_set(self, cim_sys_path, cap):
-
- # LSI MegaRAID actually not support FC Target and iSCSI target,
- # They expose empty list of CIM_FCPort
- if cim_sys_path.classname == 'LSIESG_MegaRAIDHBA':
- return
-
- flag_fc_support = self._c.profile_check(
- SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- # One more check for NetApp Typo:
- # NetApp: 'FC Target Port'
- # SMI-S: 'FC Target Ports'
- # Bug reported.
- if not flag_fc_support:
- flag_fc_support = self._c.profile_check(
- 'FC Target Port',
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- flag_iscsi_support = self._c.profile_check(
- SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
-
- if flag_fc_support or flag_iscsi_support:
- cap.set(Capabilities.TARGET_PORTS)
- return
-
- def _group_mask_map_cap_set(self, cim_sys_path, cap):
- """
- We set caps for these methods recording to 1.5+ Group M&M profile:
- access_groups()
- access_groups_granted_to_volume()
- volumes_accessible_by_access_group()
- access_group_initiator_add()
- access_group_initiator_delete()
- volume_mask()
- volume_unmask()
- access_group_create()
- access_group_delete()
- """
- # These are mandatory in SNIA SMI-S.
- # We are not in the position of SNIA SMI-S certification.
- cap.set(Capabilities.ACCESS_GROUPS)
- cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
- cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
- cap.set(Capabilities.VOLUME_MASK)
- if self._fc_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
- cap.set(Capabilities.ACCESS_GROUP_CREATE_WWPN)
- if self._iscsi_tgt_is_supported(cim_sys_path):
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
- cap.set(Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN)
-
- # RemoveMembers is also mandatory
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
-
- cim_gmm_cap_pros = [
- 'SupportedAsynchronousActions',
- 'SupportedSynchronousActions',
- 'SupportedDeviceGroupFeatures']
-
- cim_gmm_cap = self._c.Associators(
- cim_sys_path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_GroupMaskingMappingCapabilities',
- PropertyList=cim_gmm_cap_pros)[0]
-
- # if empty dev group in spc is allowed, RemoveMembers() is enough
- # to do volume_unmask(). RemoveMembers() is mandatory.
- if DMTF.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
- cim_gmm_cap['SupportedDeviceGroupFeatures']:
- cap.set(Capabilities.VOLUME_UNMASK)
-
- # DeleteMaskingView() is optional, this is required by volume_unmask()
- # when empty dev group in spc not allowed.
- elif ((DMTF.GMM_CAP_DELETE_SPC in
- cim_gmm_cap['SupportedSynchronousActions']) or
- (DMTF.GMM_CAP_DELETE_SPC in
- cim_gmm_cap['SupportedAsynchronousActions'])):
- cap.set(Capabilities.VOLUME_UNMASK)
-
- # DeleteGroup is optional, this is required by access_group_delete()
- if ((DMTF.GMM_CAP_DELETE_GROUP in
- cim_gmm_cap['SupportedSynchronousActions']) or
- (DMTF.GMM_CAP_DELETE_GROUP in
- cim_gmm_cap['SupportedAsynchronousActions'])):
- cap.set(Capabilities.ACCESS_GROUP_DELETE)
- return None
-
@handle_cim_errors
def capabilities(self, system, flags=0):
- if self._c.is_netappe():
- cap = self._common_capabilities(system)
-
- #TODO We need to investigate why our interrogation code doesn't
- #work.
- #The array is telling us one thing, but when we try to use it, it
- #doesn't work
- return cap
-
cim_sys = self._get_cim_instance_by_id(
'System', system.id, raise_error=True)
-
- cap = Capabilities()
-
- # 'Block Services Package' profile
- self._bsp_cap_set(cim_sys.path, cap)
-
- # 'Disk Drive Lite' profile
- self._disk_cap_set(cim_sys.path, cap)
-
- # 'Masking and Mapping' and 'Group Masking and Mapping' profiles
- mask_type = self._mask_type()
- if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = MASK_TYPE_MASK
-
- if mask_type == MASK_TYPE_GROUP:
- self._group_mask_map_cap_set(cim_sys.path, cap)
- else:
- self._mask_map_cap_set(cim_sys.path, cap)
-
- # 'FC Target Ports' and 'iSCSI Target Ports' profiles
- self._tgt_cap_set(cim_sys.path, cap)
-
- self._rs_supported_capabilities(system, cap)
- return cap
+ return smis_cap.get(self._c, cim_sys, system)
@handle_cim_errors
def plugin_info(self, flags=0):
@@ -1372,8 +1049,8 @@ class Smis(IStorageAreaNetwork):
"Unsupported provisioning")
# Get the Configuration service for the system we are interested in.
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', pool.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', pool.system_id)
sp = self._get_cim_instance_by_id('Pool', pool.id)
in_params = {'ElementName': volume_name,
@@ -1406,8 +1083,8 @@ class Smis(IStorageAreaNetwork):
def _detach_netapp_e(self, vol, sync):
#Get the Configuration service for the system we are interested in.
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', vol.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', vol.system_id)
in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}
@@ -1423,8 +1100,8 @@ class Smis(IStorageAreaNetwork):
if self._c.is_netappe():
return self._detach_netapp_e(vol, sync)
- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- vol.system_id, raise_error=False)
+ rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
+ vol.system_id, raise_error=False)
if rs:
in_params = {'Operation': pywbem.Uint16(8),
@@ -1528,8 +1205,8 @@ class Smis(IStorageAreaNetwork):
self._detach(vol, s)
def _volume_delete_netapp_e(self, volume, flags=0):
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', volume.system_id)
lun = self._get_cim_instance_by_id('Volume', volume.id)
#If we actually have an association to delete, the volume will be
@@ -1556,8 +1233,8 @@ class Smis(IStorageAreaNetwork):
"""
Delete a volume
"""
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', volume.system_id)
lun = self._get_cim_instance_by_id('Volume', volume.id)
self._deal_volume_associations(volume, lun)
@@ -1575,8 +1252,8 @@ class Smis(IStorageAreaNetwork):
"""
Re-size a volume
"""
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', volume.system_id)
+ scs = self._c.get_class_instance('CIM_StorageConfigurationService',
+ 'SystemName', volume.system_id)
lun = self._get_cim_instance_by_id('Volume', volume.id)
in_params = {'ElementType': pywbem.Uint16(2),
@@ -1596,8 +1273,8 @@ class Smis(IStorageAreaNetwork):
"""
rc = [None, None]
- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system_id, raise_error=False)
+ rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
+ system_id, raise_error=False)
if rs:
rs_cap = self._c.Associators(
@@ -1648,8 +1325,9 @@ class Smis(IStorageAreaNetwork):
or rep_type == Volume.REPLICATE_MIRROR_SYNC:
raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")
- rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- volume_src.system_id, raise_error=False)
+ rs = self._c.get_class_instance("CIM_ReplicationService", 'SystemName',
+ volume_src.system_id,
+ raise_error=False)
if pool is not None:
cim_pool = self._get_cim_instance_by_id('Pool', pool.id)
@@ -1677,9 +1355,9 @@ class Smis(IStorageAreaNetwork):
method = 'CreateReplica'
# Check for storage configuration service
- rs = self._get_class_instance("CIM_StorageConfigurationService",
- 'SystemName', volume_src.system_id,
- raise_error=False)
+ rs = self._c.get_class_instance("CIM_StorageConfigurationService",
+ 'SystemName', volume_src.system_id,
+ raise_error=False)
ct = Volume.REPLICATE_CLONE
if rep_type == Volume.REPLICATE_CLONE:
@@ -1710,30 +1388,6 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.NO_SUPPORT,
"volume-replicate not supported")
- def _get_cim_service_path(self, cim_sys_path, class_name):
- """
- Return None if not supported
- """
- try:
- cim_srvs = self._c.AssociatorNames(
- cim_sys_path,
- AssocClass='CIM_HostedService',
- ResultClass=class_name)
- except CIMError as ce:
- if ce[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
- return None
- else:
- raise
- if len(cim_srvs) == 1:
- return cim_srvs[0]
- elif len(cim_srvs) == 0:
- return None
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_get_cim_service_path(): Got unexpected(not 1) "
- "count of %s from cim_sys %s: %s" %
- (class_name, cim_sys_path, cim_srvs))
-
def _cim_dev_mg_path_create(self, cim_gmm_path, name, cim_vol_path,
vol_id):
rc = INVOKE_FAILED
@@ -1865,7 +1519,7 @@ class Smis(IStorageAreaNetwork):
'Volume', volume.id, ['Name'],
raise_error=True)
- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')
cim_spcs_path = self._c.AssociatorNames(
@@ -1920,15 +1574,15 @@ class Smis(IStorageAreaNetwork):
"""
Grant access to a volume to an group
"""
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
# Workaround for EMC VNX/CX
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._volume_mask_group(access_group, volume, flags)
return self._volume_mask_old(access_group, volume, flags)
@@ -1945,7 +1599,7 @@ class Smis(IStorageAreaNetwork):
cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
- cim_css_path = self._get_cim_service_path(
+ cim_css_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')
cim_vol = self._get_cim_instance_by_id(
@@ -2001,7 +1655,7 @@ class Smis(IStorageAreaNetwork):
"DeviceMaskingGroup in SPC. But target SMI-S provider "
"does not support any of these")
- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')
cim_spcs_path = self._c.AssociatorNames(
@@ -2064,22 +1718,22 @@ class Smis(IStorageAreaNetwork):
@handle_cim_errors
def volume_unmask(self, access_group, volume, flags=0):
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
# Workaround for EMC VNX/CX
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._volume_unmask_group(access_group, volume)
return self._volume_unmask_old(access_group, volume)
def _volume_unmask_old(self, access_group, volume):
cim_sys = self._get_cim_instance_by_id(
'System', access_group.system_id, raise_error=True)
- cim_ccs_path = self._get_cim_service_path(
+ cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')
cim_vol = self._get_cim_instance_by_id(
@@ -2264,18 +1918,18 @@ class Smis(IStorageAreaNetwork):
@handle_cim_errors
def volumes_accessible_by_access_group(self, access_group, flags=0):
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vols = []
cim_vol_pros = self._cim_vol_pros()
# Workaround for EMC VNX/CX
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', access_group.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg = self._cim_init_mg_of_id(
access_group.id, raise_error=True)
@@ -2304,19 +1958,19 @@ class Smis(IStorageAreaNetwork):
@handle_cim_errors
def access_groups_granted_to_volume(self, volume, flags=0):
rc = []
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_vol = self._get_cim_instance_by_id(
'Volume', volume.id, raise_error=True)
# Workaround for EMC VNX/CX
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_sys = self._get_cim_instance_by_id(
'System', volume.system_id, raise_error=True)
if cim_sys.path.classname == 'Clar_StorageSystem':
- mask_type = MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK
cim_spc_pros = None
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_spc_pros = []
else:
cim_spc_pros = self._cim_spc_pros()
@@ -2327,7 +1981,7 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_SCSIProtocolController',
PropertyList=cim_spc_pros)
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg_pros = self._cim_init_mg_pros()
for cim_spc in cim_spcs:
cim_init_mgs = self._c.Associators(
@@ -2386,7 +2040,7 @@ class Smis(IStorageAreaNetwork):
if property_list is None:
property_list = []
- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys_path, 'CIM_GroupMaskingMappingService')
return self._c.Associators(
@@ -2395,35 +2049,10 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_InitiatorMaskingGroup',
PropertyList=property_list)
- def _mask_type(self, raise_error=False):
- """
- Return MASK_TYPE_NO_SUPPORT, MASK_TYPE_MASK or MASK_TYPE_GROUP
- if 'Group Masking and Mapping' profile is supported, return
- MASK_TYPE_GROUP
-
- If raise_error == False, just return MASK_TYPE_NO_SUPPORT
- or, raise NO_SUPPORT error.
- """
- if self._c.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_5,
- raise_error=False):
- return MASK_TYPE_GROUP
- if self._c.profile_check(SmisCommon.SNIA_MASK_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return MASK_TYPE_MASK
- if raise_error:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Target SMI-S provider does not support "
- "%s version %s or %s version %s" %
- (SmisCommon.SNIA_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_4,
- SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5))
- return MASK_TYPE_NO_SUPPORT
-
@handle_cim_errors
def access_groups(self, search_key=None, search_value=None, flags=0):
rc = []
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
cim_sys_pros = self._property_list_of_id('System')
cim_syss = self._root_cim_syss(cim_sys_pros)
@@ -2434,16 +2063,16 @@ class Smis(IStorageAreaNetwork):
# Workaround for EMC VNX/CX.
# Even they claim support of Group M&M via
# CIM_RegisteredProfile, but actually they don't support it.
- mask_type = MASK_TYPE_MASK
+ mask_type = smis_cap.MASK_TYPE_MASK
system_id = self._sys_id(cim_sys)
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
cim_init_mg_pros = self._cim_init_mg_pros()
cim_init_mgs = self._cim_init_mg_of(cim_sys.path,
cim_init_mg_pros)
rc.extend(list(self._cim_init_mg_to_lsm(x, system_id)
for x in cim_init_mgs))
- elif mask_type == MASK_TYPE_MASK:
+ elif mask_type == smis_cap.MASK_TYPE_MASK:
cim_spcs = self._cim_spc_of(cim_sys.path, cim_spc_pros)
rc.extend(
list(self._cim_spc_to_lsm(cim_spc, system_id)
@@ -2481,7 +2110,7 @@ class Smis(IStorageAreaNetwork):
Return CIMInstanceName
Raise error if failed. Return if pass.
"""
- cim_hw_srv_path = self._get_cim_service_path(
+ cim_hw_srv_path = self._c.get_cim_service_path(
cim_sys_path, 'CIM_StorageHardwareIDManagementService')
in_params = {'StorageID': init_id,
@@ -2519,7 +2148,7 @@ class Smis(IStorageAreaNetwork):
cim_init_path = self._cim_init_path_check_or_create(
cim_sys.path, init_id, init_type)
- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')
in_params = {
@@ -2543,9 +2172,9 @@ class Smis(IStorageAreaNetwork):
def access_group_initiator_add(self, access_group, init_id, init_type,
flags=0):
init_id = _lsm_init_id_to_snia(init_id)
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._ag_init_add_group(access_group, init_id, init_type)
else:
return self._ag_init_add_old(access_group, init_id, init_type)
@@ -2578,7 +2207,7 @@ class Smis(IStorageAreaNetwork):
self._cim_init_path_check_or_create(cim_sys.path, init_id, init_type)
- cim_ccs_path = self._get_cim_service_path(
+ cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')
in_params = {'InitiatorPortIDs': [init_id],
@@ -2627,7 +2256,7 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
"Refuse to remove last initiator from access group")
- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')
# RemoveMembers from InitiatorMaskingGroup
@@ -2654,9 +2283,9 @@ class Smis(IStorageAreaNetwork):
"SMI-S plugin does not support "
"access_group_initiator_delete() against NetApp-E")
init_id = _lsm_init_id_to_snia(init_id)
- mask_type = self._mask_type(raise_error=True)
+ mask_type = smis_cap.mask_type(self._c, raise_error=True)
- if mask_type == MASK_TYPE_GROUP:
+ if mask_type == smis_cap.MASK_TYPE_GROUP:
return self._ag_init_del_group(access_group, init_id)
else:
return self._ag_init_del_old(access_group, init_id)
@@ -2667,7 +2296,7 @@ class Smis(IStorageAreaNetwork):
cim_spc = self._cim_spc_of_id(access_group.id, raise_error=True)
- cim_ccs_path = self._get_cim_service_path(
+ cim_ccs_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')
hide_params = {'InitiatorPortIDs': [init_id],
@@ -2974,54 +2603,6 @@ class Smis(IStorageAreaNetwork):
else:
return cim_syss
- def _fc_tgt_is_supported(self, cim_sys_path):
- """
- Return True if FC Target Port 1.4+ profile is supported.
- """
- flag_fc_support = self._c.profile_check(
- SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- # One more check for NetApp Typo:
- # NetApp: 'FC Target Port'
- # SMI-S: 'FC Target Ports'
- # Bug reported.
- if not flag_fc_support:
- flag_fc_support = self._c.profile_check(
- 'FC Target Port',
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- if flag_fc_support:
- return True
- else:
- return False
-
- def _iscsi_tgt_is_supported(self, cim_sys_path):
- """
- Return True if FC Target Port 1.4+ profile is supported.
- We use CIM_iSCSIProtocolEndpoint as it's a start point we are
- using in our code of target_ports().
- """
- if self._c.profile_check(SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False):
- return True
- return False
-
- def _multi_sys_is_supported(self):
- """
- Return True if Multiple ComputerSystem 1.4+ profile is supported.
- Return False else.
- """
- flag_multi_sys_support = self._c.profile_check(
- SmisCommon.SNIA_MULTI_SYS_PROFILE,
- SmisCommon.SMIS_SPEC_VER_1_4,
- raise_error=False)
- if flag_multi_sys_support:
- return True
- else:
- return False
-
@staticmethod
def _is_frontend_fc_tgt(cim_fc_tgt):
"""
@@ -3044,7 +2625,7 @@ class Smis(IStorageAreaNetwork):
else:
property_list = merge_list(property_list, ['UsageRestriction'])
all_cim_syss_path = [cim_sys_path]
- if self._multi_sys_is_supported():
+ if smis_cap.multi_sys_is_supported(self._c):
all_cim_syss_path.extend(
self._leaf_cim_syss_path_of(cim_sys_path))
for cur_cim_sys_path in all_cim_syss_path:
@@ -3123,7 +2704,7 @@ class Smis(IStorageAreaNetwork):
else:
property_list = merge_list(property_list, ['Role'])
all_cim_syss_path = [cim_sys_path]
- if self._multi_sys_is_supported():
+ if smis_cap.multi_sys_is_supported(self._c):
all_cim_syss_path.extend(
self._leaf_cim_syss_path_of(cim_sys_path))
for cur_cim_sys_path in all_cim_syss_path:
@@ -3313,8 +2894,8 @@ class Smis(IStorageAreaNetwork):
property_list=self._property_list_of_id('System'))
for cim_sys in cim_syss:
system_id = self._sys_id(cim_sys)
- flag_fc_support = self._fc_tgt_is_supported(cim_sys.path)
- flag_iscsi_support = self._iscsi_tgt_is_supported(cim_sys.path)
+ flag_fc_support = smis_cap.fc_tgt_is_supported(self._c)
+ flag_iscsi_support = smis_cap.iscsi_tgt_is_supported(self._c)
# Assuming: if one system does not support target_ports(),
# all systems from the same provider will not support
@@ -3544,8 +3125,8 @@ class Smis(IStorageAreaNetwork):
"EMC VNX/CX which lacks the support of SNIA 1.5+ "
"Group Masking and Mapping profile")
- flag_fc_support = self._fc_tgt_is_supported(cim_sys.path)
- flag_iscsi_support = self._iscsi_tgt_is_supported(cim_sys.path)
+ flag_fc_support = smis_cap.fc_tgt_is_supported(self._c)
+ flag_iscsi_support = smis_cap.iscsi_tgt_is_supported(self._c)
if init_type == AccessGroup.INIT_TYPE_WWPN and not flag_fc_support:
raise LsmError(ErrorNumber.NO_SUPPORT,
@@ -3564,7 +3145,7 @@ class Smis(IStorageAreaNetwork):
cim_sys.path, init_id, init_type)
# Create CIM_InitiatorMaskingGroup
- cim_gmm_path = self._get_cim_service_path(
+ cim_gmm_path = self._c.get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')
in_params = {'GroupName': name,
@@ -3622,6 +3203,7 @@ class Smis(IStorageAreaNetwork):
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
return self._cim_init_mg_to_lsm(cim_init_mg, system.id)
+ @handle_cim_errors
def access_group_delete(self, access_group, flags=0):
self._c.profile_check(
SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
diff --git a/plugin/smispy/smis_cap.py b/plugin/smispy/smis_cap.py
new file mode 100644
index 0000000..ae11460
--- /dev/null
+++ b/plugin/smispy/smis_cap.py
@@ -0,0 +1,398 @@
+# Copyright (C) 2014 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from lsm import Capabilities, LsmError, ErrorNumber
+from smis_constants import *
+from dmtf import *
+from smis_common import SmisCommon
+
+MASK_TYPE_NO_SUPPORT = 0
+MASK_TYPE_MASK = 1
+MASK_TYPE_GROUP = 2
+
+
+def _rs_supported_capabilities(smis_common, system, cap):
+ """
+ Interrogate the supported features of the replication service
+ """
+ rs = smis_common.get_class_instance("CIM_ReplicationService", 'SystemName',
+ system.id, raise_error=False)
+ if rs:
+ rs_cap = smis_common.Associators(
+ rs.path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_ReplicationServiceCapabilities')[0]
+
+ s_rt = rs_cap['SupportedReplicationTypes']
+
+ if RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt or \
+ RepSvc.Action.CREATE_ELEMENT_REPLICA in s_rt:
+ cap.set(Capabilities.VOLUME_REPLICATE)
+
+ # Mirror support is not working and is not supported at this time.
+ # if RepSvc.RepTypes.SYNC_MIRROR_LOCAL in s_rt:
+ # cap.set(Capabilities.DeviceID)
+
+ # if RepSvc.RepTypes.ASYNC_MIRROR_LOCAL \
+ # in s_rt:
+ # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
+
+ if RepSvc.RepTypes.SYNC_SNAPSHOT_LOCAL in s_rt or \
+ RepSvc.RepTypes.ASYNC_SNAPSHOT_LOCAL in s_rt:
+ cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
+
+ if RepSvc.RepTypes.SYNC_CLONE_LOCAL in s_rt or \
+ RepSvc.RepTypes.ASYNC_CLONE_LOCAL in s_rt:
+ cap.set(Capabilities.VOLUME_REPLICATE_COPY)
+ else:
+ # Try older storage configuration service
+
+ rs = smis_common.get_class_instance("CIM_StorageConfigurationService",
+ 'SystemName', system.id,
+ raise_error=False)
+
+ if rs:
+ rs_cap = smis_common.Associators(
+ rs.path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_StorageConfigurationCapabilities')[0]
+
+ if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
+ sct = rs_cap['SupportedCopyTypes']
+
+ if sct and len(sct):
+ cap.set(Capabilities.VOLUME_REPLICATE)
+
+ # Mirror support is not working and is not supported at
+ # this time.
+
+ # if CopyTypes.ASYNC in sct:
+ # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC)
+
+ # if CopyTypes.SYNC in sct:
+ # cap.set(Capabilities.VOLUME_REPLICATE_MIRROR_SYNC)
+
+ if CopyTypes.UNSYNCASSOC in sct:
+ cap.set(Capabilities.VOLUME_REPLICATE_CLONE)
+
+ if CopyTypes.UNSYNCUNASSOC in sct:
+ cap.set(Capabilities.VOLUME_REPLICATE_COPY)
+
+
+def _bsp_cap_set(smis_common, cim_sys_path, cap):
+ """
+ Set capabilities for these methods:
+ volumes()
+ volume_create()
+ volume_resize()
+ volume_delete()
+ """
+ # CIM_StorageConfigurationService is optional.
+ cim_scs_path = smis_common.get_cim_service_path(
+ cim_sys_path, 'CIM_StorageConfigurationService')
+
+ if cim_scs_path is None:
+ return
+
+ # These methods are mandatory for CIM_StorageConfigurationService:
+ # CreateOrModifyElementFromStoragePool()
+ # ReturnToStoragePool()
+ # But SNIA never defined which function of
+ # CreateOrModifyElementFromStoragePool() is mandatory.
+ # Hence we check CIM_StorageConfigurationCapabilities
+ # which is mandatory if CIM_StorageConfigurationService is supported.
+ cim_scs_cap = smis_common.Associators(
+ cim_scs_path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_StorageConfigurationCapabilities',
+ PropertyList=['SupportedAsynchronousActions',
+ 'SupportedSynchronousActions',
+ 'SupportedStorageElementTypes'])[0]
+
+ element_types = cim_scs_cap['SupportedStorageElementTypes']
+ sup_actions = []
+
+ if 'SupportedSynchronousActions' in cim_scs_cap:
+ if cim_scs_cap['SupportedSynchronousActions']:
+ sup_actions.extend(cim_scs_cap['SupportedSynchronousActions'])
+
+ if 'SupportedAsynchronousActions' in cim_scs_cap:
+ if cim_scs_cap['SupportedAsynchronousActions']:
+ sup_actions.extend(cim_scs_cap['SupportedAsynchronousActions'])
+
+ if DMTF.SCS_CAP_SUP_ST_VOLUME in element_types or \
+ DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
+ cap.set(Capabilities.VOLUMES)
+ if DMTF.SCS_CAP_SUP_THIN_ST_VOLUME in element_types:
+ cap.set(Capabilities.VOLUME_THIN)
+
+ if DMTF.SCS_CAP_VOLUME_CREATE in sup_actions:
+ cap.set(Capabilities.VOLUME_CREATE)
+
+ if DMTF.SCS_CAP_VOLUME_DELETE in sup_actions:
+ cap.set(Capabilities.VOLUME_DELETE)
+
+ if DMTF.SCS_CAP_VOLUME_MODIFY in sup_actions:
+ cap.set(Capabilities.VOLUME_RESIZE)
+
+ return
+
+
+def _disk_cap_set(smis_common, cim_sys_path, cap):
+ if not smis_common.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return
+
+ cap.set(Capabilities.DISKS)
+ return
+
+
+def _group_mask_map_cap_set(smis_common, cim_sys_path, cap):
+ """
+ We set caps for these methods recording to 1.5+ Group M&M profile:
+ access_groups()
+ access_groups_granted_to_volume()
+ volumes_accessible_by_access_group()
+ access_group_initiator_add()
+ access_group_initiator_delete()
+ volume_mask()
+ volume_unmask()
+ access_group_create()
+ access_group_delete()
+ """
+ # These are mandatory in SNIA SMI-S.
+ # We are not in the position of SNIA SMI-S certification.
+ cap.set(Capabilities.ACCESS_GROUPS)
+ cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
+ cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
+ cap.set(Capabilities.VOLUME_MASK)
+ if fc_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
+ cap.set(Capabilities.ACCESS_GROUP_CREATE_WWPN)
+ if iscsi_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
+ cap.set(Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN)
+
+ # RemoveMembers is also mandatory
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
+
+ cim_gmm_cap_pros = [
+ 'SupportedAsynchronousActions',
+ 'SupportedSynchronousActions',
+ 'SupportedDeviceGroupFeatures']
+
+ cim_gmm_cap = smis_common.Associators(
+ cim_sys_path,
+ AssocClass='CIM_ElementCapabilities',
+ ResultClass='CIM_GroupMaskingMappingCapabilities',
+ PropertyList=cim_gmm_cap_pros)[0]
+
+ # if empty dev group in spc is allowed, RemoveMembers() is enough
+ # to do volume_unmask(). RemoveMembers() is mandatory.
+ if DMTF.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
+ cim_gmm_cap['SupportedDeviceGroupFeatures']:
+ cap.set(Capabilities.VOLUME_UNMASK)
+
+ # DeleteMaskingView() is optional, this is required by volume_unmask()
+ # when empty dev group in spc not allowed.
+ elif ((DMTF.GMM_CAP_DELETE_SPC in
+ cim_gmm_cap['SupportedSynchronousActions']) or
+ (DMTF.GMM_CAP_DELETE_SPC in
+ cim_gmm_cap['SupportedAsynchronousActions'])):
+ cap.set(Capabilities.VOLUME_UNMASK)
+
+ # DeleteGroup is optional, this is required by access_group_delete()
+ if ((DMTF.GMM_CAP_DELETE_GROUP in
+ cim_gmm_cap['SupportedSynchronousActions']) or
+ (DMTF.GMM_CAP_DELETE_GROUP in
+ cim_gmm_cap['SupportedAsynchronousActions'])):
+ cap.set(Capabilities.ACCESS_GROUP_DELETE)
+ return None
+
+
+def _mask_map_cap_set(smis_common, cim_sys_path, cap):
+ """
+ In SNIA SMI-S 1.4rev6 'Masking and Mapping' profile:
+ CIM_ControllerConfigurationService is mandatory
+ and it's ExposePaths() and HidePaths() are mandatory
+ """
+ if not smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return
+
+ cap.set(Capabilities.ACCESS_GROUPS)
+ cap.set(Capabilities.VOLUME_MASK)
+ cap.set(Capabilities.VOLUME_UNMASK)
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
+ cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
+ cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
+
+ # EMC VNX does not support CreateStorageHardwareID for iSCSI
+ # and require WWNN for WWPN. Hence both are not supported.
+ if cim_sys_path.classname == 'Clar_StorageSystem':
+ return
+
+ if fc_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
+ if iscsi_tgt_is_supported(smis_common):
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
+ return
+
+
+def _tgt_cap_set(smis_common, cim_sys_path, cap):
+
+ # LSI MegaRAID actually not support FC Target and iSCSI target,
+ # They expose empty list of CIM_FCPort
+ if cim_sys_path.classname == 'LSIESG_MegaRAIDHBA':
+ return
+
+ flag_fc_support = smis_common.profile_check(
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ # One more check for NetApp Typo:
+ # NetApp: 'FC Target Port'
+ # SMI-S: 'FC Target Ports'
+ # Bug reported.
+ if not flag_fc_support:
+ flag_fc_support = smis_common.profile_check(
+ 'FC Target Port',
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ flag_iscsi_support = smis_common.profile_check(
+ SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+
+ if flag_fc_support or flag_iscsi_support:
+ cap.set(Capabilities.TARGET_PORTS)
+ return
+
+
+def mask_type(smis_common, raise_error=False):
+ """
+ Return MASK_TYPE_NO_SUPPORT, MASK_TYPE_MASK or MASK_TYPE_GROUP
+ if 'Group Masking and Mapping' profile is supported, return
+ MASK_TYPE_GROUP
+
+ If raise_error == False, just return MASK_TYPE_NO_SUPPORT
+ or, raise NO_SUPPORT error.
+ """
+ if smis_common.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_5,
+ raise_error=False):
+ return MASK_TYPE_GROUP
+ if smis_common.profile_check(SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return MASK_TYPE_MASK
+ if raise_error:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support "
+ "%s version %s or %s version %s" %
+ (SmisCommon.SNIA_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ SmisCommon.SNIA_GROUP_MASK_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_5))
+ return MASK_TYPE_NO_SUPPORT
+
+
+def fc_tgt_is_supported(smis_common):
+ """
+ Return True if FC Target Port 1.4+ profile is supported.
+ """
+ flag_fc_support = smis_common.profile_check(
+ SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ # One more check for NetApp Typo:
+ # NetApp: 'FC Target Port'
+ # SMI-S: 'FC Target Ports'
+ # Bug reported.
+ if not flag_fc_support:
+ flag_fc_support = smis_common.profile_check(
+ 'FC Target Port',
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ if flag_fc_support:
+ return True
+ else:
+ return False
+
+
+def iscsi_tgt_is_supported(smis_common):
+ """
+ Return True if FC Target Port 1.4+ profile is supported.
+ We use CIM_iSCSIProtocolEndpoint as it's a start point we are
+ using in our code of target_ports().
+ """
+ if smis_common.profile_check(SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False):
+ return True
+ return False
+
+
+def multi_sys_is_supported(smis_common):
+ """
+ Return True if Multiple ComputerSystem 1.4+ profile is supported.
+ Return False else.
+ """
+ flag_multi_sys_support = smis_common.profile_check(
+ SmisCommon.SNIA_MULTI_SYS_PROFILE,
+ SmisCommon.SMIS_SPEC_VER_1_4,
+ raise_error=False)
+ if flag_multi_sys_support:
+ return True
+ else:
+ return False
+
+
+def get(smis_common, cim_sys, system):
+ cap = Capabilities()
+
+ if smis_common.is_netappe():
+ _rs_supported_capabilities(smis_common, system, cap)
+
+ #TODO We need to investigate why our interrogation code doesn't
+ #work.
+ #The array is telling us one thing, but when we try to use it, it
+ #doesn't work
+ return cap
+
+ # 'Block Services Package' profile
+ _bsp_cap_set(smis_common, cim_sys.path, cap)
+
+ # 'Disk Drive Lite' profile
+ _disk_cap_set(smis_common, cim_sys.path, cap)
+
+ # 'Masking and Mapping' and 'Group Masking and Mapping' profiles
+ mt = mask_type(smis_common)
+ if cim_sys.path.classname == 'Clar_StorageSystem':
+ mt = MASK_TYPE_MASK
+
+ if mask_type == MASK_TYPE_GROUP:
+ _group_mask_map_cap_set(smis_common, cim_sys.path, cap)
+ else:
+ _mask_map_cap_set(smis_common, cim_sys.path, cap)
+
+ # 'FC Target Ports' and 'iSCSI Target Ports' profiles
+ _tgt_cap_set(smis_common, cim_sys.path, cap)
+
+ _rs_supported_capabilities(smis_common, system, cap)
+ return cap
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index cf01b8f..6f91b20 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -27,6 +27,7 @@ import pywbem
from dmtf import DMTF
from lsm import LsmError, ErrorNumber
+from utils import (merge_list)
def _profile_register_load(wbem_conn):
@@ -139,6 +140,7 @@ def _profile_spec_ver_to_num(spec_ver_str):
int(tmp_list[2]))
return None
+
class SmisCommon(object):
SNIA_BLK_ROOT_PROFILE = 'Array'
SNIA_BLK_SRVS_PROFILE = 'Block Services'
@@ -226,6 +228,65 @@ class SmisCommon(object):
return _profile_check(
self._profile_dict, profile_name, spec_ver, raise_error)
+ def get_class_instance(self, class_name, prop_name, prop_value,
+ raise_error=True, property_list=None):
+ """
+ Gets an instance of a class that optionally matches a specific
+ property name and value
+ """
+ instances = None
+ if property_list is None:
+ property_list = [prop_name]
+ else:
+ property_list = merge_list(property_list, [prop_name])
+
+ try:
+ cim_xxxs = self.EnumerateInstances(
+ class_name, PropertyList=property_list)
+ except CIMError as ce:
+ error_code = tuple(ce)[0]
+
+ if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
+ raise_error is False:
+ return None
+ else:
+ raise
+
+ for cim_xxx in cim_xxxs:
+ if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
+ return cim_xxx
+
+ if raise_error:
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "Unable to find class instance %s " % class_name +
+ "with property %s " % prop_name +
+ "with value %s" % prop_value)
+ return None
+
+ def get_cim_service_path(self, cim_sys_path, class_name):
+ """
+ Return None if not supported
+ """
+ try:
+ cim_srvs = self.AssociatorNames(
+ cim_sys_path,
+ AssocClass='CIM_HostedService',
+ ResultClass=class_name)
+ except CIMError as ce:
+ if ce[0] == pywbem.CIM_ERR_NOT_SUPPORTED:
+ return None
+ else:
+ raise
+ if len(cim_srvs) == 1:
+ return cim_srvs[0]
+ elif len(cim_srvs) == 0:
+ return None
+ else:
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "_get_cim_service_path(): Got unexpected(not 1) "
+ "count of %s from cim_sys %s: %s" %
+ (class_name, cim_sys_path, cim_srvs))
+
def _vendor_namespace(self):
if self.root_blk_cim_rp:
cim_syss_path = self._wbem_conn.AssociatorNames(
diff --git a/plugin/smispy/smis_constants.py b/plugin/smispy/smis_constants.py
index 8c184a7..0536cf5 100644
--- a/plugin/smispy/smis_constants.py
+++ b/plugin/smispy/smis_constants.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2014 Red Hat, Inc.
+# Copyright (C) 2014 Red Hat, Inc.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
@@ -66,9 +66,6 @@ JOB_RETRIEVE_POOL = 2
IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989
-MASK_TYPE_NO_SUPPORT = 0
-MASK_TYPE_MASK = 1
-MASK_TYPE_GROUP = 2
class RepSvc(object):
--
1.8.2.1