Discussion:
[Libstoragemgmt-devel] [PATCH 00/11] Capabilities updates (V2)
Tony Asleson
2014-07-29 22:56:07 UTC
Permalink
Note: This is an updated patch set. The first one
was missing some changes.

This is Gris's patch set with modifictions to
1st and 3rd patches. I simplified by just exposing
one method that can be used to retrieve the supported
methods as a dict or all methods as a dict.

The last 2 patches are additions that fix up a couple of
small issues I found in patch series.


I also renamed the patch for one of the pathes named:

"ontap plugin: fix changed capacities" as one of them
was actually for nstor.

Please review.

Gris Ge (8):
python library: lsm.Capacities changes (V3)
test: fix changed capabilities
lsmcli: improve capabilities code (V3)
ontap plugin: fix changed capacities
nstor plugin: fix changed capacities
sim plugin: more strict access group related methods
smis plugin: lsm.Client.capabilities() rewrite
nstor and ontap plugin: change FS_SNAPSHOT_REVERT to
FS_SNAPSHOT_RESTORE

Tony Asleson (3):
nstor.py: Remove references to removed constants.
ontap.py: Remove references to removed constants
C API: Update capabilities constants

.../libstoragemgmt/libstoragemgmt_capabilities.h | 23 +-
plugin/nstor/nstor.py | 14 +-
plugin/ontap/ontap.py | 11 +-
plugin/sim/simarray.py | 44 ++-
plugin/simc/simc_lsmplugin.c | 14 +-
plugin/smispy/smis.py | 419 ++++++++++++++-------
python_binding/lsm/_data.py | 59 ++-
test/cmdtest.py | 22 +-
test/plugin_test.py | 89 +++--
test/tester.c | 36 +-
tools/lsmcli/cmdline.py | 118 +-----
tools/lsmcli/data_display.py | 4 +-
12 files changed, 499 insertions(+), 354 deletions(-)
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:08 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Remove of these capacities:
BLOCK_SUPPORT
FS_SUPPORT
# We don't actually need them.

* Renamed these capabilities:
ACCESS_GROUP_CREATE -> ACCESS_GROUP_CREATE_WWPN
ACCESS_GROUP_INITIATOR_ADD -> ACCESS_GROUP_INITIATOR_ADD_WWPN
FS_SNAPSHOT_REVERT -> FS_SNAPSHOT_RESTORE
FS_SNAPSHOT_REVERT_SPECIFIC_FILES -> FS_SNAPSHOT_RESTORE_SPECIFIC_FILES
# To match the name of lsm.Client.fs_snapshot_restore()

* Added these capabilities:
ACCESS_GROUP_CREATE_ISCSI_IQN
ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN
ACCESS_GROUP_INITIATOR_ADD_MIX
# _ADD_MIX means can add different type of init_id into access group.
# _ADD_ISCSI_IQN and _ADD_WWPN indicate the types supported.

* Added public methods:
get_supported: Returns a hash of supported capabilities

V3 tasleson, changed public methods added

Signed-off-by: Gris Ge <***@redhat.com>
Signed-off-by: Tony Asleson <***@redhat.com>
---
python_binding/lsm/_data.py | 58 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 48 insertions(+), 10 deletions(-)

diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 8fd42a3..10c4cd6 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -743,11 +743,9 @@ class Capabilities(IData):
SUPPORTED # Supported
) = (0, 1)

- _NUM = 512
+ _NUM = 512 # Indicate the maximum capability integer

- #Array wide
- BLOCK_SUPPORT = 0 # Array handles block operations
- FS_SUPPORT = 1 # Array handles file system
+ _CAP_NUM_BEGIN = 20 # Indicate the first capability integer

#Block operations
VOLUMES = 20
@@ -773,9 +771,10 @@ class Capabilities(IData):
VOLUME_MASK = 36
VOLUME_UNMASK = 37
ACCESS_GROUPS = 38
- ACCESS_GROUP_CREATE = 39
+ ACCESS_GROUP_CREATE_WWPN = 39
ACCESS_GROUP_DELETE = 40
- ACCESS_GROUP_INITIATOR_ADD = 41
+ ACCESS_GROUP_INITIATOR_ADD_WWPN = 41
+ # For empty access group, this indicate it can add WWPN into it.
ACCESS_GROUP_INITIATOR_DELETE = 42

VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP = 43
@@ -784,6 +783,13 @@ class Capabilities(IData):
VOLUME_CHILD_DEPENDENCY = 45
VOLUME_CHILD_DEPENDENCY_RM = 46

+ ACCESS_GROUP_CREATE_ISCSI_IQN = 47
+ ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN = 48
+ # For empty access group, this indicate it can add iSCSI IQN into it.
+
+ ACCESS_GROUP_INITIATOR_ADD_MIX = 49
+ # Allowing add different initiator type than existing one
+
VOLUME_ISCSI_CHAP_AUTHENTICATION = 53

VOLUME_THIN = 55
@@ -798,8 +804,8 @@ class Capabilities(IData):
FS_SNAPSHOTS = 106
FS_SNAPSHOT_CREATE = 107
FS_SNAPSHOT_DELETE = 109
- FS_SNAPSHOT_REVERT = 110
- FS_SNAPSHOT_REVERT_SPECIFIC_FILES = 111
+ FS_SNAPSHOT_RESTORE = 110
+ FS_SNAPSHOT_RESTORE_SPECIFIC_FILES = 111
FS_CHILD_DEPENDENCY = 112
FS_CHILD_DEPENDENCY_RM = 113
FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES = 114
@@ -840,9 +846,11 @@ class Capabilities(IData):
ACCESS_GROUPS_QUICK_SEARCH = 213
FS_QUICK_SEARCH = 214
NFS_EXPORTS_QUICK_SEARCH = 215
- TARGET_PORTS = 215
+ TARGET_PORTS = 216
TARGET_PORTS_QUICK_SEARCH = 217

+ DISKS = 220
+
def _to_dict(self):
rc = {'class': self.__class__.__name__,
'cap': ''.join(['%02x' % b for b in self._cap])}
@@ -860,10 +868,40 @@ class Capabilities(IData):
return False

def get(self, capability):
- if capability > len(self._cap):
+ if capability >= len(self._cap):
return Capabilities.UNSUPPORTED
return self._cap[capability]

+ @staticmethod
+ def _lsm_cap_to_str_dict():
+ """
+ Return a dict containing all valid capability:
+ integer => string name
+ """
+ lsm_cap_to_str_conv = dict()
+ for cap_str, cap_int in Capabilities.__dict__.items():
+ if type(cap_str) == str and type(cap_int) == int and \
+ cap_str[0] != '_' and \
+ Capabilities._CAP_NUM_BEGIN <= cap_int <= Capabilities._NUM:
+ lsm_cap_to_str_conv[cap_int] = cap_str
+ return lsm_cap_to_str_conv
+
+ def get_supported(self, all_cap=False):
+ """
+ Returns a hash of the supported capabilities in the form
+ constant, name
+ """
+ all_caps = Capabilities._lsm_cap_to_str_dict()
+
+ if all_cap:
+ return all_caps
+
+ rc = {}
+ for i in range(0, len(self._cap)):
+ if self._cap[i] == Capabilities.SUPPORTED:
+ rc[i] = all_caps[i]
+ return rc
+
def set(self, capability, value=SUPPORTED):
self._cap[capability] = value
return None
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:11 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Sync with access group capabilities changes.
* 7-Mode ONTAP does not support MIX type of access group.

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

diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index 33525a2..fb0244d 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -418,9 +418,11 @@ class Ontap(IStorageAreaNetwork, INfs):
cap.set(Capabilities.VOLUME_MASK)
cap.set(Capabilities.VOLUME_UNMASK)
cap.set(Capabilities.ACCESS_GROUPS)
- cap.set(Capabilities.ACCESS_GROUP_CREATE)
+ cap.set(Capabilities.ACCESS_GROUP_CREATE_WWPN)
+ cap.set(Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN)
cap.set(Capabilities.ACCESS_GROUP_DELETE)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD)
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_IQN)
cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
@@ -784,7 +786,6 @@ class Ontap(IStorageAreaNetwork, INfs):

return self._access_group(na_ags[0])

-
@handle_ontap_errors
def volumes_accessible_by_access_group(self, access_group, flags=0):
rc = []
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:10 UTC
Permalink
From: Gris Ge <***@redhat.com>

* PEP8 clean up.
* Use lsm.Capabilities.lsm_cap_to_str() to replace the old code.
* Use lsm.lsmcli.data_display.DisplayData.display_data_script_way() for
displaying capabilities.

V3: Used the only one newly available public method

Signed-off-by: Gris Ge <***@redhat.com>
Signed-off-by: Tony Asleson <***@redhat.com>
---
python_binding/lsm/_data.py | 3 +-
tools/lsmcli/cmdline.py | 118 ++++++++-----------------------------------
tools/lsmcli/data_display.py | 4 +-
3 files changed, 24 insertions(+), 101 deletions(-)

diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 10c4cd6..7bab6ce 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -899,7 +899,8 @@ class Capabilities(IData):
rc = {}
for i in range(0, len(self._cap)):
if self._cap[i] == Capabilities.SUPPORTED:
- rc[i] = all_caps[i]
+ if i in all_caps:
+ rc[i] = all_caps[i]
return rc

def set(self, capability, value=SUPPORTED):
diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index 0af2034..4909ae8 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -22,6 +22,7 @@ import getpass
import time
import tty
import termios
+from collections import OrderedDict

from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
@@ -914,8 +915,8 @@ class CmdLine:
self.c.access_groups_granted_to_volume(lsm_vol))
else:
return self.display_data([])
- elif search_key and \
- search_key not in AccessGroup.SUPPORTED_SEARCH_KEYS:
+ elif (search_key and
+ search_key not in AccessGroup.SUPPORTED_SEARCH_KEYS):
raise ArgError("Search key '%s' is not supported by "
"Access Group listing" % search_key)
self.display_data(
@@ -1076,102 +1077,23 @@ class CmdLine:
s = _get_item(self.c.systems(), args.sys, "system id")

cap = self.c.capabilities(s)
- self._cp("BLOCK_SUPPORT", cap.supported(Capabilities.BLOCK_SUPPORT))
- self._cp("FS_SUPPORT", cap.supported(Capabilities.FS_SUPPORT))
- self._cp("VOLUMES", cap.supported(Capabilities.VOLUMES))
- self._cp("VOLUME_CREATE", cap.supported(Capabilities.VOLUME_CREATE))
- self._cp("VOLUME_RESIZE", cap.supported(Capabilities.VOLUME_RESIZE))
- self._cp("VOLUME_REPLICATE",
- cap.supported(Capabilities.VOLUME_REPLICATE))
- self._cp("VOLUME_REPLICATE_CLONE",
- cap.supported(Capabilities.VOLUME_REPLICATE_CLONE))
- self._cp("VOLUME_REPLICATE_COPY",
- cap.supported(Capabilities.VOLUME_REPLICATE_COPY))
- self._cp("VOLUME_REPLICATE_MIRROR_ASYNC",
- cap.supported(Capabilities.VOLUME_REPLICATE_MIRROR_ASYNC))
- self._cp("VOLUME_REPLICATE_MIRROR_SYNC",
- cap.supported(Capabilities.VOLUME_REPLICATE_MIRROR_SYNC))
- self._cp("VOLUME_COPY_RANGE_BLOCK_SIZE",
- cap.supported(Capabilities.VOLUME_COPY_RANGE_BLOCK_SIZE))
- self._cp("VOLUME_COPY_RANGE",
- cap.supported(Capabilities.VOLUME_COPY_RANGE))
- self._cp("VOLUME_COPY_RANGE_CLONE",
- cap.supported(Capabilities.VOLUME_COPY_RANGE_CLONE))
- self._cp("VOLUME_COPY_RANGE_COPY",
- cap.supported(Capabilities.VOLUME_COPY_RANGE_COPY))
- self._cp("VOLUME_DELETE", cap.supported(Capabilities.VOLUME_DELETE))
- self._cp("VOLUME_ONLINE", cap.supported(Capabilities.VOLUME_ONLINE))
- self._cp("VOLUME_OFFLINE", cap.supported(Capabilities.VOLUME_OFFLINE))
- self._cp("VOLUME_THIN",
- cap.supported(Capabilities.VOLUME_THIN))
- self._cp("VOLUME_ISCSI_CHAP_AUTHENTICATION",
- cap.supported(Capabilities.VOLUME_ISCSI_CHAP_AUTHENTICATION))
- self._cp("VOLUME_MASK",
- cap.supported(Capabilities.VOLUME_MASK))
- self._cp("VOLUME_UNMASK",
- cap.supported(Capabilities.VOLUME_UNMASK))
- self._cp("ACCESS_GROUPS",
- cap.supported(Capabilities.ACCESS_GROUPS))
- self._cp("ACCESS_GROUP_CREATE",
- cap.supported(Capabilities.ACCESS_GROUP_CREATE))
- self._cp("ACCESS_GROUP_DELETE",
- cap.supported(Capabilities.ACCESS_GROUP_DELETE))
- self._cp("ACCESS_GROUP_ADD_INITIATOR",
- cap.supported(Capabilities.ACCESS_GROUP_INITIATOR_ADD))
- self._cp("ACCESS_GROUP_DEL_INITIATOR",
- cap.supported(Capabilities.ACCESS_GROUP_INITIATOR_DELETE))
- self._cp("VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP",
- cap.supported(
- Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP))
- self._cp("ACCESS_GROUPS_GRANTED_TO_VOLUME",
- cap.supported(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME))
- self._cp("VOLUME_CHILD_DEPENDENCY",
- cap.supported(Capabilities.VOLUME_CHILD_DEPENDENCY))
- self._cp("VOLUME_CHILD_DEPENDENCY_RM",
- cap.supported(Capabilities.VOLUME_CHILD_DEPENDENCY_RM))
- self._cp("FS", cap.supported(Capabilities.FS))
- self._cp("FS_DELETE", cap.supported(Capabilities.FS_DELETE))
- self._cp("FS_RESIZE", cap.supported(Capabilities.FS_RESIZE))
- self._cp("FS_CREATE", cap.supported(Capabilities.FS_CREATE))
- self._cp("FS_CLONE", cap.supported(Capabilities.FS_CLONE))
- self._cp("FILE_CLONE", cap.supported(Capabilities.FILE_CLONE))
- self._cp("FS_SNAPSHOTS", cap.supported(Capabilities.FS_SNAPSHOTS))
- self._cp("FS_SNAPSHOT_CREATE",
- cap.supported(Capabilities.FS_SNAPSHOT_CREATE))
- self._cp("FS_SNAPSHOT_DELETE",
- cap.supported(Capabilities.FS_SNAPSHOT_DELETE))
- self._cp("FS_SNAPSHOT_REVERT",
- cap.supported(Capabilities.FS_SNAPSHOT_REVERT))
- self._cp("FS_SNAPSHOT_REVERT_SPECIFIC_FILES",
- cap.supported(Capabilities.FS_SNAPSHOT_REVERT_SPECIFIC_FILES))
- self._cp("FS_CHILD_DEPENDENCY",
- cap.supported(Capabilities.FS_CHILD_DEPENDENCY))
- self._cp("FS_CHILD_DEPENDENCY_RM",
- cap.supported(Capabilities.FS_CHILD_DEPENDENCY_RM))
- self._cp("FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES", cap.supported(
- Capabilities.FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES))
- self._cp("EXPORT_AUTH", cap.supported(Capabilities.EXPORT_AUTH))
- self._cp("EXPORTS", cap.supported(Capabilities.EXPORTS))
- self._cp("EXPORT_FS", cap.supported(Capabilities.EXPORT_FS))
- self._cp("EXPORT_REMOVE", cap.supported(Capabilities.EXPORT_REMOVE))
- self._cp("EXPORT_CUSTOM_PATH",
- cap.supported(Capabilities.EXPORT_CUSTOM_PATH))
- self._cp("POOLS_QUICK_SEARCH",
- cap.supported(Capabilities.POOLS_QUICK_SEARCH))
- self._cp("VOLUMES_QUICK_SEARCH",
- cap.supported(Capabilities.VOLUMES_QUICK_SEARCH))
- self._cp("DISKS_QUICK_SEARCH",
- cap.supported(Capabilities.DISKS_QUICK_SEARCH))
- self._cp("FS_QUICK_SEARCH",
- cap.supported(Capabilities.FS_QUICK_SEARCH))
- self._cp("ACCESS_GROUPS_QUICK_SEARCH",
- cap.supported(Capabilities.ACCESS_GROUPS_QUICK_SEARCH))
- self._cp("NFS_EXPORTS_QUICK_SEARCH",
- cap.supported(Capabilities.NFS_EXPORTS_QUICK_SEARCH))
- self._cp("TARGET_PORTS",
- cap.supported(Capabilities.TARGET_PORTS))
- self._cp("TARGET_PORTS_QUICK_SEARCH",
- cap.supported(Capabilities.TARGET_PORTS_QUICK_SEARCH))
+ sup_caps = sorted(cap.get_supported().values())
+ all_caps = sorted(cap.get_supported(True).values())
+
+ sep = DisplayData.DEFAULT_SPLITTER
+ if self.args.sep is not None:
+ sep = self.args.sep
+
+ cap_data = OrderedDict()
+ # Show support capabilities first
+ for v in sup_caps:
+ cap_data[v] = 'SUPPORTED'
+
+ for v in all_caps:
+ if v not in sup_caps:
+ cap_data[v] = 'UNSUPPORTED'
+
+ DisplayData.display_data_script_way([cap_data], sep)

def plugin_info(self, args):
desc, version = self.c.plugin_info()
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 2b8ac68..50d61c7 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -679,14 +679,14 @@ class DisplayData(object):
else:
return None
if display_way == DisplayData.DISPLAY_WAY_SCRIPT:
- DisplayData._display_data_script_way(data_dict_list, splitter)
+ DisplayData.display_data_script_way(data_dict_list, splitter)
elif display_way == DisplayData.DISPLAY_WAY_COLUMN:
DisplayData._display_data_column_way(
data_dict_list, splitter, flag_with_header)
return True

@staticmethod
- def _display_data_script_way(data_dict_list, splitter):
+ def display_data_script_way(data_dict_list, splitter):
key_column_width = 1
value_column_width = 1
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:09 UTC
Permalink
From: Gris Ge <***@redhat.com>

* cmdtest.py
1. Fix incorrect strip in parse().
2. Sync with changes of capabilities.
3. Use random_iqn() when creating access group.
# Simulator has more strict checking now.

* plugin_test.py
1. Sync with changes of capabilities.
2. Choose non-empty access group for volume mask test.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 22 +++++++------
test/plugin_test.py | 89 +++++++++++++++++++++++++++++++++--------------------
2 files changed, 68 insertions(+), 43 deletions(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index b394a62..f63cc4a 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -110,12 +110,13 @@ def parse(out):
rc = []
for line in out.split('\n'):
elem = line.split(sep)
-
+ cleaned_elem = []
for e in elem:
e = e.strip()
+ cleaned_elem.append(e)

- if len(elem) > 1:
- rc.append(elem)
+ if len(cleaned_elem) > 1:
+ rc.append(cleaned_elem)
return rc


@@ -439,12 +440,12 @@ def test_display(cap, system_id):
status for each of them
"""
to_test = ['SYSTEMS']
+ to_test.append('POOLS')

- if cap['BLOCK_SUPPORT']:
- to_test.append('POOLS')
+ if cap['VOLUMES']:
to_test.append('VOLUMES')

- if cap['FS_SUPPORT'] and cap['FS']:
+ if cap['FS']:
to_test.append("FS")

if cap['EXPORTS']:
@@ -589,10 +590,10 @@ def test_mapping(cap, system_id):
iqn1 = random_iqn()
iqn2 = random_iqn()

- if cap['ACCESS_GROUP_CREATE']:
+ if cap['ACCESS_GROUP_CREATE_ISCSI_IQN']:
ag_id = access_group_create(iqn1, system_id)

- if cap['ACCESS_GROUP_ADD_INITIATOR']:
+ if cap['ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN']:
access_group_initiator_add(ag_id, iqn2)

if cap['VOLUME_MASK'] and cap['VOLUME_UNMASK']:
@@ -613,7 +614,7 @@ def test_mapping(cap, system_id):
if cap['VOLUME_DELETE']:
volume_delete(vol_id)

- if cap['ACCESS_GROUP_DEL_INITIATOR']:
+ if cap['ACCESS_GROUP_INITIATOR_DELETE']:
access_group_remove_init(ag_id, iqn1)
access_group_remove_init(ag_id, iqn2)

@@ -648,6 +649,7 @@ def create_all(cap, system_id):
test_fs_creation(cap, system_id)
test_nfs(cap, system_id)

+
def search_test(cap, system_id):
print "\nTesting query with search ID\n"
sys_id_filter = "--sys='%s'" % system_id
@@ -662,7 +664,7 @@ def search_test(cap, system_id):

disk_id_filter = "--disk='%s'" % test_disk_id

- ag_id = access_group_create(iqn[0], system_id)
+ ag_id = access_group_create(random_iqn(), system_id)
ag_id_filter = "--ag='%s'" % ag_id

fs_id = fs_create(pool_id)
diff --git a/test/plugin_test.py b/test/plugin_test.py
index 0731e25..d60b965 100755
--- a/test/plugin_test.py
+++ b/test/plugin_test.py
@@ -614,7 +614,14 @@ class TestPlugin(unittest.TestCase):
if len(ag_list):
vol = self._volume_create(s.id)[0]
self.assertTrue(vol is not None)
- ag = ag_list[0]
+ chose_ag = None
+ for ag in ag_list:
+ if len(ag.init_ids) >= 1:
+ chose_ag = ag
+ break
+ if chose_ag is None:
+ raise Exception("No access group with 1+ member "
+ "found, cannot do volume mask test")

if vol is not None:
self.c.volume_mask(ag, vol)
@@ -623,31 +630,22 @@ class TestPlugin(unittest.TestCase):
self._masking_state(cap, ag, vol, False)
self._volume_delete(vol)

- def _create_access_group(self, cap, s):
+ def _create_access_group(self, cap, s, init_type):
ag_created = None

- # Without this information we would need to systematically go through
- # different port types trying to create an access group, which we
- # can do, but not until we need too.
- if not supported(cap, [lsm.Capabilities.TARGET_PORTS]):
- return None
-
- tps = self.c.target_ports('system_id', s.id)
- if len(tps):
- tp = tps[0]
-
- if tp.port_type == lsm.TargetPort.PORT_TYPE_FC:
- ag_created = self.c.access_group_create(
- rs('access_group'),
- '500A0986994B8DC5',
- lsm.AccessGroup.INIT_TYPE_WWPN, s.id)
- if tp.port_type == lsm.TargetPort.PORT_TYPE_ISCSI:
- ag_created = self.c.access_group_create(
- rs('access_group'),
- 'iqn.1994-05.com.domain:01.89bd01',
- lsm.AccessGroup.INIT_TYPE_ISCSI_IQN, s.id)
-
- self.assertTrue(ag_created is not None)
+ if init_type == lsm.AccessGroup.INIT_TYPE_ISCSI_IQN:
+ ag_created = self.c.access_group_create(
+ rs('access_group'),
+ 'iqn.1994-05.com.domain:01.89bd01',
+ lsm.AccessGroup.INIT_TYPE_ISCSI_IQN, s)
+
+ elif init_type == lsm.AccessGroup.INIT_TYPE_WWPN:
+ ag_created = self.c.access_group_create(
+ rs('access_group'),
+ '500A0986994B8DC5',
+ lsm.AccessGroup.INIT_TYPE_WWPN, s)
+
+ self.assertTrue(ag_created is not None)

if ag_created is not None:
ag_list = self.c.access_groups()
@@ -667,11 +665,21 @@ class TestPlugin(unittest.TestCase):
"access group list!")

def _test_ag_create_delete(self, cap, s):
+ ag = None
if supported(cap, [lsm.Capabilities.ACCESS_GROUPS,
- lsm.Capabilities.ACCESS_GROUP_CREATE]):
- ag = self._create_access_group(cap, s)
+ lsm.Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN]):
+ ag = self._create_access_group(
+ cap, s, lsm.AccessGroup.INIT_TYPE_ISCSI_IQN)
if ag is not None and \
- supported(cap, [lsm.Capabilities.ACCESS_GROUP_DELETE]):
+ supported(cap, [lsm.Capabilities.ACCESS_GROUP_DELETE]):
+ self._delete_access_group(ag)
+
+ if supported(cap, [lsm.Capabilities.ACCESS_GROUPS,
+ lsm.Capabilities.ACCESS_GROUP_CREATE_WWPN]):
+ ag = self._create_access_group(
+ cap, s, lsm.AccessGroup.INIT_TYPE_WWPN)
+ if ag is not None and \
+ supported(cap, [lsm.Capabilities.ACCESS_GROUP_DELETE]):
self._delete_access_group(ag)

def test_access_group_create_delete(self):
@@ -729,11 +737,19 @@ class TestPlugin(unittest.TestCase):
if supported(cap, [lsm.Capabilities.ACCESS_GROUPS]):
ag_list = self.c.access_groups('system_id', s.id)

- if len(ag_list) == 0 and \
- supported(cap, [lsm.Capabilities.ACCESS_GROUP_CREATE,
- lsm.Capabilities.ACCESS_GROUP_DELETE]):
- ag_to_delete = self._create_access_group(cap, s)
- ag_list = self.c.access_groups('system_id', s.id)
+ if len(ag_list) == 0:
+ if supported(
+ cap, [lsm.Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN,
+ lsm.Capabilities.ACCESS_GROUP_DELETE]):
+ ag_to_delete = self._create_access_group(
+ cap, s, lsm.AccessGroup.INIT_TYPE_ISCSI_IQN)
+ ag_list = self.c.access_groups('system_id', s.id)
+ if supported(
+ cap, [lsm.Capabilities.ACCESS_GROUP_CREATE_WWPN,
+ lsm.Capabilities.ACCESS_GROUP_DELETE]):
+ ag_to_delete = self._create_access_group(
+ cap, s, lsm.AccessGroup.INIT_TYPE_WWPN)
+ ag_list = self.c.access_groups('system_id', s.id)

if len(ag_list):
# Try and find an initiator group that has a usable access
@@ -745,7 +761,14 @@ class TestPlugin(unittest.TestCase):
break

if supported(cap, [lsm.Capabilities.
- ACCESS_GROUP_INITIATOR_ADD]):
+ ACCESS_GROUP_INITIATOR_ADD_WWPN]):
+ init_id = self._ag_init_add(ag)
+ if supported(cap, [lsm.Capabilities.
+ ACCESS_GROUP_INITIATOR_DELETE]):
+ self._ag_init_delete(ag, init_id)
+
+ if supported(cap, [lsm.Capabilities.
+ ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN]):
init_id = self._ag_init_add(ag)
if supported(cap, [lsm.Capabilities.
ACCESS_GROUP_INITIATOR_DELETE]):
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:12 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Sync with changes of access group capabilities.
* PEP8 clean up

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

diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index c008d55..a863535 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -281,9 +281,9 @@ class NexentaStor(INfs, IStorageAreaNetwork):
c.set(Capabilities.VOLUME_MASK)
c.set(Capabilities.VOLUME_UNMASK)
c.set(Capabilities.ACCESS_GROUPS)
- c.set(Capabilities.ACCESS_GROUP_CREATE)
+ c.set(Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN)
c.set(Capabilities.ACCESS_GROUP_DELETE)
- c.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD)
+ c.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
c.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
c.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
c.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
@@ -743,7 +743,7 @@ class NexentaStor(INfs, IStorageAreaNetwork):
(access_group.name, access_group.id))

return self._request("list_hostgroup_members", "stmf",
- [access_group.name])
+ [access_group.name])

@handle_nstor_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:17 UTC
Permalink
Also corrected correct constant for
ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN

Signed-off-by: Tony Asleson <***@redhat.com>
---
plugin/ontap/ontap.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index 1662d4d..d33e230 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -401,8 +401,6 @@ class Ontap(IStorageAreaNetwork, INfs):
@handle_ontap_errors
def capabilities(self, system, flags=0):
cap = Capabilities()
- cap.set(Capabilities.BLOCK_SUPPORT)
- cap.set(Capabilities.FS_SUPPORT)
cap.set(Capabilities.VOLUMES)
cap.set(Capabilities.VOLUME_CREATE)
cap.set(Capabilities.VOLUME_RESIZE)
@@ -422,7 +420,7 @@ class Ontap(IStorageAreaNetwork, INfs):
cap.set(Capabilities.ACCESS_GROUP_CREATE_ISCSI_IQN)
cap.set(Capabilities.ACCESS_GROUP_DELETE)
cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_WWPN)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_IQN)
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN)
cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:15 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Rename FS_SNAPSHOT_REVERT to FS_SNAPSHOT_RESTORE in nstor and ontap plugin.

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

diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index a863535..22e053d 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -250,8 +250,8 @@ class NexentaStor(INfs, IStorageAreaNetwork):
c.set(Capabilities.FS_SNAPSHOTS)
c.set(Capabilities.FS_SNAPSHOT_CREATE)
c.set(Capabilities.FS_SNAPSHOT_DELETE)
- c.set(Capabilities.FS_SNAPSHOT_REVERT)
- # c.set(Capabilities.FS_SNAPSHOT_REVERT_SPECIFIC_FILES)
+ c.set(Capabilities.FS_SNAPSHOT_RESTORE)
+ # c.set(Capabilities.FS_SNAPSHOT_RESTORE_SPECIFIC_FILES)
c.set(Capabilities.FS_CHILD_DEPENDENCY)
c.set(Capabilities.FS_CHILD_DEPENDENCY_RM)
# c.set(Capabilities.FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES)
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index fb0244d..1662d4d 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -437,7 +437,7 @@ class Ontap(IStorageAreaNetwork, INfs):
cap.set(Capabilities.FS_SNAPSHOTS)
cap.set(Capabilities.FS_SNAPSHOT_CREATE)
cap.set(Capabilities.FS_SNAPSHOT_DELETE)
- cap.set(Capabilities.FS_SNAPSHOT_REVERT)
+ cap.set(Capabilities.FS_SNAPSHOT_RESTORE)
cap.set(Capabilities.FS_CHILD_DEPENDENCY)
cap.set(Capabilities.FS_CHILD_DEPENDENCY_RM)
cap.set(Capabilities.EXPORT_AUTH)
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:16 UTC
Permalink
Signed-off-by: Tony Asleson <***@redhat.com>
---
plugin/nstor/nstor.py | 4 ----
1 file changed, 4 deletions(-)

diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index 22e053d..c29c712 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -236,10 +236,6 @@ class NexentaStor(INfs, IStorageAreaNetwork):
def capabilities(self, system, flags=0):
c = Capabilities()

- #Array wide
- # c.set(Capabilities.BLOCK_SUPPORT)
- c.set(Capabilities.FS_SUPPORT)
-
#File system
c.set(Capabilities.FS)
c.set(Capabilities.FS_DELETE)
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:13 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Raise error on these conditions when access_group_create():
1. Duplicate name
2. Duplicate init_id
* Don't fail when got duplicate call of access_group_create().

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/sim/simarray.py | 44 +++++++++++++++++++++++++++++++++++---------
1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index 5d9cb6d..b399b03 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -1043,13 +1043,21 @@ class SimData(object):
def ags(self, flags=0):
return self.ag_dict.values()

- def _check_dup_init(self, init_id):
+ def _sim_ag_of_init(self, init_id):
+ """
+ Return sim_ag which containing this init_id.
+ If not found, return None
+ """
for sim_ag in self.ag_dict.values():
if init_id in sim_ag['init_ids']:
- raise LsmError(ErrorNumber.EXISTS_INITIATOR,
- "init_id %s already exist in other "
- % init_id +
- "access group %s" % sim_ag['ag_id'])
+ return sim_ag
+ return None
+
+ def _sim_ag_of_name(self, ag_name):
+ for sim_ag in self.ag_dict.values():
+ if ag_name == sim_ag['name']:
+ return sim_ag
+ return None

def _check_dup_name(self, sim_list, name, error_num):
used_names = [x['name'] for x in sim_list]
@@ -1057,9 +1065,27 @@ class SimData(object):
raise LsmError(error_num, "Name '%s' already in use" % name)

def access_group_create(self, name, init_id, init_type, sys_id, flags=0):
- self._check_dup_name(
- self.ag_dict.values(), name, ErrorNumber.EXISTS_ACCESS_GROUP)
- self._check_dup_init(init_id)
+ exist_sim_ag = self._sim_ag_of_init(init_id)
+ if exist_sim_ag:
+ if exist_sim_ag['name'] == name:
+ return exist_sim_ag
+ else:
+ raise LsmError(ErrorNumber.EXISTS_INITIATOR,
+ "Initiator %s already exist in other " %
+ init_id + "access group %s(%s)" %
+ (exist_sim_ag['name'], exist_sim_ag['ag_id']))
+
+ exist_sim_ag = self._sim_ag_of_name(name)
+ if exist_sim_ag:
+ if init_id in exist_sim_ag['init_ids']:
+ return exist_sim_ag
+ else:
+ raise LsmError(ErrorNumber.EXISTS_ACCESS_GROUP,
+ "Another access group %s(%s) is using " %
+ (exist_sim_ag['name'], exist_sim_ag['ag_id']) +
+ "requested name %s but not contain init_id %s" %
+ (exist_sim_ag['name'], init_id))
+
sim_ag = dict()
sim_ag['init_ids'] = [init_id]
sim_ag['init_type'] = init_type
@@ -1083,7 +1109,7 @@ class SimData(object):
if init_id in self.ag_dict[ag_id]['init_ids']:
return self.ag_dict[ag_id]

- self._check_dup_init(init_id)
+ self._sim_ag_of_init(init_id)

self.ag_dict[ag_id]['init_ids'].extend([init_id])
return self.ag_dict[ag_id]
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:18 UTC
Permalink
At the moment we don't have the corresponding function
that returns a hash of capabilities for C. We could do
this, but not sure how useful it would be for C users.

Signed-off-by: Tony Asleson <***@redhat.com>
---
.../libstoragemgmt/libstoragemgmt_capabilities.h | 23 +++++++++-----
plugin/simc/simc_lsmplugin.c | 14 ++++-----
test/tester.c | 36 ++++++++--------------
3 files changed, 34 insertions(+), 39 deletions(-)

diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h b/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h
index c0c6d24..bc45f7e 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h
@@ -37,8 +37,6 @@ typedef enum {

/** \enum lsm_capability_value_type Capabilities supported by array */
typedef enum {
- LSM_CAP_BLOCK_SUPPORT = 0, /**< Array supports block ops */
- LSM_CAP_FS_SUPPORT = 1, /**< Array supports file system ops */

LSM_CAP_VOLUMES = 20, /**< List volumes */
LSM_CAP_VOLUME_CREATE = 21, /**< Create volumes */
@@ -49,6 +47,7 @@ typedef enum {
LSM_CAP_VOLUME_REPLICATE_COPY = 25, /**< Can make a bitwise copy of volume */
LSM_CAP_VOLUME_REPLICATE_MIRROR_ASYNC = 26, /**< Mirror data with delay */
LSM_CAP_VOLUME_REPLICATE_MIRROR_SYNC = 27, /**< Mirror data and always in sync */
+
LSM_CAP_VOLUME_COPY_RANGE_BLOCK_SIZE = 28, /**< Size of a block for range operations */
LSM_CAP_VOLUME_COPY_RANGE = 29, /**< Sub volume replication support */
LSM_CAP_VOLUME_COPY_RANGE_CLONE = 30, /**< Can space efficient copy a region(s) of a volume*/
@@ -62,9 +61,9 @@ typedef enum {
LSM_CAP_VOLUME_MASK = 36, /**< Grant an access group to a volume */
LSM_CAP_VOLUME_UNMASK = 37, /**< Revoke access for an access group */
LSM_CAP_ACCESS_GROUPS = 38, /**< List access groups */
- LSM_CAP_ACCESS_GROUP_CREATE = 39, /**< Create an access group */
+ LSM_CAP_ACCESS_GROUP_CREATE_WWPN = 39, /**< Create an access group */
LSM_CAP_ACCESS_GROUP_DELETE = 40, /**< Delete an access group */
- LSM_CAP_ACCESS_GROUP_INITIATOR_ADD = 41, /**< Add an initiator to an access group */
+ LSM_CAP_ACCESS_GROUP_INITIATOR_ADD_WWPN = 41, /**< Add an initiator to an access group */
LSM_CAP_ACCESS_GROUP_INITIATOR_DELETE = 42, /**< Remove an initiator from an access group */

LSM_CAP_VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP = 43, /**< Retrieve a list of volumes accessible by an access group */
@@ -73,6 +72,10 @@ typedef enum {
LSM_CAP_VOLUME_CHILD_DEPENDENCY = 45, /**< Used to determine if a volume has any dependencies */
LSM_CAP_VOLUME_CHILD_DEPENDENCY_RM = 46, /**< Removes dependendies */

+ LSM_CAP_ACCESS_GROUP_CREATE_ISCSI_IQN = 47, /**< Create iSCSI access group */
+ LSM_CAP_ACCESS_GROUP_INITIATOR_ADD_ISCSI_IQN = 48, /**< For empty access group, this indicates it can add iSCSI IQN to it */
+ LSM_CAP_ACCESS_GROUP_INITIATOR_ADD_MIX = 49, /**< Allowing add different initiator type that existing one */
+
LSM_CAP_VOLUME_ISCSI_CHAP_AUTHENTICATION = 53, /**< If you can configure iSCSI chap authentication */

LSM_CAP_VOLUME_THIN = 55, /**< Thin provisioned volumes are supported */
@@ -86,8 +89,8 @@ typedef enum {
LSM_CAP_FS_SNAPSHOTS = 106, /**< List FS snapshots */
LSM_CAP_FS_SNAPSHOT_CREATE = 107, /**< Create a snapshot */
LSM_CAP_FS_SNAPSHOT_DELETE = 109, /**< Delete a snapshot */
- LSM_CAP_FS_SNAPSHOT_REVERT = 110, /**< Revert the state of a FS to the specified snapshot */
- LSM_CAP_FS_SNAPSHOT_REVERT_SPECIFIC_FILES = 111, /**< Revert the state of a list of files to a specified snapshot */
+ LSM_CAP_FS_SNAPSHOT_RESTORE = 110, /**< Revert the state of a FS to the specified snapshot */
+ LSM_CAP_FS_SNAPSHOT_RESTORE_SPECIFIC_FILES = 111, /**< Revert the state of a list of files to a specified snapshot */
LSM_CAP_FS_CHILD_DEPENDENCY = 112, /**< Determine if a child dependency exists for the specified file */
LSM_CAP_FS_CHILD_DEPENDENCY_RM = 113, /**< Remove any dependencies the file system may have */
LSM_CAP_FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES = 114, /**< Remove any dependencies for specific files */
@@ -100,7 +103,6 @@ typedef enum {

LSM_CAP_POOL_CREATE = 130, /**< Pool create support */
LSM_CAP_POOL_CREATE_FROM_DISKS = 131, /**< Pool create from disks */
- LSM_CAP_POOL_CREATE_FROM_VOLUMES = 132, /**< Pool create from volumes */
LSM_CAP_POOL_CREATE_FROM_POOL = 133, /**< Pool create from pool */

LSM_CAP_POOL_CREATE_DISK_RAID_0 = 140,
@@ -126,7 +128,12 @@ typedef enum {
LSM_CAP_DISKS_QUICK_SEARCH = 212, /**< Seach occurs on array */
LSM_CAP_ACCESS_GROUPS_QUICK_SEARCH = 213, /**< Seach occurs on array */
LSM_CAP_FS_QUICK_SEARCH = 214, /**< Seach occurs on array */
- LSM_CAP_NFS_EXPORTS_QUICK_SEARCH = 215 /**< Seach occurs on array */
+ LSM_CAP_NFS_EXPORTS_QUICK_SEARCH = 215, /**< Seach occurs on array */
+
+ LSM_CAP_TARGET_PORTS = 216, /**< List target ports */
+ LSM_CAP_TARGET_PORTS_QUICK_SEARCH = 217, /**< Filtering occurs on array */
+
+ LSM_CAP_DISKS = 220 /**< List disk drives */

} lsm_capability_type;

diff --git a/plugin/simc/simc_lsmplugin.c b/plugin/simc/simc_lsmplugin.c
index 310fa32..ddc9b1c 100644
--- a/plugin/simc/simc_lsmplugin.c
+++ b/plugin/simc/simc_lsmplugin.c
@@ -334,9 +334,7 @@ static int cap(lsm_plugin_ptr c, lsm_system *system,
*cap = lsm_capability_record_alloc(NULL);

if( *cap ) {
- rc = lsm_capability_set_n(*cap, LSM_CAPABILITY_SUPPORTED, 46,
- LSM_CAP_BLOCK_SUPPORT,
- LSM_CAP_FS_SUPPORT,
+ rc = lsm_capability_set_n(*cap, LSM_CAPABILITY_SUPPORTED, 44,
LSM_CAP_VOLUMES,
LSM_CAP_VOLUME_CREATE,
LSM_CAP_VOLUME_RESIZE,
@@ -355,9 +353,9 @@ static int cap(lsm_plugin_ptr c, lsm_system *system,
LSM_CAP_VOLUME_MASK,
LSM_CAP_VOLUME_UNMASK,
LSM_CAP_ACCESS_GROUPS,
- LSM_CAP_ACCESS_GROUP_CREATE,
- LSM_CAP_ACCESS_GROUP_DELETE,
- LSM_CAP_ACCESS_GROUP_INITIATOR_ADD,
+ LSM_CAP_ACCESS_GROUP_CREATE_WWPN,
+ LSM_CAP_ACCESS_GROUP_CREATE_WWPN,
+ LSM_CAP_ACCESS_GROUP_INITIATOR_ADD_WWPN,
LSM_CAP_ACCESS_GROUP_INITIATOR_DELETE,
LSM_CAP_VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP,
LSM_CAP_ACCESS_GROUPS_GRANTED_TO_VOLUME,
@@ -372,8 +370,8 @@ static int cap(lsm_plugin_ptr c, lsm_system *system,
LSM_CAP_FS_SNAPSHOTS,
LSM_CAP_FS_SNAPSHOT_CREATE,
LSM_CAP_FS_SNAPSHOT_DELETE,
- LSM_CAP_FS_SNAPSHOT_REVERT,
- LSM_CAP_FS_SNAPSHOT_REVERT_SPECIFIC_FILES,
+ LSM_CAP_FS_SNAPSHOT_RESTORE,
+ LSM_CAP_FS_SNAPSHOT_RESTORE_SPECIFIC_FILES,
LSM_CAP_FS_CHILD_DEPENDENCY,
LSM_CAP_FS_CHILD_DEPENDENCY_RM,
LSM_CAP_FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES,
diff --git a/test/tester.c b/test/tester.c
index f7434af..8d56386 100644
--- a/test/tester.c
+++ b/test/tester.c
@@ -1867,8 +1867,6 @@ START_TEST(test_capabilities)
G(rc, lsm_capabilities, c, sys[0], &cap, LSM_FLAG_RSVD);

if( LSM_ERR_OK == rc ) {
- cap_test(cap, LSM_CAP_BLOCK_SUPPORT);
- cap_test(cap, LSM_CAP_FS_SUPPORT);
cap_test(cap, LSM_CAP_VOLUMES);
cap_test(cap, LSM_CAP_VOLUME_CREATE);
cap_test(cap, LSM_CAP_VOLUME_RESIZE);
@@ -1887,9 +1885,8 @@ START_TEST(test_capabilities)
cap_test(cap, LSM_CAP_VOLUME_MASK);
cap_test(cap, LSM_CAP_VOLUME_UNMASK);
cap_test(cap, LSM_CAP_ACCESS_GROUPS);
- cap_test(cap, LSM_CAP_ACCESS_GROUP_CREATE);
- cap_test(cap, LSM_CAP_ACCESS_GROUP_DELETE);
- cap_test(cap, LSM_CAP_ACCESS_GROUP_INITIATOR_ADD);
+ cap_test(cap, LSM_CAP_ACCESS_GROUP_CREATE_WWPN);
+ cap_test(cap, LSM_CAP_ACCESS_GROUP_INITIATOR_ADD_WWPN);
cap_test(cap, LSM_CAP_ACCESS_GROUP_INITIATOR_DELETE);
cap_test(cap, LSM_CAP_VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP);
cap_test(cap, LSM_CAP_ACCESS_GROUPS_GRANTED_TO_VOLUME);
@@ -1904,8 +1901,8 @@ START_TEST(test_capabilities)
cap_test(cap, LSM_CAP_FS_SNAPSHOTS);
cap_test(cap, LSM_CAP_FS_SNAPSHOT_CREATE);
cap_test(cap, LSM_CAP_FS_SNAPSHOT_DELETE);
- cap_test(cap, LSM_CAP_FS_SNAPSHOT_REVERT);
- cap_test(cap, LSM_CAP_FS_SNAPSHOT_REVERT_SPECIFIC_FILES);
+ cap_test(cap, LSM_CAP_FS_SNAPSHOT_RESTORE);
+ cap_test(cap, LSM_CAP_FS_SNAPSHOT_RESTORE_SPECIFIC_FILES);
cap_test(cap, LSM_CAP_FS_CHILD_DEPENDENCY);
cap_test(cap, LSM_CAP_FS_CHILD_DEPENDENCY_RM);
cap_test(cap, LSM_CAP_FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES );
@@ -2055,8 +2052,6 @@ START_TEST(test_capability)
int rc;
int i;
lsm_capability_type expected_present[] = {
- LSM_CAP_BLOCK_SUPPORT,
- LSM_CAP_FS_SUPPORT,
LSM_CAP_VOLUMES,
LSM_CAP_VOLUME_CREATE,
LSM_CAP_VOLUME_RESIZE,
@@ -2075,9 +2070,8 @@ START_TEST(test_capability)
LSM_CAP_VOLUME_MASK,
LSM_CAP_VOLUME_UNMASK,
LSM_CAP_ACCESS_GROUPS,
- LSM_CAP_ACCESS_GROUP_CREATE,
- LSM_CAP_ACCESS_GROUP_DELETE,
- LSM_CAP_ACCESS_GROUP_INITIATOR_ADD,
+ LSM_CAP_ACCESS_GROUP_CREATE_WWPN,
+ LSM_CAP_ACCESS_GROUP_INITIATOR_ADD_WWPN,
LSM_CAP_ACCESS_GROUP_INITIATOR_DELETE,
LSM_CAP_VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP,
LSM_CAP_ACCESS_GROUPS_GRANTED_TO_VOLUME,
@@ -2092,8 +2086,8 @@ START_TEST(test_capability)
LSM_CAP_FS_SNAPSHOTS,
LSM_CAP_FS_SNAPSHOT_CREATE,
LSM_CAP_FS_SNAPSHOT_DELETE,
- LSM_CAP_FS_SNAPSHOT_REVERT,
- LSM_CAP_FS_SNAPSHOT_REVERT_SPECIFIC_FILES,
+ LSM_CAP_FS_SNAPSHOT_RESTORE,
+ LSM_CAP_FS_SNAPSHOT_RESTORE_SPECIFIC_FILES,
LSM_CAP_FS_CHILD_DEPENDENCY,
LSM_CAP_FS_CHILD_DEPENDENCY_RM,
LSM_CAP_FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES,
@@ -2106,7 +2100,6 @@ START_TEST(test_capability)
LSM_CAP_EXPORT_CUSTOM_PATH,
LSM_CAP_POOL_CREATE,
LSM_CAP_POOL_CREATE_FROM_DISKS,
- LSM_CAP_POOL_CREATE_FROM_VOLUMES,
LSM_CAP_POOL_CREATE_FROM_POOL,

LSM_CAP_POOL_CREATE_DISK_RAID_0,
@@ -2132,9 +2125,7 @@ START_TEST(test_capability)
fail_unless(cap != NULL);

if( cap ) {
- G(rc, lsm_capability_set_n, cap, LSM_CAPABILITY_SUPPORTED, 46,
- LSM_CAP_BLOCK_SUPPORT,
- LSM_CAP_FS_SUPPORT,
+ G(rc, lsm_capability_set_n, cap, LSM_CAPABILITY_SUPPORTED, 44,
LSM_CAP_VOLUMES,
LSM_CAP_VOLUME_CREATE,
LSM_CAP_VOLUME_RESIZE,
@@ -2153,9 +2144,8 @@ START_TEST(test_capability)
LSM_CAP_VOLUME_MASK,
LSM_CAP_VOLUME_UNMASK,
LSM_CAP_ACCESS_GROUPS,
- LSM_CAP_ACCESS_GROUP_CREATE,
- LSM_CAP_ACCESS_GROUP_DELETE,
- LSM_CAP_ACCESS_GROUP_INITIATOR_ADD,
+ LSM_CAP_ACCESS_GROUP_CREATE_WWPN,
+ LSM_CAP_ACCESS_GROUP_INITIATOR_ADD_WWPN,
LSM_CAP_ACCESS_GROUP_INITIATOR_DELETE,
LSM_CAP_VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP,
LSM_CAP_ACCESS_GROUPS_GRANTED_TO_VOLUME,
@@ -2170,8 +2160,8 @@ START_TEST(test_capability)
LSM_CAP_FS_SNAPSHOTS,
LSM_CAP_FS_SNAPSHOT_CREATE,
LSM_CAP_FS_SNAPSHOT_DELETE,
- LSM_CAP_FS_SNAPSHOT_REVERT,
- LSM_CAP_FS_SNAPSHOT_REVERT_SPECIFIC_FILES,
+ LSM_CAP_FS_SNAPSHOT_RESTORE,
+ LSM_CAP_FS_SNAPSHOT_RESTORE_SPECIFIC_FILES,
LSM_CAP_FS_CHILD_DEPENDENCY,
LSM_CAP_FS_CHILD_DEPENDENCY_RM,
LSM_CAP_FS_CHILD_DEPENDENCY_RM_SPECIFIC_FILES,
--
1.8.2.1
Tony Asleson
2014-07-29 22:56:14 UTC
Permalink
From: Gris Ge <***@redhat.com>

* Complete rewrite of capabilities() methods except volume replication
related.
* SMI-S profile based capabilities check.
# Assuming every vendor is following the SNIA standard mandatory settings.
# We are not SNIA CTP test, we can redirect bug to vendor if user
# complained.

* Tested on:
EMC VNX, EMC VMAX, Fujitsu Eternus, HDS AMS, Dell Compellent, HP 3par,
Dot Hill DHS

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

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index bf2355d..3ad92f8 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -65,6 +65,11 @@ from lsm import (IStorageAreaNetwork, error, uri_parse, LsmError, ErrorNumber,
# _cim_xxx_of_id(some_id)
# Return CIMInstance for given ID

+# Terminology
+# SPC CIM_SCSIProtocolController
+# BSP SNIA SMI-S 'Block Services Package' profile
+# Group M&M SNIA SMI-S 'Group Masking and Mapping' profile
+

def handle_cim_errors(method):
def cim_wrapper(*args, **kwargs):
@@ -178,6 +183,11 @@ class DMTF(object):
# Allowing empty DeviceMaskingGroup associated to SPC
GMM_CAP_INIT_MG_ALLOW_EMPTY_W_SPC = pywbem.Uint16(5)

+ # CIM_GroupMaskingMappingCapabilities['SupportedAsynchronousActions']
+ # and 'SupportedSynchronousActions'. They are using the same value map.
+ GMM_CAP_DELETE_SPC = pywbem.Uint16(24)
+ GMM_CAP_DELETE_GROUP = pywbem.Uint16(20)
+
_INIT_TYPE_CONV = {
DMTF.ID_TYPE_OTHER: AccessGroup.INIT_TYPE_OTHER,
DMTF.ID_TYPE_WWPN: AccessGroup.INIT_TYPE_WWPN,
@@ -730,53 +740,72 @@ class Smis(IStorageAreaNetwork):
def plugin_unregister(self, flags=0):
self._c = None

- def _scs_supported_capabilities(self, system, cap):
+ def _bsp_cap_set(self, cim_sys_path, cap):
"""
- Interrogate the supported features of the Storage Configuration
- service
+ Set capabilities for these methods:
+ volumes()
+ volume_create()
+ volume_resize()
+ volume_delete()
"""
- scs = self._get_class_instance('CIM_StorageConfigurationService',
- 'SystemName', system.id)
-
- if scs is not None:
- scs_cap_inst = self._c.Associators(
- scs.path,
- AssocClass='CIM_ElementCapabilities',
- ResultClass='CIM_StorageConfigurationCapabilities')[0]
-
- if scs_cap_inst is not None:
- # print 'Async', scs_cap_inst['SupportedAsynchronousActions']
- # print 'Sync', scs_cap_inst['SupportedSynchronousActions']
- async = None
- sync = None
-
- if 'SupportedAsynchronousActions' in scs_cap_inst:
- async = scs_cap_inst['SupportedAsynchronousActions']
- if 'SupportedSynchronousActions' in scs_cap_inst:
- sync = scs_cap_inst['SupportedSynchronousActions']
-
- if async is None:
- async = []
+ if self.fallback_mode:
+ # pools() is mandatory, we will try pools() related methods first
+ try:
+ self._cim_pools_of(cim_sys_path)
+ except CIMError as e:
+ if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
+ e[0] == pywbem.CIM_ERR_INVALID_CLASS:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support "
+ "CIM_StoragePool querying which is "
+ "mandatory for pools() method")
+ else:
+ raise
+ # For fallback mode, if StoragePool is supported, then BSP is
+ # supported.
+ #
+ # For interop, plugin_register() already ensured the support
+ # of 1.4+ Array profile which make 'BSP' mandatory as sub profile.
+ # This is mandatory for BSP profile:
+ cap.set(Capabilities.VOLUMES)

- if sync is None:
- sync = []
+ # CIM_StorageConfigurationService is optional.
+ cim_scs_path = self._get_cim_service_path(
+ cim_sys_path, 'CIM_StorageConfigurationService')

- combined = async
- combined.extend(sync)
+ if cim_scs_path is None:
+ return

- #TODO Get rid of magic numbers
- if 'SupportedStorageElementTypes' in scs_cap_inst:
- if 2 in scs_cap_inst['SupportedStorageElementTypes']:
- cap.set(Capabilities.VOLUMES)
+ # These methods are mandatory for CIM_StorageConfigurationService:
+ # CreateOrModifyElementFromStoragePool()
+ # ReturnToStoragePool()
+ cap.set(Capabilities.VOLUME_CREATE)
+ cap.set(Capabilities.VOLUME_DELETE)
+ cap.set(Capabilities.VOLUME_RESIZE)

- if 5 in combined:
- cap.set(Capabilities.VOLUME_CREATE)
+ return

- if 6 in combined:
- cap.set(Capabilities.VOLUME_DELETE)
+ def _disk_cap_set(self, cim_sys_path, cap):
+ if self.fallback_mode:
+ try:
+ # Assuming provider support disk drive when systems under it
+ # support it.
+ self._enumerate('CIM_DiskDrive')
+ except CIMError as e:
+ if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
+ e[0] == pywbem.CIM_ERR_INVALID_CLASS:
+ return
+ else:
+ raise
+ else:
+ if not self._profile_is_supported(SNIA.DISK_LITE_PROFILE,
+ SNIA.SMIS_SPEC_VER_1_4,
+ strict=False,
+ raise_error=False):
+ return

- if 7 in combined:
- cap.set(Capabilities.VOLUME_RESIZE)
+ cap.set(Capabilities.DISKS)
+ return

def _rs_supported_capabilities(self, system, cap):
"""
@@ -827,7 +856,7 @@ class Smis(IStorageAreaNetwork):
if rs_cap is not None and 'SupportedCopyTypes' in rs_cap:
sct = rs_cap['SupportedCopyTypes']

- if len(sct):
+ if sct and len(sct):
cap.set(Capabilities.VOLUME_REPLICATE)

# Mirror support is not working and is not supported at
@@ -845,65 +874,60 @@ class Smis(IStorageAreaNetwork):
if Smis.CopyTypes.UNSYNCUNASSOC in sct:
cap.set(Capabilities.VOLUME_REPLICATE_COPY)

- def _pcm_supported_capabilities(self, system, cap):
- """
- Interrogate the supported features of
- CIM_ProtocolControllerMaskingCapabilities
+ 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

- # Get the cim object that represents the system
- cim_sys = None
- cim_pcms = None
- cim_sys = self._get_cim_instance_by_id('System', system.id)
+ For fallback mode, once we found CIM_ControllerConfigurationService,
+ we assume they are supporting 1.4rev6 'Masking and Mapping' profile.
+ Fallback mode means target provider does not support interop, but
+ they still need to follow at least SNIA SMI-S 1.4rev6
+ """
if self.fallback_mode:
-
- # Using 'ExposePathsSupported of
- # CIM_ProtocolControllerMaskingCapabilities
- # to check support status of HidePaths() and ExposePaths() is
- # not documented by SNIA SMI-S 1.4 or 1.6, but only defined in
- # DMTF CIM MOF files.
- try:
- cim_pcms = self._c.Associators(
- cim_sys.path,
- ResultClass='CIM_ProtocolControllerMaskingCapabilities')
- except CIMError as e:
- if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
- e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- return
- if cim_pcms is not None and len(cim_pcms) == 1:
- cap.set(Capabilities.ACCESS_GROUPS)
- cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
- cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
-
- if cim_pcms[0]['ExposePathsSupported']:
- cap.set(Capabilities.VOLUME_MASK)
- cap.set(Capabilities.VOLUME_UNMASK)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
+ cim_ccs_path = self._get_cim_service_path(
+ cim_sys_path, 'CIM_ControllerConfigurationService')
+ if cim_ccs_path is None:
return
- else:
- # Since SNIA SMI-S 1.4rev6:
- # CIM_ControllerConfigurationService is mandatory
- # and it's ExposePaths() and HidePaths() are mandatory
- cap.set(Capabilities.ACCESS_GROUPS)
- cap.set(Capabilities.VOLUME_MASK)
- cap.set(Capabilities.VOLUME_UNMASK)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_ADD)
- cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
- cap.set(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME)
- cap.set(Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP)
+
+ elif not self._profile_is_supported(SNIA.MASK_PROFILE,
+ SNIA.SMIS_SPEC_VER_1_4,
+ strict=False,
+ 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()

- # Assume that the SMI-S we are talking to supports blocks
- cap.set(Capabilities.BLOCK_SUPPORT)
-
- self._scs_supported_capabilities(system, cap)
self._rs_supported_capabilities(system, cap)
return cap

- def _tgt_port_capabilities(self, system, 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 = False
flag_iscsi_support = False
if self.fallback_mode:
@@ -911,18 +935,14 @@ class Smis(IStorageAreaNetwork):
flag_iscsi_support = True
# CIM_FCPort is the contral class of FC Targets profile
try:
- self._enumerate('CIM_FCPort')
+ self._cim_fc_tgt_of(cim_sys_path)
except CIMError as e:
if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
e[0] == pywbem.CIM_ERR_INVALID_CLASS:
flag_fc_support = False

- # Even CIM_EthernetPort is the contral class of iSCSI Target
- # Ports profile, but that class is optional. :(
- # We use CIM_iSCSIProtocolEndpoint as it's a start point we are
- # using in our code of target_ports().
try:
- self._enumerate('CIM_iSCSIProtocolEndpoint')
+ self._cim_iscsi_pg_of(cim_sys_path)
except CIMError as e:
if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
e[0] == pywbem.CIM_ERR_INVALID_CLASS:
@@ -953,11 +973,100 @@ class Smis(IStorageAreaNetwork):
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, but we require target provider
+ # to support empty InitiatorMaskingGroup.
+ cim_gmm_cap_pros = [
+ 'SupportedInitiatorGroupFeatures',
+ '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 DMTF.GMM_CAP_INIT_MG_ALLOW_EMPTY in \
+ cim_gmm_cap['SupportedInitiatorGroupFeatures']:
+ cap.set(Capabilities.ACCESS_GROUP_INITIATOR_DELETE)
+
+ # if empty dev group in spc is allowed, RemoveMembers() is enough
+ # to do volume_unamsk(). 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):
- cap = self._common_capabilities(system)
- self._pcm_supported_capabilities(system, cap)
- self._tgt_port_capabilities(system, cap)
+
+ cim_sys = self._get_cim_instance_by_id(
+ 'System', system.id, raise_error=True)
+
+ cap = Capabilities()
+
+ # 'Block Services Package' profile
+ self._bsp_cap_set(cim_sys.path, cap)
+
+ # 'Disk Drive Lite' profile
+ self._disk_cap_set(cim_sys.path, cap)
+
+ # 'Masking and Mapping' and 'Group Masking and Mapping' profiles
+ mask_type = self._mask_type()
+ if cim_sys.path.classname == 'Clar_StorageSystem':
+ mask_type = Smis.MASK_TYPE_MASK
+
+ if mask_type == Smis.MASK_TYPE_GROUP:
+ self._group_mask_map_cap_set(cim_sys.path, cap)
+ else:
+ self._mask_map_cap_set(cim_sys.path, cap)
+
+ # 'FC Target Ports' and 'iSCSI Target Ports' profiles
+ self._tgt_cap_set(cim_sys.path, cap)
+
+ self._rs_supported_capabilities(system, cap)
return cap

@handle_cim_errors
@@ -2250,7 +2359,9 @@ class Smis(IStorageAreaNetwork):
cim_sys.path,
AssocClass='CIM_ElementCapabilities',
ResultClass='CIM_GroupMaskingMappingCapabilities',
- PropertyList=['SupportedDeviceGroupFeatures'])[0]
+ PropertyList=['SupportedDeviceGroupFeatures',
+ 'SupportedSynchronousActions',
+ 'SupportedAsynchronousActions'])[0]

flag_empty_dev_in_spc = False

@@ -2258,6 +2369,18 @@ class Smis(IStorageAreaNetwork):
cim_gmm_cap['SupportedDeviceGroupFeatures']:
flag_empty_dev_in_spc = True

+ if flag_empty_dev_in_spc is False:
+ if ((DMTF.GMM_CAP_DELETE_SPC not in
+ cim_gmm_cap['SupportedSynchronousActions']) and
+ (DMTF.GMM_CAP_DELETE_SPC not in
+ cim_gmm_cap['SupportedAsynchronousActions'])):
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "volume_unmask() not supported. It requires one of these "
+ "1. support of DeleteMaskingView(). 2. allowing empty "
+ "DeviceMaskingGroup in SPC. But target SMI-S provider "
+ "does not support any of these")
+
cim_gmm_path = self._get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')

@@ -2419,7 +2542,7 @@ class Smis(IStorageAreaNetwork):
except CIMError as ce:
error_code = tuple(ce)[0]
if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
- error_code == pywbem.CIM_ERR_INVALID_PARAMETER:
+ error_code == pywbem.CIM_ERR_INVALID_PARAMETER:
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported ' +
'by this array')
@@ -2829,7 +2952,8 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.NO_SUPPORT,
"EMC VNX/CX require WWNN defined when adding "
"new initiator which is not supported by LSM yet. "
- "Please do it via EMC vendor specific tools.")
+ "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)

@@ -4120,14 +4244,20 @@ class Smis(IStorageAreaNetwork):
else:
return cim_syss

- def _fc_tgt_is_supported(self):
+ def _fc_tgt_is_supported(self, cim_sys_path):
"""
Return True if FC Target Port 1.4+ profile is supported.
- For fallback_mode, always return True.
- Return False else.
+ For fallback_mode, we call self._cim_fc_tgt_of() and do try-except
"""
if self.fallback_mode:
+ try:
+ self._cim_fc_tgt_of(cim_sys_path)
+ except CIMError as e:
+ if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
+ e[0] == pywbem.CIM_ERR_INVALID_CLASS:
+ return False
return True
+
flag_fc_support = self._profile_is_supported(
SNIA.FC_TGT_PORT_PROFILE,
SNIA.SMIS_SPEC_VER_1_4,
@@ -4148,23 +4278,31 @@ class Smis(IStorageAreaNetwork):
else:
return False

- def _iscsi_tgt_is_supported(self):
+ def _iscsi_tgt_is_supported(self, cim_sys_path):
"""
Return True if FC Target Port 1.4+ profile is supported.
- For fallback_mode, always return True.
- Return False else.
+ For fallback_mode, we call self._cim_iscsi_pg_of() and do try-except
+ For fallback_mode:
+ Even CIM_EthernetPort is the contral class of iSCSI Target
+ Ports profile, but that class is optional. :(
+ We use CIM_iSCSIProtocolEndpoint as it's a start point we are
+ using in our code of target_ports().
"""
if self.fallback_mode:
+ try:
+ self._cim_iscsi_pg_of(cim_sys_path)
+ except CIMError as e:
+ if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \
+ e[0] == pywbem.CIM_ERR_INVALID_CLASS:
+ return False
return True
- flag_iscsi_support = self._profile_is_supported(
- SNIA.ISCSI_TGT_PORT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- strict=False,
- raise_error=False)
- if flag_iscsi_support:
+
+ if self._profile_is_supported(SNIA.ISCSI_TGT_PORT_PROFILE,
+ SNIA.SMIS_SPEC_VER_1_4,
+ strict=False,
+ raise_error=False):
return True
- else:
- return False
+ return False

def _multi_sys_is_supported(self):
"""
@@ -4466,17 +4604,6 @@ class Smis(IStorageAreaNetwork):
@handle_cim_errors
def target_ports(self, search_key=None, search_value=None, flags=0):
rc = []
- flag_fc_support = self._fc_tgt_is_supported()
- flag_iscsi_support = self._iscsi_tgt_is_supported()
-
- if flag_fc_support is False and flag_iscsi_support is False:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Target SMI-S provider does not support any of"
- "these profiles: '%s %s', '%s %s'"
- % (SNIA.SMIS_SPEC_VER_1_4,
- SNIA.FC_TGT_PORT_PROFILE,
- SNIA.SMIS_SPEC_VER_1_4,
- SNIA.ISCSI_TGT_PORT_PROFILE))

cim_fc_tgt_pros = ['UsageRestriction', 'ElementName', 'SystemName',
'PermanentAddress', 'PortDiscriminator',
@@ -4486,6 +4613,21 @@ 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)
+
+ # Assuming: if one system does not support target_ports(),
+ # all systems from the same provider will not support
+ # target_ports().
+ if flag_fc_support is False and flag_iscsi_support is False:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support any of"
+ "these profiles: '%s %s', '%s %s'"
+ % (SNIA.SMIS_SPEC_VER_1_4,
+ SNIA.FC_TGT_PORT_PROFILE,
+ SNIA.SMIS_SPEC_VER_1_4,
+ SNIA.ISCSI_TGT_PORT_PROFILE))
+
if flag_fc_support:
# CIM_FCPort might be not belong to root cim_sys
# In that case, CIM_FCPort['SystemName'] will not be
@@ -4564,7 +4706,7 @@ class Smis(IStorageAreaNetwork):
cim_job_path = out['Job']
loop_counter = 0
job_pros = ['JobState', 'PercentComplete', 'ErrorDescription',
- 'OperationalStatus']
+ 'OperationalStatus']
cim_xxxs_path = []
while(loop_counter <= Smis._INVOKE_MAX_LOOP_COUNT):
cim_job = self._c.GetInstance(cim_job_path,
@@ -4572,7 +4714,7 @@ class Smis(IStorageAreaNetwork):
LocalOnly=False)
job_state = cim_job['JobState']
if job_state in (Smis.JS_NEW, Smis.JS_STARTING,
- Smis.JS_RUNNING):
+ Smis.JS_RUNNING):
loop_counter += 1
time.sleep(Smis._INVOKE_CHECK_INTERVAL)
continue
@@ -4696,8 +4838,18 @@ class Smis(IStorageAreaNetwork):
"SMI-S plugin only support creating FC/FCoE WWPN "
"and iSCSI AccessGroup")

- flag_fc_support = self._fc_tgt_is_supported()
- flag_iscsi_support = self._iscsi_tgt_is_supported()
+ cim_sys = self._get_cim_instance_by_id(
+ 'System', system.id, raise_error=True)
+ if cim_sys.path.classname == 'Clar_StorageSystem':
+ # EMC VNX/CX does not support Group M&M, which incorrectly exposed
+ # in CIM_RegisteredProfile
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "access_group_create() is not supported by "
+ "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)

if init_type == AccessGroup.INIT_TYPE_WWPN and not flag_fc_support:
raise LsmError(ErrorNumber.NO_SUPPORT,
@@ -4712,15 +4864,6 @@ class Smis(IStorageAreaNetwork):
"iSCSI target port, which not allow creating "
"iSCSI IQN access group")

- cim_sys = self._get_cim_instance_by_id('System', system.id)
- if cim_sys.path.classname == 'Clar_StorageSystem':
- # EMC VNX/CX does not support Group M&M, which incorrectly exposed
- # in CIM_RegisteredProfile
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "access_group_create() is not supported by "
- "EMC VNX/CX which lacks the support of SNIA 1.5+ "
- "Group Masking and Mapping profile")
-
cim_init = self._cim_init_check_or_create(
cim_sys.path, init_id, init_type)
--
1.8.2.1
Gris Ge
2014-07-30 06:37:55 UTC
Permalink
Post by Tony Asleson
Please review.
Thanks for the correction.
This patch set looks good for me.

Just a trivial changes to save some loop count.
=========================
diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 7bab6ce..bd06286 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -897,7 +897,7 @@ class Capabilities(IData):
return all_caps

rc = {}
- for i in range(0, len(self._cap)):
+ for i in all_caps.keys():
if self._cap[i] == Capabilities.SUPPORTED:
if i in all_caps:
rc[i] = all_caps[i]

=========================

This patch set is based on a lot of un-committed patch. It applied clean.
Let me know if you lose trace of them.

Thank you.

Best regards.
--
Gris Ge
Continue reading on narkive:
Loading...