Discussion:
[Libstoragemgmt-devel] [PATCH 0/7] Access Group clean up and fix.
Gris Ge
2014-08-01 03:17:18 UTC
Permalink
Please check individual patches for detail.

Thank you in advance.

Gris Ge (7):
python libraray: remove unused initiator type: INIT_TYPE_WWNN,
INIT_TYPE_HOSTNAME, INIT_TYPE_SAS
python library: standardize wwpn string to lsm way
lsmcli: remove unused init_type of AccessGroup
IBM v7k plugin: Removed not tested SAS init_type of AccessGroup
ontap plugin: Rename ErrorNumber.INVALID_IQN to
ErrorNumber.INVALID_INIT
lsmcli: Reomve --init-type and auto detect the init_type
SMI-S plugin: convert lsm WWPN form to SNIA form and fix access group
bugs

doc/man/lsmcli.1.in | 12 +--
plugin/ontap/ontap.py | 2 +-
plugin/smispy/smis.py | 175 ++++++++++++++++++++++-------------------
plugin/v7k/ibmv7k.py | 5 --
python_binding/lsm/__init__.py | 3 +-
python_binding/lsm/_client.py | 6 +-
python_binding/lsm/_common.py | 76 +++++++++++++++++-
python_binding/lsm/_data.py | 9 +--
tools/lsmcli/cmdline.py | 54 +++++++------
tools/lsmcli/data_display.py | 3 -
10 files changed, 212 insertions(+), 133 deletions(-)
--
1.8.3.1
Gris Ge
2014-08-01 03:17:19 UTC
Permalink
Remove these initiator types as no plugin are using it:
INIT_TYPE_WWNN
INIT_TYPE_HOSTNAME
INIT_TYPE_SAS

C library not updated for this change yet.

We can add it back if needed.

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/lsm/_data.py | 3 ---
1 file changed, 3 deletions(-)

diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index ff5065f..70ee4da 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -650,10 +650,7 @@ class AccessGroup(IData):
INIT_TYPE_UNKNOWN = 0
INIT_TYPE_OTHER = 1
INIT_TYPE_WWPN = 2
- INIT_TYPE_WWNN = 3
- INIT_TYPE_HOSTNAME = 4
INIT_TYPE_ISCSI_IQN = 5
- INIT_TYPE_SAS = 6
INIT_TYPE_ISCSI_WWPN_MIXED = 7

def __init__(self, _id, _name, _init_ids, _init_type, _system_id,
--
1.8.3.1
Gris Ge
2014-08-01 03:17:20 UTC
Permalink
* Unify the form of WWPN in LSM:
(?:[0-9a-f]{2}:){7}[0-9a-f]{2}
* _client.py will converted user input as standard form.
* _data.py will converted plugin input as standard form.
* Expose these methods for plugin and user to verify init_id:
wwpn_to_lsm_type(), iscsi_iqn_validate(), init_id_to_lsm_type()
* Rename ErrorNumber.INVALID_IQN to ErrorNumber.INVALID_INIT.

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/lsm/__init__.py | 3 +-
python_binding/lsm/_client.py | 6 +++-
python_binding/lsm/_common.py | 76 +++++++++++++++++++++++++++++++++++++++++-
python_binding/lsm/_data.py | 6 ++--
4 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index 308ad15..ccb521a 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -4,7 +4,8 @@ from version import VERSION

from _common import error, info, LsmError, ErrorLevel, ErrorNumber, \
JobStatus, uri_parse, md5, Proxy, size_bytes_2_size_human, \
- common_urllib2_error_handler, size_human_2_size_bytes
+ common_urllib2_error_handler, size_human_2_size_bytes, \
+ wwpn_to_lsm_type, iscsi_iqn_validate, init_id_to_lsm_type
from _data import (Disk, Volume, Pool, System, FileSystem, FsSnapshot,
NfsExport, BlockRange, AccessGroup, TargetPort,
Capabilities)
diff --git a/python_binding/lsm/_client.py b/python_binding/lsm/_client.py
index 61a7aa2..bac1bc6 100644
--- a/python_binding/lsm/_client.py
+++ b/python_binding/lsm/_client.py
@@ -21,7 +21,7 @@ import unittest
from lsm import (Volume, NfsExport, Capabilities, Pool, System,
Disk, AccessGroup, FileSystem, FsSnapshot,
uri_parse, LsmError, JobStatus, ErrorNumber,
- INetworkAttachedStorage, TargetPort)
+ INetworkAttachedStorage, TargetPort, init_id_to_lsm_type)

from _common import return_requires as _return_requires
from _common import UDS_PATH as _UDS_PATH
@@ -427,6 +427,7 @@ class Client(INetworkAttachedStorage):
Register a user/password for the specified initiator for CHAP
authentication.
"""
+ iscsi_iqn_validate(init_id, raise_error=True)
return self._tp.rpc('iscsi_chap_auth', _del_self(locals()))

## Returns an array of volume objects
@@ -652,6 +653,7 @@ class Client(INetworkAttachedStorage):
Creates an access group and add the specified initiator id,
init_type and desired access.
"""
+ init_id = init_id_to_lsm_type(init_id, raise_error=True)
return self._tp.rpc('access_group_create', _del_self(locals()))

## Deletes an access group.
@@ -679,6 +681,7 @@ class Client(INetworkAttachedStorage):
"""
Adds an initiator to an access group
"""
+ init_id = init_id_to_lsm_type(init_id, raise_error=True)
return self._tp.rpc('access_group_initiator_add', _del_self(locals()))

## Deletes an initiator from an access group
@@ -692,6 +695,7 @@ class Client(INetworkAttachedStorage):
"""
Deletes an initiator from an access group
"""
+ init_id = init_id_to_lsm_type(init_id, raise_error=True)
return self._tp.rpc('access_group_initiator_delete',
_del_self(locals()))

diff --git a/python_binding/lsm/_common.py b/python_binding/lsm/_common.py
index fdd10ab..f3c66ec 100644
--- a/python_binding/lsm/_common.py
+++ b/python_binding/lsm/_common.py
@@ -76,6 +76,80 @@ def common_urllib2_error_handler(exp):
raise LsmError(ErrorNumber.PLUGIN_ERROR, "Unexpected exception",
stack_trace)

+_regex_wwpn = re.compile(r"""
+ ^
+ [0x|0X]{0,1}
+ (:?[0-9A-Fa-f]{2}
+ [\.\-:]{0,1}){7}
+ [0-9A-Fa-f]{2}
+ $
+ """, re.X)
+
+def wwpn_to_lsm_type(wwpn, raise_error=True):
+ """
+ Conver provided WWPN string into LSM standarded one:
+ (?:[0-9a-f]{2}:){7}[0-9a-f]{2}
+ Return the converted WWPN
+ Return None if raise_error is False and not a valid WWPN.
+ """
+ if _regex_wwpn.match(str(wwpn)):
+ s = str(wwpn)
+ s = s.lower()
+ s = re.sub(r'0x', '', s)
+ s = re.sub(r'[^0-9a-f]', '', s)
+ s = ":".join(re.findall(r'..', s))
+ return s
+ if raise_error:
+ raise LsmError(ErrorNumber.INVALID_INIT,
+ "Invalid WWPN Initiator: %s" % wwpn)
+ return None
+
+_regex_iscsi_iqn = re.compile(r"""
+ ^
+ iqn # iqn
+ \. # .
+ [0-9]{4}-[0-9]{2} # 1995-02
+ \. # .
+ [A-Za-z](?:[A-Za-z0-9\-]*[A-Za-z0-9])? # com
+ \. # .
+ [A-Za-z](?:[A-Za-z0-9\-]*[A-Za-z0-9])? # redhat
+ : # :
+ [\.A-Za-z\-0-9]+ # gris-01
+ $
+ """, re.X)
+
+def iscsi_iqn_validate(iqn, raise_error=True):
+ """
+ Return True if got a valid iSCSI IQN.
+ Return False if raise_error is False when not a valid iSCSI IQN.
+ """
+ if _regex_iscsi_iqn.match(str(iqn)):
+ return True
+
+ if raise_error:
+ raise LsmError(ErrorNumber.INVALID_INIT,
+ "Invalid iSCSI IQN Initiator: %s" % iqn)
+ return False
+
+def init_id_to_lsm_type(init_id, raise_error=True):
+ """
+ For WWPN init_id, we convert it into LSM standard format:
+ (?:[0-9a-f]{2}:){7}[0-9a-f]{2}
+ For iSCSI IQN, return init_id without change.
+ If not WWPn nor iSCSI IQN, raise error (Return None if raise_error is
+ False)
+ """
+ if iscsi_iqn_validate(init_id, raise_error=False):
+ return init_id
+ wwpn = wwpn_to_lsm_type(init_id, raise_error=False)
+ if wwpn:
+ return wwpn
+
+ if raise_error:
+ raise LsmError(ErrorNumber.INVALID_INIT,
+ "Invalid Initiator ID, not a iSCSI IQN or WWPN: %s" %
+ init_id)
+ return None

## Documentation for Proxy class.
#
@@ -455,7 +529,7 @@ class ErrorNumber(object):
INVALID_VOLUME = 115
INVALID_CAPABILITY = 116
INVALID_SYSTEM = 117
- INVALID_IQN = 118
+ INVALID_INIT = 118
INVALID_DISK = 119
INVALID_BLOCK_RANGE = 121

diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 70ee4da..a06e37d 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -24,7 +24,7 @@ except ImportError:
import json

from json.decoder import WHITESPACE
-from _common import get_class, default_property
+from _common import get_class, default_property, init_id_to_lsm_type


class DataEncoder(json.JSONEncoder):
@@ -657,7 +657,9 @@ class AccessGroup(IData):
_plugin_data=None):
self._id = _id
self._name = _name # AccessGroup name
- self._init_ids = _init_ids # List of initiator IDs
+ self._init_ids = list(
+ init_id_to_lsm_type(i, raise_error=True)
+ for i in _init_ids)
self._init_type = _init_type
self._system_id = _system_id # System id this group belongs
self._plugin_data = _plugin_data
--
1.8.3.1
Gris Ge
2014-08-01 03:17:21 UTC
Permalink
* Removed unused init_type of AccessGroup:
AccessGroup.INIT_TYPE_WWNN
AccessGroup.INIT_TYPE_HOSTNAME
AccessGroup.INIT_TYPE_SAS

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/data_display.py | 3 ---
1 file changed, 3 deletions(-)

diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index a4d9629..c4807dd 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -283,10 +283,7 @@ _AG_INIT_TYPE_CONV = {
AccessGroup.INIT_TYPE_UNKNOWN: 'Unknown',
AccessGroup.INIT_TYPE_OTHER: 'Other',
AccessGroup.INIT_TYPE_WWPN: 'WWPN',
- AccessGroup.INIT_TYPE_WWNN: 'WWNN',
- AccessGroup.INIT_TYPE_HOSTNAME: 'Hostname',
AccessGroup.INIT_TYPE_ISCSI_IQN: 'iSCSI',
- AccessGroup.INIT_TYPE_SAS: 'SAS',
AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED: 'iSCSI/WWPN Mixed',
}
--
1.8.3.1
Gris Ge
2014-08-01 03:17:22 UTC
Permalink
* Removed the support of AccessGroup.INIT_TYPE_SAS which is purely base
on IBM documents not tested.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/v7k/ibmv7k.py | 5 -----
1 file changed, 5 deletions(-)

diff --git a/plugin/v7k/ibmv7k.py b/plugin/v7k/ibmv7k.py
index 7a0c2d6..5781aed 100644
--- a/plugin/v7k/ibmv7k.py
+++ b/plugin/v7k/ibmv7k.py
@@ -326,11 +326,6 @@ class IbmV7k(IStorageAreaNetwork):
# TODO: Add support for > 1 iscsiname case.
# v7k cli is not parse friendly for > 1 case.
lsm_init_id = v7k_init['iscsi_name']
- elif 'SAS_WWPN' in v7k_init:
- # TODO: Add support for > 1 SAS_WWPN case.
- # v7k cli is not parse friendly for > 1 case.
- lsm_init_type = AccessGroup.INIT_TYPE_SAS
- lsm_init_id = v7k_init['SAS_WWPN']
else:
# Since lshost worked, support it as other type.
lsm_init_type = AccessGroup.INIT_TYPE_OTHER
--
1.8.3.1
Gris Ge
2014-08-01 03:17:23 UTC
Permalink
* Rename ErrorNumber.INVALID_IQN to ErrorNumber.INVALID_INIT.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/ontap/ontap.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index d33e230..6cf7ec0 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -44,7 +44,7 @@ e_map = {
na.Filer.ESERVICENOTLICENSED: ErrorNumber.NOT_LICENSED,
na.Filer.ECLONE_LICENSE_EXPIRED: ErrorNumber.NOT_LICENSED,
na.Filer.ECLONE_NOT_LICENSED: ErrorNumber.NOT_LICENSED,
- na.Filer.EINVALID_ISCSI_NAME: ErrorNumber.INVALID_IQN,
+ na.Filer.EINVALID_ISCSI_NAME: ErrorNumber.INVALID_INIT,
na.Filer.ETIMEOUT: ErrorNumber.PLUGIN_TIMEOUT,
na.Filer.EUNKNOWN: ErrorNumber.PLUGIN_ERROR
}
--
1.8.3.1
Gris Ge
2014-08-01 03:17:24 UTC
Permalink
* Remove --init-type option and do auto detection on initiator type.
* Manpage updated.

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

diff --git a/doc/man/lsmcli.1.in b/doc/man/lsmcli.1.in
index 1492847..d6337eb 100644
--- a/doc/man/lsmcli.1.in
+++ b/doc/man/lsmcli.1.in
@@ -357,11 +357,7 @@ Create an access group.
Required. The human friendly name for new access group.
.TP
\fB--init\fR \fI<INIT_ID>\fR
-Required. The first initiator ID of new access group.
-.TP
-\fB--init-type\fR \fI<INIT_TYPE>\fR
-Required. The initiator type. Valid values are: \fBWWPN\fR, \fBWWNN\fR,
-\fBISCSI\fR, \fBHOSTNAME\fR, \fBSAS\fR.
+Required. The first initiator ID of new access group. WWPN or iSCSI IQN.
.TP
\fB--sys\fR \fI<SYS_ID>\fR
Required. The ID of system where this access group should reside on.
@@ -373,11 +369,7 @@ Adds an initiator to an access group.
Required. ID of access group.
.TP
\fB--init\fR \fI<INIT_ID>\fR
-Required. ID of initiator to add.
-.TP
-\fB--init-type\fR \fI<INIT_TYPE>\fR
-Required. The initiator type. Valid values are: \fBWWPN\fR, \fBWWNN\fR,
-\fBISCSI\fR, \fBHOSTNAME\fR, \fBSAS\fR.
+Required. ID of initiator to add. WWPN or iSCSI IQN.

.SS access-group-remove
Removes an initiator from an access group.
diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index 3f68d05..bdabf52 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -23,6 +23,7 @@ import time
import tty
import termios
from collections import OrderedDict
+import re

from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
@@ -30,7 +31,8 @@ from argparse import RawTextHelpFormatter
from lsm import (Client, Pool, VERSION, LsmError, Disk,
Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
- AccessGroup, FileSystem, NfsExport, TargetPort)
+ AccessGroup, FileSystem, NfsExport, TargetPort,
+ iscsi_iqn_validate, wwpn_to_lsm_type)

from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
@@ -72,6 +74,20 @@ def getch():
termios.tcsetattr(fd, termios.TCSADRAIN, prev)
return ch

+def parse_convert_init(init_id):
+ """
+ If init_id is a WWPN, convert it into LSM standard version:
+ (?:[0-9a-f]{2}:){7}[0-9a-f]{2}
+
+ Return (converted_init_id, lsm_init_type)
+ """
+ if iscsi_iqn_validate(init_id, raise_error=False):
+ return (init_id, AccessGroup.INIT_TYPE_ISCSI_IQN)
+ wwpn = wwpn_to_lsm_type(init_id, raise_error=False)
+ if wwpn:
+ return (wwpn, AccessGroup.INIT_TYPE_WWPN)
+
+ raise ArgError("--init-id %s is not a valid WWPN or iSCSI IQN" % init_id)

## This class represents a command line argument error
class ArgError(Exception):
@@ -104,10 +120,6 @@ list_choices = ['VOLUMES', 'POOLS', 'FS', 'SNAPSHOTS',
'EXPORTS', "NFS_CLIENT_AUTH", 'ACCESS_GROUPS',
'SYSTEMS', 'DISKS', 'PLUGINS', 'TARGET_PORTS']

-init_types = ('WWPN', 'WWNN', 'ISCSI', 'HOSTNAME', 'SAS')
-init_id_help = "Access Group Initiator type: " + \
- ", ".join(init_types)
-
provision_types = ('DEFAULT', 'THIN', 'FULL')
provision_help = "provisioning type: " + ", ".join(provision_types)

@@ -171,9 +183,6 @@ disk_id_filter_opt = dict(name='--disk', metavar='<DISK_ID>',

size_opt = dict(name='--size', metavar='<SIZE>', help=size_help)

-init_type_opt = dict(name="--init-type", help=init_id_help,
- metavar='<INIT_TYPE>', choices=init_types,
- type=str.upper)
tgt_id_opt = dict(name="--tgt", help="Search by target port ID",
metavar='<TGT_ID>')

@@ -343,10 +352,6 @@ cmds = (
dict(name='--init', metavar='<INIT_ID>', action='append',
help='Initiator ID, only used when access-group-create is '
'not supported'),
- dict(name="--init-type", type=str.upper,
- metavar='<INIT_TYPE>', choices=init_types,
- help="%s only used when access-group-create is not supported"
- % init_id_help),
],
),

@@ -368,7 +373,6 @@ cmds = (
# TODO: _client.py access_group_create should support multiple
# initiators when creating.
dict(init_id_opt),
- dict(init_type_opt),
dict(sys_id_opt),
],
),
@@ -379,7 +383,6 @@ cmds = (
args=[
dict(ag_id_opt),
dict(init_id_opt),
- dict(init_type_opt),
],
),
dict(
@@ -949,21 +952,21 @@ class CmdLine:

## Creates an access group.
def access_group_create(self, args):
- init_type = ag_init_type_str_to_lsm(args.init_type)
system = _get_item(self.c.systems(), args.sys, "system id")
- access_group = self.c.access_group_create(args.name, args.init,
+ (init_id, init_type) = parse_convert_init(args.init)
+ access_group = self.c.access_group_create(args.name, init_id,
init_type, system)
self.display_data([access_group])

def _add_rm_access_grp_init(self, args, op):
lsm_ag = _get_item(self.c.access_groups(), args.ag, "access group id")
+ (init_id, init_type) = parse_convert_init(args.init)

if op:
- init_type = ag_init_type_str_to_lsm(args.init_type)
- return self.c.access_group_initiator_add(lsm_ag, args.init,
+ return self.c.access_group_initiator_add(lsm_ag, init_id,
init_type)
else:
- return self.c.access_group_initiator_delete(lsm_ag, args.init)
+ return self.c.access_group_initiator_delete(lsm_ag, init_id)

## Adds an initiator from an access group
def access_group_add(self, args):
@@ -980,7 +983,11 @@ class CmdLine:
self.display_data(vols)

def iscsi_chap(self, args):
- self.c.iscsi_chap_auth(args.init, args.in_user,
+ (init_id, init_type) = parse_convert_init(args.init)
+ if init_type != AccessGroup.INIT_TYPE_ISCSI_IQN:
+ raise ArgError("--init-id %s is not a valid iSCSI IQN" % args.init)
+
+ self.c.iscsi_chap_auth(init_id, args.in_user,
self.args.in_pass,
self.args.out_user,
self.args.out_pass)
@@ -1261,9 +1268,6 @@ class CmdLine:
if not args.ag and not args.init:
raise ArgError('Neither --ag nor --init is defined. '
'Please specify at lease one')
- if args.init and not args.init_type:
- raise ArgError('In volume-mask command, --init and '
- '--init-type should be defined at the same time')
if args.ag and args.init:
raise ArgError('In volume-mask command, --init is '
'conflicting with --ag')
@@ -1273,8 +1277,8 @@ class CmdLine:
ag = _get_item(self.c.access_groups(), args.ag, 'Access Group ID')

if args.init:
- init_type = ag_init_type_str_to_lsm(args.init_type)
- ag = AccessGroup(0, '', args.init, init_type, vol.system_id)
+ (init_id, init_type) = parse_convert_init(args.init)
+ ag = AccessGroup(0, '', [init_id], init_type, vol.system_id)
self.c.volume_mask(ag, vol)

def volume_unmask(self, args):
--
1.8.3.1
Gris Ge
2014-08-01 03:17:25 UTC
Permalink
* Convert LSM form of WWPN to SNIA form:
[0-9A-F]{16}

* Removed these initiator types:
AccessGroup.INIT_TYPE_WWNN
AccessGroup.INIT_TYPE_HOSTNAME
AccessGroup.INIT_TYPE_SAS

* Fix these problems:
1. _cim_init_check_or_create() incorrect return CIMInstanceName when
creation needed.
# Now, method renamed to _cim_init_path_check_or_create().
# will return CIMInstanceName always.

2. The confliction error will be raise as CIMError in InvokeMethod()
command, not in _wait_invoke() method.
# Now, we do confliction check when error happened.
# Not check pre-excute, which can save some time for most legal use.

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

diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 88ae335..4d15b0e 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -30,7 +30,7 @@ from pywbem import CIMError
from lsm import (IStorageAreaNetwork, error, uri_parse, LsmError, ErrorNumber,
JobStatus, md5, Pool, Volume, AccessGroup, System,
Capabilities, Disk, VERSION, TargetPort,
- search_property)
+ search_property, wwpn_to_lsm_type)

## Variable Naming scheme:
# cim_xxx CIMInstance
@@ -137,15 +137,22 @@ def _hex_string_format(hex_str, length, every):
return ':'.join(hex_str[i:i + every] for i in range(0, length, every))


+def _lsm_init_id_to_snia(lsm_init_id):
+ """
+ If lsm_init_id is a WWPN, convert it to SNIA format:
+ [0-9A-F]{16}
+ If not, return directly.
+ """
+ if wwpn_to_lsm_type(lsm_init_id, raise_error=False):
+ return lsm_init_id.replace(':', '').upper()
+ return lsm_init_id
+
+
class DMTF(object):
# CIM_StorageHardwareID['IDType']
- ID_TYPE_OTHER = pywbem.Uint16(1)
ID_TYPE_WWPN = pywbem.Uint16(2)
- ID_TYPE_WWNN = pywbem.Uint16(3)
- ID_TYPE_HOSTNAME = pywbem.Uint16(4)
ID_TYPE_ISCSI = pywbem.Uint16(5)
- ID_TYPE_SW_WWN = pywbem.Uint16(6)
- ID_TYPE_SAS = pywbem.Uint16(7)
+
TGT_PORT_USAGE_FRONTEND_ONLY = pywbem.Uint16(2)
TGT_PORT_USAGE_UNRESTRICTED = pywbem.Uint16(4)
# CIM_FCPort['PortDiscriminator']
@@ -182,28 +189,19 @@ class DMTF(object):
# CIM_GroupMaskingMappingCapabilities['SupportedInitiatorGroupFeatures']
# Allowing empty DeviceMaskingGroup
GMM_CAP_INIT_MG_ALLOW_EMPTY = pywbem.Uint16(4)
- # 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,
- DMTF.ID_TYPE_WWNN: AccessGroup.INIT_TYPE_WWNN,
- DMTF.ID_TYPE_HOSTNAME: AccessGroup.INIT_TYPE_HOSTNAME,
- DMTF.ID_TYPE_ISCSI: AccessGroup.INIT_TYPE_ISCSI_IQN,
- DMTF.ID_TYPE_SW_WWN: AccessGroup.INIT_TYPE_OTHER,
- DMTF.ID_TYPE_SAS: AccessGroup.INIT_TYPE_SAS,
-}
-

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


@@ -2616,20 +2614,24 @@ class Smis(IStorageAreaNetwork):

Method A defined in SNIA SMIS 1.6 deprecated the Method B and Method A
saved 1 query which provide better performance.
- Hence we try method A.
- Maybe someday, we will stop trying after knowing array's supported
- SMIS version.
+
+ Only iSCSI and WWPN CIM_StorageHardwareID will be returned:
+ CIM_StorageHardwareID['IDType'] == DMTF.ID_TYPE_WWPN(2)
+ or
+ CIM_StorageHardwareID['IDType'] == DMTF.ID_TYPE_ISCSI(5)
"""
cim_inits = []
if property_list is None:
- property_list = []
+ property_list = ['IDType']
+ else:
+ property_list = _merge_list(property_list, ['IDType'])

if (not self.fallback_mode and
self._profile_is_supported(SNIA.MASK_PROFILE,
SNIA.SMIS_SPEC_VER_1_6,
strict=False,
raise_error=False)):
- return self._c.Associators(
+ cim_inits = self._c.Associators(
cim_spc_path,
AssocClass='CIM_AssociatedPrivilege',
ResultClass='CIM_StorageHardwareID',
@@ -2645,7 +2647,13 @@ class Smis(IStorageAreaNetwork):
AssocClass='CIM_AuthorizedSubject',
ResultClass='CIM_StorageHardwareID',
PropertyList=property_list))
- return cim_inits
+ rc = []
+ for cim_init in cim_inits:
+ if cim_init['IDType'] == DMTF.ID_TYPE_WWPN or \
+ cim_init['IDType'] == DMTF.ID_TYPE_ISCSI:
+ rc.append(cim_init)
+
+ return rc

def _cim_init_of_init_mg(self, cim_init_mg_path, property_list=None):
"""
@@ -2862,23 +2870,15 @@ class Smis(IStorageAreaNetwork):

return search_property(rc, search_key, search_value)

- def _cim_init_check_or_create(self, cim_sys_path, init_id, init_type):
+ def _cim_init_path_check_or_create(self, cim_sys_path, init_id, init_type):
"""
Check whether CIM_StorageHardwareID exists, if not, create new one.
"""
cim_init = self._get_cim_instance_by_id(
'Initiator', init_id, raise_error=False, property_list=['IDType'])

- # In rare chance, cim_init might holding different init_type
- # As ExposePaths is using init_id, hence we raise error instead of
- # creating new one
if cim_init:
- if _dmtf_init_type_to_lsm(cim_init) != init_type:
- raise LsmError(ErrorNumber.EXISTS_INITIATOR,
- "Another initiator exists with the same ID "
- "%s, but different init_type %d:" %
- (init_id, _dmtf_init_type_to_lsm(cim_init)))
- return cim_init
+ return cim_init.path

# Create new one
dmtf_id_type = _lsm_init_type_to_dmtf(init_type)
@@ -2887,14 +2887,13 @@ class Smis(IStorageAreaNetwork):
"SMI-S Plugin does not support init_type %d" %
init_type)

- cim_init = self._cim_init_create(
+ return self._cim_init_path_create(
cim_sys_path, init_id, dmtf_id_type)

- return cim_init
-
- def _cim_init_create(self, cim_sys_path, init_id, dmtf_id_type):
+ def _cim_init_path_create(self, cim_sys_path, init_id, dmtf_id_type):
"""
Create a CIM_StorageHardwareID.
+ Return CIM_InstanceName
Raise error if failed. Return if pass.
"""
cim_hw_srv_path = self._get_cim_service_path(
@@ -2929,11 +2928,10 @@ class Smis(IStorageAreaNetwork):

# Check whether already added.
for exist_cim_init in exist_cim_inits:
- if self._init_id(exist_cim_init) == init_id and \
- _dmtf_init_type_to_lsm(exist_cim_init) == init_type:
- return copy.deepcopy(access_group)
+ if self._init_id(exist_cim_init) == init_id:
+ return copy.deepcopy(access_group)

- cim_init = self._cim_init_check_or_create(
+ 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(
@@ -2941,7 +2939,7 @@ class Smis(IStorageAreaNetwork):

in_params = {
'MaskingGroup': cim_init_mg.path,
- 'Members': [cim_init.path],
+ 'Members': [cim_init_path],
}
(rc, out) = self._c.InvokeMethod('AddMembers',
cim_gmm_path, **in_params)
@@ -2959,6 +2957,7 @@ class Smis(IStorageAreaNetwork):
@handle_cim_errors
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)

if mask_type == Smis.MASK_TYPE_GROUP:
@@ -2987,19 +2986,12 @@ class Smis(IStorageAreaNetwork):

for exist_cim_init in exist_cim_inits:
if self._init_id(exist_cim_init) == init_id:
- if _dmtf_init_type_to_lsm(exist_cim_init) != init_type:
- raise LsmError(ErrorNumber.EXISTS_INITIATOR,
- "Another initiator exists with the same ID "
- "%s, but different init_type %d:" %
- (init_id,
- _dmtf_init_type_to_lsm(exist_cim_init)))
-
return copy.deepcopy(access_group)

# Check to see if we have this initiator already, if not we
# create it and then add to the view.

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

cim_ccs_path = self._get_cim_service_path(
cim_sys.path, 'CIM_ControllerConfigurationService')
@@ -3093,6 +3085,7 @@ class Smis(IStorageAreaNetwork):

@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, flags=0):
+ init_id = _lsm_init_id_to_snia(init_id)
mask_type = self._mask_type(raise_error=True)

if mask_type == Smis.MASK_TYPE_GROUP:
@@ -4844,6 +4837,8 @@ class Smis(IStorageAreaNetwork):
confliction.
1. Create CIM_InitiatorMaskingGroup
"""
+ old_init_id = init_id
+ init_id = _lsm_init_id_to_snia(init_id)
if self.fallback_mode:
raise LsmError(ErrorNumber.NO_SUPPORT,
"access_group_create() is not supported in "
@@ -4886,44 +4881,62 @@ class Smis(IStorageAreaNetwork):
"iSCSI target port, which not allow creating "
"iSCSI IQN access group")

- cim_init = self._cim_init_check_or_create(
+ cim_init_path = self._cim_init_path_check_or_create(
cim_sys.path, init_id, init_type)

- cim_init_mg_pros = self._cim_init_mg_pros()
- exist_cim_init_mgs = self._c.Associators(
- cim_init.path,
- AssocClass='CIM_MemberOfCollection',
- ResultClass='CIM_InitiatorMaskingGroup',
- PropertyList=cim_init_mg_pros)
-
- if len(exist_cim_init_mgs) != 0:
- for exist_cim_init_mg in exist_cim_init_mgs:
- if exist_cim_init_mg['ElementName'] == name:
- return self._cim_init_mg_to_lsm(
- exist_cim_init_mg, system.id)
-
- # Name does not match.
- raise LsmError(ErrorNumber.EXISTS_INITIATOR,
- "Initiator %s already exist in other access group "
- % init_id +
- "with name %s and ID: %s" %
- (exist_cim_init_mgs[0]['ElementName'],
- md5(exist_cim_init_mgs[0]['DeviceID'])))
-
# Create CIM_InitiatorMaskingGroup
cim_gmm_path = self._get_cim_service_path(
cim_sys.path, 'CIM_GroupMaskingMappingService')

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

- (rc, out) = self._c.InvokeMethod(
- 'CreateGroup', cim_gmm_path, **in_params)
+ cim_init_mg_pros = self._cim_init_mg_pros()

- cim_init_mg_path = self._wait_invoke(
- rc, out, out_key='MaskingGroup',
- expect_class='CIM_InitiatorMaskingGroup')
+ try:
+ (rc, out) = self._c.InvokeMethod(
+ 'CreateGroup', cim_gmm_path, **in_params)
+
+ cim_init_mg_path = self._wait_invoke(
+ rc, out, out_key='MaskingGroup',
+ expect_class='CIM_InitiatorMaskingGroup')
+ except (LsmError, CIMError):
+ # Check possible failure
+ # 1. Initiator already exist in other group.
+ # If that group hold the same name as requested.
+ # We consider as a duplicate call, return the exist one.
+ exist_cim_init_mgs = self._c.Associators(
+ cim_init_path,
+ AssocClass='CIM_MemberOfCollection',
+ ResultClass='CIM_InitiatorMaskingGroup',
+ PropertyList=cim_init_mg_pros)
+
+ if len(exist_cim_init_mgs) != 0:
+ for exist_cim_init_mg in exist_cim_init_mgs:
+ if exist_cim_init_mg['ElementName'] == name:
+ return self._cim_init_mg_to_lsm(
+ exist_cim_init_mg, system.id)
+
+ # Name does not match.
+ raise LsmError(ErrorNumber.EXISTS_INITIATOR,
+ "Initiator %s " % old_init_id +
+ "already exist in other access group "
+ "with name %s and ID: %s" %
+ (exist_cim_init_mgs[0]['ElementName'],
+ md5(exist_cim_init_mgs[0]['InstanceID'])))
+ # 2. Requested name used by other group.
+ # Since 1) already checked whether any group containing
+ # requested init_id, now, it's surelly a confliction.
+ exist_cim_init_mgs = self._cim_init_mg_of(
+ cim_sys.path, property_list=['ElementName'])
+ for exist_cim_init_mg in exist_cim_init_mgs:
+ if exist_cim_init_mg['ElementName'] == name:
+ raise LsmError(ErrorNumber.EXISTS_ACCESS_GROUP,
+ "Requested name %s is used by " % name +
+ "another access group, but not containing "
+ "requested initiator %s" % old_init_id)
+ raise

cim_init_mg = self._c.GetInstance(
cim_init_mg_path, PropertyList=cim_init_mg_pros, LocalOnly=False)
--
1.8.3.1
Tony Asleson
2014-08-01 23:48:33 UTC
Permalink
Review notes:

make check
-> sim_lsmplugin: error: unrecognized arguments: --init-type ISCSI
as --init-type was removed.

smis.py: _INIT_TYPE_CONV has been removed, but it's still being
referenced on line 228.

client.py: iscsi_iqn_validate, missing import

For standard format of WWPN/iSCSI, I would rather document and enforce a
specific format (pick one) instead of reformatting what the user gives us.

Please revise, re-test and resubmit.

Thanks,
Tony
Post by Gris Ge
Please check individual patches for detail.
Thank you in advance.
python libraray: remove unused initiator type: INIT_TYPE_WWNN,
INIT_TYPE_HOSTNAME, INIT_TYPE_SAS
python library: standardize wwpn string to lsm way
lsmcli: remove unused init_type of AccessGroup
IBM v7k plugin: Removed not tested SAS init_type of AccessGroup
ontap plugin: Rename ErrorNumber.INVALID_IQN to
ErrorNumber.INVALID_INIT
lsmcli: Reomve --init-type and auto detect the init_type
SMI-S plugin: convert lsm WWPN form to SNIA form and fix access group
bugs
doc/man/lsmcli.1.in | 12 +--
plugin/ontap/ontap.py | 2 +-
plugin/smispy/smis.py | 175 ++++++++++++++++++++++-------------------
plugin/v7k/ibmv7k.py | 5 --
python_binding/lsm/__init__.py | 3 +-
python_binding/lsm/_client.py | 6 +-
python_binding/lsm/_common.py | 76 +++++++++++++++++-
python_binding/lsm/_data.py | 9 +--
tools/lsmcli/cmdline.py | 54 +++++++------
tools/lsmcli/data_display.py | 3 -
10 files changed, 212 insertions(+), 133 deletions(-)
Continue reading on narkive:
Loading...