Discussion:
[Libstoragemgmt-devel] [PATCH 0/3] Python library: Remove lsm.Initiator class and related
Gris Ge
2014-06-17 12:47:31 UTC
Permalink
Big changes:
* Removed class:
lsm.Initiator

* Removed methods:
lsm.Client.initiators()
lsm.Client.initiator_grant()
lsm.Client.initiator_revoke()
lsm.Client.volumes_accessible_by_initiator()
lsm.Client.initiators_granted_to_volume()
lsm.Volume._access_string_to_type()

* Updated methods:
lsm.Client.iscsi_chap_auth()
# Change argument from 'lsm.Initiator: initiator' to 'String: init_id'

* lsmcli:
* Removed these commands:
list --type INITIATORS
access-revoke
access-grant
volumes-accessible-initiator
initiators-granted-volume
volume-access-group
# Replaced by "list --type VOLUMES --ag <AG_ID>"
access-group-volume
# Replaced by "list --type ACCESS_GROUPS --vol <VOL_ID>"
* Renamed these commands:
access-group-add -> ag-add-init
access-group-remove -> ag-del-init
# Just make commands shorter and less confusing.

* SMI-S plugin is fully supporting interop namespace now.
It means, besides LSI MegaRAID and NetApp E-serial, there is no need to
define namespace in URI now.
It's just a side effect when I try to isolate lsm.Initiator from access
group.


Gris Ge (3):
Python library: Remove lsm.Initiator and related methods
LSM Plugins: Remove lsm.Initiator and related methods
lsmcli: Remove initiator commands and trivial changes

doc/man/lsmcli.1.in | 58 +---
plugin/nstor/nstor.py | 91 +-----
plugin/ontap/na.py | 2 +-
plugin/ontap/ontap.py | 74 ++---
plugin/sim/simarray.py | 196 +++----------
plugin/sim/simulator.py | 28 +-
plugin/smispy/eseries.py | 65 -----
plugin/smispy/smis.py | 622 ++++++++++++++---------------------------
plugin/targetd/targetd.py | 69 +----
plugin/v7k/ibmv7k.py | 150 +---------
python_binding/lsm/__init__.py | 6 +-
python_binding/lsm/_client.py | 69 +----
python_binding/lsm/_common.py | 7 +-
python_binding/lsm/_data.py | 36 ---
python_binding/lsm/_iplugin.py | 42 +--
tools/lsmcli/cmdline.py | 210 +++-----------
tools/lsmcli/data_display.py | 50 +---
17 files changed, 359 insertions(+), 1416 deletions(-)
--
1.8.3.1
Gris Ge
2014-06-17 12:47:32 UTC
Permalink
* Removed class:
lsm.Initiator

* Removed methods:
lsm.Client.initiators()
lsm.Client.initiator_grant()
lsm.Client.initiator_revoke()
lsm.Client.volumes_accessible_by_initiator()
lsm.Client.initiators_granted_to_volume()
lsm.Volume._access_string_to_type()

* Updated methods:
lsm.Client.iscsi_chap_auth()
# Change argument from 'lsm.Initiator: initiator' to 'String: init_id'

* Removed constants:
lsm.ErrorNumber.INITIATOR_NOT_IN_ACCESS_GROUP
lsm.ErrorNumber.INVALID_INIT
lsm.ErrorNumber.NOT_FOUND_INITIATOR
lsm.ErrorNumber.UNSUPPORTED_INITIATOR_TYPE
lsm.Capabilities.INITIATORS
lsm.Capabilities.INITIATORS_GRANTED_TO_VOLUME
lsm.Capabilities.VOLUME_INITIATOR_GRANT
lsm.Capabilities.VOLUME_INITIATOR_REVOKE
lsm.Capabilities.VOLUME_ACCESSIBLE_BY_INITIATOR
lsm.Volume.ACCESS_READ_ONLY
lsm.Volume.ACCESS_READ_WRITE
lsm.Volume.ACCESS_NONE

* Added constants:
lsm.ErrorNumber.LSM_BUG
# Indicate there is bug inside of LSM. User should report this error as
# a bug to upstream.
# I am intend to replace all 'INTERNAL_ERROR' and 'PLUGIN_ERROR' to this
# one.

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/lsm/__init__.py | 6 ++--
python_binding/lsm/_client.py | 69 ++----------------------------------------
python_binding/lsm/_common.py | 7 ++---
python_binding/lsm/_data.py | 36 ----------------------
python_binding/lsm/_iplugin.py | 42 +------------------------
5 files changed, 9 insertions(+), 151 deletions(-)

diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index 6427020..e1f6c36 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -5,9 +5,9 @@ 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
-from _data import Initiator, Disk, \
- Volume, Pool, System, FileSystem, FsSnapshot, NfsExport, BlockRange, \
- AccessGroup, OptionalData, Capabilities, txt_a
+from _data import (Disk, Volume, Pool, System, FileSystem, FsSnapshot,
+ NfsExport, BlockRange, AccessGroup, OptionalData,
+ Capabilities, txt_a)
from _iplugin import IPlugin, IStorageAreaNetwork, INetworkAttachedStorage, \
INfs

diff --git a/python_binding/lsm/_client.py b/python_binding/lsm/_client.py
index 3942b8d..74e663c 100644
--- a/python_binding/lsm/_client.py
+++ b/python_binding/lsm/_client.py
@@ -19,7 +19,7 @@ import time
import os
import unittest
from lsm import (Volume, NfsExport, Capabilities, Pool, System,
- Initiator, Disk, AccessGroup, FileSystem, FsSnapshot,
+ Disk, AccessGroup, FileSystem, FsSnapshot,
uri_parse, LsmError, JobStatus, ErrorNumber,
INetworkAttachedStorage)

@@ -436,23 +436,12 @@ class Client(INetworkAttachedStorage):
"""
return self._tp.rpc('systems', _del_self(locals()))

- ## Returns an array of initiator objects
- # @param self The this pointer
- # @param flags Reserved for future use, must be zero.
- # @returns An array of initiator objects.
- @_return_requires([Initiator])
- def initiators(self, flags=0):
- """
- Return an array of initiator objects
- """
- return self._tp.rpc('initiators', _del_self(locals()))
-
## Register a user/password for the specified initiator for CHAP
# authentication.
# Note: If you pass an empty user and password the expected behavior is to
# remove any authentication for the specified initiator.
# @param self The this pointer
- # @param initiator The initiator object
+ # @param init_id The initiator ID
# @param in_user User for inbound CHAP
# @param in_password Password for inbound CHAP
# @param out_user Outbound username
@@ -460,7 +449,7 @@ class Client(INetworkAttachedStorage):
# @param flags Reserved for future use, must be zero.
# @returns None on success, throws LsmError on errors.
@_return_requires(None)
- def iscsi_chap_auth(self, initiator, in_user, in_password,
+ def iscsi_chap_auth(self, init_id, in_user, in_password,
out_user, out_password, flags=0):
"""
Register a user/password for the specified initiator for CHAP
@@ -468,58 +457,6 @@ class Client(INetworkAttachedStorage):
"""
return self._tp.rpc('iscsi_chap_auth', _del_self(locals()))

- ## Grants access so an initiator can read/write the specified volume.
- # @param self The this pointer
- # @param initiator_id The iqn, WWID etc.
- # @param initiator_type Enumerated initiator type
- # @param volume Volume to grant access to
- # @param access Enumerated access type
- # @param flags Reserved for future use, must be zero
- # @returns None on success, throws LsmError on errors.
- @_return_requires(None)
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- flags=0):
- """
- Allows an initiator to access a volume.
- """
- return self._tp.rpc('initiator_grant', _del_self(locals()))
-
- ## Revokes access for a volume for the specified initiator.
- # @param self The this pointer
- # @param initiator The iqn, WWID etc.
- # @param volume The volume to revoke access for
- # @param flags Reserved for future use, must be zero
- # @returns None on success, throws LsmError on errors.
- @_return_requires(None)
- def initiator_revoke(self, initiator, volume, flags=0):
- """
- Revokes access to a volume for the specified initiator
- """
- return self._tp.rpc('initiator_revoke', _del_self(locals()))
-
- ## Returns a list of volumes that are accessible from the specified
- # initiator.
- # @param self The this pointer
- # @param initiator The initiator object
- # @param flags Reserved for future use, must be zero
- @_return_requires([Volume])
- def volumes_accessible_by_initiator(self, initiator, flags=0):
- """
- Returns a list of volumes that the initiator has access to.
- """
- return self._tp.rpc('volumes_accessible_by_initiator',
- _del_self(locals()))
-
- ## Returns a list of initiators that have access to the specified volume.
- # @param self The this pointer
- # @param volume The volume in question
- # @param flags Reserved for future use, must be zero
- # @returns List of initiators
- @_return_requires([Initiator])
- def initiators_granted_to_volume(self, volume, flags=0):
- return self._tp.rpc('initiators_granted_to_volume',
- _del_self(locals()))
-
## Returns an array of volume objects
# @param self The this pointer
# @param flags Reserved for future use, must be zero.
diff --git a/python_binding/lsm/_common.py b/python_binding/lsm/_common.py
index 3eca617..1cec9d0 100644
--- a/python_binding/lsm/_common.py
+++ b/python_binding/lsm/_common.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2013 Red Hat, Inc.
+# Copyright (C) 2011-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
@@ -423,6 +423,7 @@ class ErrorLevel(object):
class ErrorNumber(object):
OK = 0
INTERNAL_ERROR = 1
+ LSM_BUG = 2
JOB_STARTED = 7
INDEX_BOUNDS = 10
TIMEOUT = 11
@@ -433,7 +434,6 @@ class ErrorNumber(object):
EXISTS_INITIATOR = 52
EXISTS_NAME = 53
FS_NOT_EXPORTED = 54
- INITIATOR_NOT_IN_ACCESS_GROUP = 55
EXISTS_POOL = 56
EXISTS_VOLUME = 57

@@ -442,7 +442,6 @@ class ErrorNumber(object):
INVALID_CONN = 102
INVALID_ERR = 103
INVALID_FS = 104
- INVALID_INIT = 105
INVALID_JOB = 106
INVALID_NAME = 107
INVALID_NFS = 108
@@ -478,7 +477,6 @@ class ErrorNumber(object):
NOT_FOUND_SS = 204
NOT_FOUND_VOLUME = 205
NOT_FOUND_NFS_EXPORT = 206
- NOT_FOUND_INITIATOR = 207
NOT_FOUND_SYSTEM = 208
NOT_FOUND_DISK = 209

@@ -511,7 +509,6 @@ class ErrorNumber(object):
TRANSPORT_SERIALIZATION = 401
TRANSPORT_INVALID_ARG = 402

- UNSUPPORTED_INITIATOR_TYPE = 450
UNSUPPORTED_PROVISIONING = 451
UNSUPPORTED_REPLICATION_TYPE = 452

diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 6c65faa..f86d283 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -176,26 +176,6 @@ class IData(object):


@default_property('id', doc="Unique identifier")
-@default_property('type', doc="Enumerated initiator type")
-@default_property('name', doc="User supplied name")
-class Initiator(IData):
- """
- Represents an initiator.
- """
- (TYPE_OTHER, TYPE_PORT_WWN, TYPE_NODE_WWN, TYPE_HOSTNAME, TYPE_ISCSI,
- TYPE_SAS) = (1, 2, 3, 4, 5, 7)
-
- def __init__(self, _id, _type, _name):
-
- if not _name or not len(_name):
- name = "Unsupported"
-
- self._id = _id # Identifier
- self._type = _type # Initiator type id
- self._name = _name # Initiator name
-
-
-@default_property('id', doc="Unique identifier")
@default_property('name', doc="Disk name (aka. vendor)")
@default_property('disk_type', doc="Enumerated type of disk")
@default_property('block_size', doc="Size of each block")
@@ -305,16 +285,6 @@ class Volume(IData):
(PROVISION_UNKNOWN, PROVISION_THIN, PROVISION_FULL, PROVISION_DEFAULT) = \
(-1, 1, 2, 3)

- #Initiator access
- (ACCESS_READ_ONLY, ACCESS_READ_WRITE, ACCESS_NONE) = (1, 2, 3)
-
- @staticmethod
- def _access_string_to_type(access):
- if access == "RW":
- return Volume.ACCESS_READ_WRITE
- else:
- return Volume.ACCESS_READ_ONLY
-
def __init__(self, _id, _name, _vpd83, _block_size, _num_of_blocks,
_status, _system_id, _pool_id, _optional_data=None,
_plugin_data=None):
@@ -841,12 +811,6 @@ class Capabilities(IData):
VOLUME_CHILD_DEPENDENCY = 45
VOLUME_CHILD_DEPENDENCY_RM = 46

- INITIATORS = 47
- INITIATORS_GRANTED_TO_VOLUME = 48
-
- VOLUME_INITIATOR_GRANT = 50
- VOLUME_INITIATOR_REVOKE = 51
- VOLUME_ACCESSIBLE_BY_INITIATOR = 52
VOLUME_ISCSI_CHAP_AUTHENTICATION = 53

VOLUME_THIN = 55
diff --git a/python_binding/lsm/_iplugin.py b/python_binding/lsm/_iplugin.py
index 6cb4d03..d903fc3 100644
--- a/python_binding/lsm/_iplugin.py
+++ b/python_binding/lsm/_iplugin.py
@@ -181,14 +181,6 @@ class IStorageAreaNetwork(IPlugin):
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")

- def initiators(self, flags=0):
- """
- Return an array of initiator objects
-
- Raises LsmError on error
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
def volume_create(self, pool, volume_name, size_bytes, provisioning,
flags=0):
"""
@@ -268,7 +260,7 @@ class IStorageAreaNetwork(IPlugin):
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")

- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
out_password, flags):
"""
Register a user/password for the specified initiator for CHAP
@@ -282,23 +274,6 @@ class IStorageAreaNetwork(IPlugin):
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")

- def initiator_grant(self, init_id, initiator_type, volume, access,
- flags=0):
- """
- Allows an initiator to access a volume.
-
- Returns None on success, else raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
- def initiator_revoke(self, initiator, volume, flags=0):
- """
- Revokes access to a volume for the specified initiator
-
- Returns None on success, else raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
def volume_mask(self, access_group, volume, flags=0):
"""
Allows an access group to access a volume.
@@ -384,21 +359,6 @@ class IStorageAreaNetwork(IPlugin):
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")

- def volumes_accessible_by_initiator(self, initiator, flags=0):
- """
- Returns a list of volumes that the initiator has access to,
- Raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
- def initiators_granted_to_volume(self, volume, flags=0):
- """
- Returns a list of initiators that have access to the specified volume,
- Raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
-
class INetworkAttachedStorage(IPlugin):
"""
Class the represents Network attached storage (Common NFS/CIFS operations)
--
1.8.3.1
Tony Asleson
2014-06-17 18:38:21 UTC
Permalink
Post by Gris Ge
lsm.ErrorNumber.LSM_BUG
# Indicate there is bug inside of LSM. User should report this error as
# a bug to upstream.
# I am intend to replace all 'INTERNAL_ERROR' and 'PLUGIN_ERROR' to this
# one.
I would like to distinguish between the library and plug-in bugs as in
the future not all plug-ins may be published and distributed by project,
but by array providers. This way users can be better informed where
they need to seek assistance when they encounter a problem.

Regards,
Tony
Tony Asleson
2014-06-18 21:42:57 UTC
Permalink
Patch committed

Thanks,
Tony
Post by Gris Ge
lsm.Initiator
lsm.Client.initiators()
lsm.Client.initiator_grant()
lsm.Client.initiator_revoke()
lsm.Client.volumes_accessible_by_initiator()
lsm.Client.initiators_granted_to_volume()
lsm.Volume._access_string_to_type()
lsm.Client.iscsi_chap_auth()
# Change argument from 'lsm.Initiator: initiator' to 'String: init_id'
lsm.ErrorNumber.INITIATOR_NOT_IN_ACCESS_GROUP
lsm.ErrorNumber.INVALID_INIT
lsm.ErrorNumber.NOT_FOUND_INITIATOR
lsm.ErrorNumber.UNSUPPORTED_INITIATOR_TYPE
lsm.Capabilities.INITIATORS
lsm.Capabilities.INITIATORS_GRANTED_TO_VOLUME
lsm.Capabilities.VOLUME_INITIATOR_GRANT
lsm.Capabilities.VOLUME_INITIATOR_REVOKE
lsm.Capabilities.VOLUME_ACCESSIBLE_BY_INITIATOR
lsm.Volume.ACCESS_READ_ONLY
lsm.Volume.ACCESS_READ_WRITE
lsm.Volume.ACCESS_NONE
lsm.ErrorNumber.LSM_BUG
# Indicate there is bug inside of LSM. User should report this error as
# a bug to upstream.
# I am intend to replace all 'INTERNAL_ERROR' and 'PLUGIN_ERROR' to this
# one.
---
python_binding/lsm/__init__.py | 6 ++--
python_binding/lsm/_client.py | 69 ++----------------------------------------
python_binding/lsm/_common.py | 7 ++---
python_binding/lsm/_data.py | 36 ----------------------
python_binding/lsm/_iplugin.py | 42 +------------------------
5 files changed, 9 insertions(+), 151 deletions(-)
diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index 6427020..e1f6c36 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -5,9 +5,9 @@ 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
-from _data import Initiator, Disk, \
- Volume, Pool, System, FileSystem, FsSnapshot, NfsExport, BlockRange, \
- AccessGroup, OptionalData, Capabilities, txt_a
+from _data import (Disk, Volume, Pool, System, FileSystem, FsSnapshot,
+ NfsExport, BlockRange, AccessGroup, OptionalData,
+ Capabilities, txt_a)
from _iplugin import IPlugin, IStorageAreaNetwork, INetworkAttachedStorage, \
INfs
diff --git a/python_binding/lsm/_client.py b/python_binding/lsm/_client.py
index 3942b8d..74e663c 100644
--- a/python_binding/lsm/_client.py
+++ b/python_binding/lsm/_client.py
@@ -19,7 +19,7 @@ import time
import os
import unittest
from lsm import (Volume, NfsExport, Capabilities, Pool, System,
- Initiator, Disk, AccessGroup, FileSystem, FsSnapshot,
+ Disk, AccessGroup, FileSystem, FsSnapshot,
uri_parse, LsmError, JobStatus, ErrorNumber,
INetworkAttachedStorage)
"""
return self._tp.rpc('systems', _del_self(locals()))
- ## Returns an array of initiator objects
- """
- Return an array of initiator objects
- """
- return self._tp.rpc('initiators', _del_self(locals()))
-
## Register a user/password for the specified initiator for CHAP
# authentication.
# Note: If you pass an empty user and password the expected behavior is to
# remove any authentication for the specified initiator.
@_return_requires(None)
- def iscsi_chap_auth(self, initiator, in_user, in_password,
+ def iscsi_chap_auth(self, init_id, in_user, in_password,
"""
Register a user/password for the specified initiator for CHAP
"""
return self._tp.rpc('iscsi_chap_auth', _del_self(locals()))
- ## Grants access so an initiator can read/write the specified volume.
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- """
- Allows an initiator to access a volume.
- """
- return self._tp.rpc('initiator_grant', _del_self(locals()))
-
- ## Revokes access for a volume for the specified initiator.
- """
- Revokes access to a volume for the specified initiator
- """
- return self._tp.rpc('initiator_revoke', _del_self(locals()))
-
- ## Returns a list of volumes that are accessible from the specified
- # initiator.
- """
- Returns a list of volumes that the initiator has access to.
- """
- return self._tp.rpc('volumes_accessible_by_initiator',
- _del_self(locals()))
-
- ## Returns a list of initiators that have access to the specified volume.
- return self._tp.rpc('initiators_granted_to_volume',
- _del_self(locals()))
-
## Returns an array of volume objects
diff --git a/python_binding/lsm/_common.py b/python_binding/lsm/_common.py
index 3eca617..1cec9d0 100644
--- a/python_binding/lsm/_common.py
+++ b/python_binding/lsm/_common.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2013 Red Hat, Inc.
+# Copyright (C) 2011-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
OK = 0
INTERNAL_ERROR = 1
+ LSM_BUG = 2
JOB_STARTED = 7
INDEX_BOUNDS = 10
TIMEOUT = 11
EXISTS_INITIATOR = 52
EXISTS_NAME = 53
FS_NOT_EXPORTED = 54
- INITIATOR_NOT_IN_ACCESS_GROUP = 55
EXISTS_POOL = 56
EXISTS_VOLUME = 57
INVALID_CONN = 102
INVALID_ERR = 103
INVALID_FS = 104
- INVALID_INIT = 105
INVALID_JOB = 106
INVALID_NAME = 107
INVALID_NFS = 108
NOT_FOUND_SS = 204
NOT_FOUND_VOLUME = 205
NOT_FOUND_NFS_EXPORT = 206
- NOT_FOUND_INITIATOR = 207
NOT_FOUND_SYSTEM = 208
NOT_FOUND_DISK = 209
TRANSPORT_SERIALIZATION = 401
TRANSPORT_INVALID_ARG = 402
- UNSUPPORTED_INITIATOR_TYPE = 450
UNSUPPORTED_PROVISIONING = 451
UNSUPPORTED_REPLICATION_TYPE = 452
diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 6c65faa..f86d283 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@default_property('id', doc="Unique identifier")
- """
- Represents an initiator.
- """
- (TYPE_OTHER, TYPE_PORT_WWN, TYPE_NODE_WWN, TYPE_HOSTNAME, TYPE_ISCSI,
- TYPE_SAS) = (1, 2, 3, 4, 5, 7)
-
-
- name = "Unsupported"
-
- self._id = _id # Identifier
- self._type = _type # Initiator type id
- self._name = _name # Initiator name
-
-
@default_property('name', doc="Disk name (aka. vendor)")
@default_property('disk_type', doc="Enumerated type of disk")
@default_property('block_size', doc="Size of each block")
(PROVISION_UNKNOWN, PROVISION_THIN, PROVISION_FULL, PROVISION_DEFAULT) = \
(-1, 1, 2, 3)
- #Initiator access
- (ACCESS_READ_ONLY, ACCESS_READ_WRITE, ACCESS_NONE) = (1, 2, 3)
-
- return Volume.ACCESS_READ_WRITE
- return Volume.ACCESS_READ_ONLY
-
def __init__(self, _id, _name, _vpd83, _block_size, _num_of_blocks,
_status, _system_id, _pool_id, _optional_data=None,
VOLUME_CHILD_DEPENDENCY = 45
VOLUME_CHILD_DEPENDENCY_RM = 46
- INITIATORS = 47
- INITIATORS_GRANTED_TO_VOLUME = 48
-
- VOLUME_INITIATOR_GRANT = 50
- VOLUME_INITIATOR_REVOKE = 51
- VOLUME_ACCESSIBLE_BY_INITIATOR = 52
VOLUME_ISCSI_CHAP_AUTHENTICATION = 53
VOLUME_THIN = 55
diff --git a/python_binding/lsm/_iplugin.py b/python_binding/lsm/_iplugin.py
index 6cb4d03..d903fc3 100644
--- a/python_binding/lsm/_iplugin.py
+++ b/python_binding/lsm/_iplugin.py
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
- """
- Return an array of initiator objects
-
- Raises LsmError on error
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
def volume_create(self, pool, volume_name, size_bytes, provisioning,
"""
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
"""
Register a user/password for the specified initiator for CHAP
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
- def initiator_grant(self, init_id, initiator_type, volume, access,
- """
- Allows an initiator to access a volume.
-
- Returns None on success, else raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
- """
- Revokes access to a volume for the specified initiator
-
- Returns None on success, else raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
"""
Allows an access group to access a volume.
"""
raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
- """
- Returns a list of volumes that the initiator has access to,
- Raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
- """
- Returns a list of initiators that have access to the specified volume,
- Raises LsmError on errors.
- """
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
-
"""
Class the represents Network attached storage (Common NFS/CIFS operations)
Gris Ge
2014-06-17 12:47:33 UTC
Permalink
* Remove lsm.Initiator and related methods from plugins.
* Update iscsi_chap_auth().
* SMI-S plugin now fully support interop namespace.
* Removed some unused methods from SMI-S plugin.
* Tested by these commands:
lsmcli list --type access_groups
lsmcli ag-add-init --ag <AG_ID> --init <INIT_ID> --init-type WWPN|iSCSI
lsmcli ag-del-init --ag <AG_ID> --init <INIT_ID>
lsmcli volume-mask --vol <VOL_ID> --ag <AG_ID>
lsmcli list --type volumes --ag <AG_ID>
lsmcli list --type access_groups --vol <VOL_ID>
lsmcli volume-unmask --vol <VOL_ID> --ag <AG_ID>
* Tested on these plugin:
nstor:
Nexentastor 3.1.5
ONTAP:
ONTAP 8.1.2 7-mode
Simulator:
SimArray 2.4
SMI-S:
EMC VNX(full test)
SMI-S access group query test:
EMC VMAX, FUJITSU ETERNUS, HDS AMS[1], IBM XIV, NetApp ONTAP[2]
SMI-S NetApp E-Serial:
'Masking and Mapping' not supported.
Targetd:
lsmcli volume-mask --vol <VOL_ID> --init <INIT_ID> --init-type iSCSI
lsmcli list --type volumes --ag <AG_ID>
lsmcli list --type access_groups --vol <VOL_ID>
lsmcli volume-unmask --vol <VOL_ID> --ag <AG_ID>

[1] HDS AMS marked 'other' type of access_group, need investigation, might be
iSCSI target port.

[2] NetApp ONTAP SMI-S provider does not provider initiator ID when call
access_groups(), need investigation.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/nstor/nstor.py | 91 +------
plugin/ontap/na.py | 2 +-
plugin/ontap/ontap.py | 74 ++----
plugin/sim/simarray.py | 196 ++++-----------
plugin/sim/simulator.py | 28 +--
plugin/smispy/eseries.py | 65 -----
plugin/smispy/smis.py | 622 ++++++++++++++++------------------------------
plugin/targetd/targetd.py | 69 +----
plugin/v7k/ibmv7k.py | 150 +----------
9 files changed, 302 insertions(+), 995 deletions(-)

diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index f655a5e..c47a670 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -30,7 +30,7 @@ import time
import traceback

from lsm import (AccessGroup, Capabilities, ErrorNumber, FileSystem, INfs,
- IStorageAreaNetwork, Initiator, LsmError, NfsExport, Pool,
+ IStorageAreaNetwork, LsmError, NfsExport, Pool,
FsSnapshot, System, VERSION, Volume, md5, Error,
common_urllib2_error_handler, search_property)

@@ -502,18 +502,6 @@ class NexentaStor(INfs, IStorageAreaNetwork):
return search_property(vol_list, search_key, search_value)

@handle_nstor_errors
- def initiators(self, flags=0):
- """
- Return an array of initiator objects
- """
- i_list = []
- for ag in self.access_groups():
- for initiator_id in ag.init_ids:
- i_list.append(Initiator(initiator_id,
- Initiator.TYPE_ISCSI, initiator_id))
- return i_list
-
- @handle_nstor_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
flags=0):
"""
@@ -633,7 +621,7 @@ class NexentaStor(INfs, IStorageAreaNetwork):
# return

@handle_nstor_errors
- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
out_password, flags=0):
"""
Register a user/password for the specified initiator for CHAP
@@ -652,60 +640,25 @@ class NexentaStor(INfs, IStorageAreaNetwork):

try:
self._request("create_initiator", "iscsitarget",
- [initiator.name,
+ [init_id,
{'initiatorchapuser': in_user,
'initiatorchapsecret': in_password}])
except:
self._request("modify_initiator", "iscsitarget",
- [initiator.name,
+ [init_id,
{'initiatorchapuser': in_user,
'initiatorchapsecret': in_password}])

self._request("modify_initiator", "iscsitarget",
- [initiator.name,
+ [init_id,
{'initiatorchapuser': in_user,
'initiatorchapsecret': in_password}])
return

- @handle_nstor_errors
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- flags=0):
- """
- Allows an initiator to access a volume.
- """
- hg_name = NexentaStor._calc_group(initiator_id)
- try:
- self.access_group_create(hg_name, initiator_id, initiator_type,
- 'NA')
- except:
- pass
- self._volume_mask(hg_name, volume.name)
- return
-
def _get_views(self, volume_name):
return self._request("list_lun_mapping_entries", "scsidisk",
[volume_name])

- @handle_nstor_errors
- def initiator_revoke(self, initiator, volume, flags=0):
- """
- Revokes access to a volume for the specified initiator
- """
- ag_name = NexentaStor._calc_group(initiator.name)
- views = self._get_views(volume.name)
- view_number = -1
- for view in views:
- if view['host_group'] == ag_name:
- view_number = view['entry_number']
- if view_number == -1:
- raise LsmError(ErrorNumber.NO_MAPPING, "There is no such mapping "
- "for volume %s" %
- volume.name)
- self._request("remove_lun_mapping_entry", "scsidisk",
- [volume.name, view_number])
- self._request("destroy_hostgroup", "stmf", [ag_name])
- return
-
def _volume_mask(self, group_name, volume_name):
self._request("add_lun_mapping_entry", "scsidisk",
[volume_name, {'host_group': group_name}])
@@ -800,7 +753,7 @@ class NexentaStor(INfs, IStorageAreaNetwork):
"""
Adds an initiator to an access group
"""
- if init_type != Initiator.TYPE_ISCSI:
+ if init_type != AccessGroup.INIT_TYPE_ISCSI_IQN:
raise LsmError(ErrorNumber.NO_SUPPORT,
"Nstor only support iSCSI Access Group")

@@ -869,35 +822,3 @@ class NexentaStor(INfs, IStorageAreaNetwork):
clone_name = dep.split('@')[0]
self._request("promote", "volume", [clone_name])
return None
-
- @handle_nstor_errors
- def volumes_accessible_by_initiator(self, initiator, flags=0):
- """
- Returns a list of volumes that the initiator has access to.
- """
- ag_name = NexentaStor._calc_group(initiator.name)
- volumes = []
- all_volumes_list = self.volumes()
- for vol in all_volumes_list:
- for view in self._get_views(vol.name):
- if view['host_group'] == ag_name:
- volumes.append(vol)
- return volumes
-
- @handle_nstor_errors
- def initiators_granted_to_volume(self, volume, flags=0):
- """
- Returns a list of initiators that have access to the specified volume.
- """
- ag_list = self.access_groups()
- i_list = self.initiators()
- initiators_id = []
- for view in self._get_views(volume.name):
- for ag in ag_list:
- if ag.name == view['host_group']:
- initiators_id.extend(ag.initiators)
- initiators = []
- for i in i_list:
- if i.name in initiators_id:
- initiators.append(i)
- return initiators
diff --git a/plugin/ontap/na.py b/plugin/ontap/na.py
index 0986a9c..214cc0d 100644
--- a/plugin/ontap/na.py
+++ b/plugin/ontap/na.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2013 Red Hat, Inc.
+# Copyright (C) 2012-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
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index cde128f..203dfe7 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -23,7 +23,7 @@ import urlparse
import sys

import na
-from lsm import (Volume, Initiator, FileSystem, FsSnapshot, NfsExport,
+from lsm import (Volume, FileSystem, FsSnapshot, NfsExport,
AccessGroup, System, Capabilities, Disk, Pool, OptionalData,
IStorageAreaNetwork, INfs, LsmError, ErrorNumber, JobStatus,
md5, Error, VERSION, common_urllib2_error_handler,
@@ -519,32 +519,6 @@ class Ontap(IStorageAreaNetwork, INfs):
def systems(self, flags=0):
return [self.sys_info]

- @handle_ontap_errors
- def initiators(self, flags=0):
- """
- We will list all the initiators that are in all the groups.
- """
- rc = []
- groups = self.f.igroups()
-
- for g in groups:
- #Get the initiator in the group
- if g['initiators']:
- inits = na.to_list(g['initiators']['initiator-info'])
-
- for i in inits:
- init = i['initiator-name']
-
- if g['initiator-group-type'] == 'iscsi':
- init_type = Initiator.TYPE_ISCSI
- else:
- init_type = Initiator.TYPE_PORT_WWN
-
- name = init
- rc.append(Initiator(init, init_type, name))
-
- return rc
-
def _get_volume(self, vol_name, pool_id):
return self._lun(self.f.luns_get_specific(pool_id, vol_name, None)[0])

@@ -735,13 +709,13 @@ class Ontap(IStorageAreaNetwork, INfs):
return self.f.lun_offline(volume.name)

@handle_ontap_errors
- def volume_mask(self, group, volume, flags=0):
- self.f.lun_map(group.name, volume.name)
+ def volume_mask(self, access_group, volume, flags=0):
+ self.f.lun_map(access_group.name, volume.name)
return None

@handle_ontap_errors
- def volume_unmask(self, group, volume, flags=0):
- self.f.lun_unmap(group.name, volume.name)
+ def volume_unmask(self, access_group, volume, flags=0):
+ self.f.lun_unmap(access_group.name, volume.name)
return None

@staticmethod
@@ -772,20 +746,24 @@ class Ontap(IStorageAreaNetwork, INfs):
[self._access_group(g) for g in groups], search_key, search_value)

@handle_ontap_errors
- def access_group_create(self, name, initiator_id, id_type, system_id,
+ def access_group_create(self, name, init_id, init_type, system_id,
flags=0):
cur_groups = self.access_groups()
for cg in cur_groups:
if cg.name == name:
raise LsmError(ErrorNumber.EXISTS_ACCESS_GROUP,
- "Access group exists!")
+ "Access group with the same name exists!")

- if id_type == Initiator.TYPE_ISCSI:
+ if init_type == AccessGroup.INIT_TYPE_ISCSI_IQN:
self.f.igroup_create(name, 'iscsi')
- else:
+ elif init_type == AccessGroup.INIT_TYPE_WWPN:
self.f.igroup_create(name, 'fcp')
+ else:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "ONTAP only support iSCSI and FC/FCoE, but got "
+ "init_type: %d" % init_type)

- self.f.igroup_add_initiator(name, initiator_id)
+ self.f.igroup_add_initiator(name, init_id)

groups = self.access_groups()
for g in groups:
@@ -796,25 +774,25 @@ class Ontap(IStorageAreaNetwork, INfs):
"Unable to find group just created!")

@handle_ontap_errors
- def access_group_delete(self, group, flags=0):
- return self.f.igroup_delete(group.name)
+ def access_group_delete(self, access_group, flags=0):
+ return self.f.igroup_delete(access_group.name)

@handle_ontap_errors
- def access_group_initiator_add(self, group, initiator_id, id_type,
+ def access_group_initiator_add(self, access_group, init_id, init_type,
flags=0):
- return self.f.igroup_add_initiator(group.name, initiator_id)
+ return self.f.igroup_add_initiator(access_group.name, init_id)

@handle_ontap_errors
- def access_group_initiator_delete(self, group, initiator_id, flags=0):
- return self.f.igroup_del_initiator(group.name, initiator_id)
+ def access_group_initiator_delete(self, access_group, init_id, flags=0):
+ return self.f.igroup_del_initiator(access_group.name, init_id)

@handle_ontap_errors
- def volumes_accessible_by_access_group(self, group, flags=0):
+ def volumes_accessible_by_access_group(self, access_group, flags=0):
rc = []

- if len(group.initiators):
- luns = self.f.lun_initiator_list_map_info(group.initiators[0],
- group.name)
+ if len(access_group.init_ids):
+ luns = self.f.lun_initiator_list_map_info(access_group.init_ids[0],
+ access_group.name)
rc = [self._lun(l) for l in luns]

return rc
@@ -825,7 +803,7 @@ class Ontap(IStorageAreaNetwork, INfs):
return [self._access_group(g) for g in groups]

@handle_ontap_errors
- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
out_password, flags=0):
if out_user and out_password and \
(in_user is None or in_password is None):
@@ -833,7 +811,7 @@ class Ontap(IStorageAreaNetwork, INfs):
"out_user and out_password only supported if "
"inbound is supplied")

- self.f.iscsi_initiator_add_auth(initiator.id, in_user, in_password,
+ self.f.iscsi_initiator_add_auth(init_id, in_user, in_password,
out_user, out_password)

@staticmethod
diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index c7cc2cc..0ccc4dc 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2013 Red Hat, Inc.
+# Copyright (C) 2011-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
@@ -27,8 +27,8 @@ import time

from lsm import (size_human_2_size_bytes, size_bytes_2_size_human)
from lsm import (System, Volume, Disk, Pool, FileSystem, AccessGroup,
- Initiator, FsSnapshot, NfsExport, OptionalData, md5,
- LsmError, ErrorNumber, JobStatus)
+ FsSnapshot, NfsExport, OptionalData, md5, LsmError,
+ ErrorNumber, JobStatus)

# Used for format width for disks
D_FMT = 5
@@ -387,30 +387,6 @@ class SimArray(object):
sim_ags = self.data.access_groups_granted_to_volume(vol_id, flags)
return [SimArray._sim_ag_2_lsm(a) for a in sim_ags]

- @staticmethod
- def _sim_init_2_lsm(sim_init):
- return Initiator(sim_init['init_id'], sim_init['init_type'],
- sim_init['name'])
-
- def inits(self, flags=0):
- sim_inits = self.data.inits()
- return [SimArray._sim_init_2_lsm(a) for a in sim_inits]
-
- def initiator_grant(self, init_id, init_type, vol_id, access, flags=0):
- return self.data.initiator_grant(
- init_id, init_type, vol_id, access, flags)
-
- def initiator_revoke(self, init_id, vol_id, flags=0):
- return self.data.initiator_revoke(init_id, vol_id, flags)
-
- def volumes_accessible_by_initiator(self, init_id, flags=0):
- sim_vols = self.data.volumes_accessible_by_initiator(init_id, flags)
- return [SimArray._sim_vol_2_lsm(v) for v in sim_vols]
-
- def initiators_granted_to_volume(self, vol_id, flags=0):
- sim_inits = self.data.initiators_granted_to_volume(vol_id, flags)
- return [SimArray._sim_init_2_lsm(i) for i in sim_inits]
-
def iscsi_chap_auth(self, init_id, in_user, in_pass, out_user, out_pass,
flags=0):
return self.data.iscsi_chap_auth(init_id, in_user, in_pass, out_user,
@@ -453,16 +429,6 @@ class SimData(object):
}
}

- self.init_dict = {
- Initiator.id = sim_init,
- }
- sim_init = {
- 'init_id': Initiator.id,
- 'init_type': Initiator.TYPE_XXXX,
- 'name': SimData.SIM_DATA_INIT_NAME,
- 'sys_id': SimData.SIM_DATA_SYS_ID,
- }
-
self.ag_dict ={
AccessGroup.id = sim_ag,
}
@@ -536,7 +502,7 @@ class SimData(object):
}
"""
SIM_DATA_BLK_SIZE = 512
- SIM_DATA_VERSION = "2.3"
+ SIM_DATA_VERSION = "2.4"
SIM_DATA_SYS_ID = 'sim-01'
SIM_DATA_INIT_NAME = 'NULL'
SIM_DATA_TMO = 30000 # ms
@@ -869,6 +835,8 @@ class SimData(object):
return self.ag_dict.values()

def volume_create(self, pool_id, vol_name, size_bytes, thinp, flags=0):
+ self._check_dup_name(
+ self.vol_dict.values(), vol_name, ErrorNumber.EXISTS_VOLUME)
size_bytes = SimData._block_rounding(size_bytes)
# check free size
free_space = self.pool_free_space(pool_id)
@@ -1033,16 +1001,23 @@ class SimData(object):
def ags(self, flags=0):
return self.ag_dict.values()

+ def _check_dup_init(self, init_id):
+ 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'])
+ def _check_dup_name(self, sim_list, name, error_num):
+ used_names = [x['name'] for x in sim_list]
+ if name in used_names:
+ 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)
sim_ag = dict()
- if init_id not in self.init_dict.keys():
- sim_init = dict()
- sim_init['init_id'] = init_id
- sim_init['init_type'] = init_type
- sim_init['name'] = SimData.SIM_DATA_INIT_NAME
- sim_init['sys_id'] = SimData.SIM_DATA_SYS_ID
- self.init_dict[init_id] = sim_init
-
sim_ag['init_ids'] = [init_id]
sim_ag['init_type'] = init_type
sim_ag['sys_id'] = SimData.SIM_DATA_SYS_ID
@@ -1062,26 +1037,18 @@ class SimData(object):
if ag_id not in self.ag_dict.keys():
raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
"Access group not found")
- if init_id not in self.init_dict.keys():
- sim_init = dict()
- sim_init['init_id'] = init_id
- sim_init['init_type'] = init_type
- sim_init['name'] = SimData.SIM_DATA_INIT_NAME
- sim_init['sys_id'] = SimData.SIM_DATA_SYS_ID
- self.init_dict[init_id] = sim_init
if init_id in self.ag_dict[ag_id]['init_ids']:
- return self.ag_dict[ag_id]
+ return None

- self.ag_dict[ag_id]['init_ids'].extend([init_id])
+ self._check_dup_init(init_id)

+ self.ag_dict[ag_id]['init_ids'].extend([init_id])
return None

def access_group_initiator_delete(self, ag_id, init_id, flags=0):
if ag_id not in self.ag_dict.keys():
raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
"Access group not found: %s" % ag_id)
- if init_id not in self.init_dict.keys():
- return None

if init_id in self.ag_dict[ag_id]['init_ids']:
new_init_ids = []
@@ -1122,9 +1089,7 @@ class SimData(object):
return None

def volumes_accessible_by_access_group(self, ag_id, flags=0):
- if ag_id not in self.ag_dict.keys():
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "Access group not found: %s" % ag_id)
+ # We don't check wether ag_id is valid
rc = []
for sim_vol in self.vol_dict.values():
if 'mask' not in sim_vol:
@@ -1134,9 +1099,7 @@ class SimData(object):
return rc

def access_groups_granted_to_volume(self, vol_id, flags=0):
- if vol_id not in self.vol_dict.keys():
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
+ # We don't check wether vold_id is valid
sim_ags = []
if 'mask' in self.vol_dict[vol_id].keys():
ag_ids = self.vol_dict[vol_id]['mask'].keys()
@@ -1144,40 +1107,6 @@ class SimData(object):
sim_ags.extend([self.ag_dict[ag_id]])
return sim_ags

- def inits(self, flags=0):
- return self.init_dict.values()
-
- def initiator_grant(self, init_id, init_type, vol_id, access, flags):
- if vol_id not in self.vol_dict.keys():
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
- if init_id not in self.init_dict.keys():
- sim_init = dict()
- sim_init['init_id'] = init_id
- sim_init['init_type'] = init_type
- sim_init['name'] = SimData.SIM_DATA_INIT_NAME
- sim_init['sys_id'] = SimData.SIM_DATA_SYS_ID
- self.init_dict[init_id] = sim_init
- if 'mask_init' not in self.vol_dict[vol_id].keys():
- self.vol_dict[vol_id]['mask_init'] = dict()
-
- self.vol_dict[vol_id]['mask_init'][init_id] = access
- return None
-
- def initiator_revoke(self, init_id, vol_id, flags=0):
- if vol_id not in self.vol_dict.keys():
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
- if init_id not in self.init_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such Initiator: %s" % init_id)
-
- if 'mask_init' in self.vol_dict[vol_id].keys():
- if init_id in self.vol_dict[vol_id]['mask_init'].keys():
- del self.vol_dict[vol_id]['mask_init'][init_id]
-
- return None
-
def _ag_ids_of_init(self, init_id):
"""
Find out the access groups defined initiator belong to.
@@ -1189,44 +1118,9 @@ class SimData(object):
rc.extend([sim_ag['ag_id']])
return rc

- def volumes_accessible_by_initiator(self, init_id, flags=0):
- if init_id not in self.init_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such Initiator: %s" % init_id)
- rc_dedup_dict = dict()
- ag_ids = self._ag_ids_of_init(init_id)
- for ag_id in ag_ids:
- sim_vols = self.volumes_accessible_by_access_group(ag_id)
- for sim_vol in sim_vols:
- rc_dedup_dict[sim_vol['vol_id']] = sim_vol
-
- for sim_vol in self.vol_dict.values():
- if 'mask_init' in sim_vol:
- if init_id in sim_vol['mask_init'].keys():
- rc_dedup_dict[sim_vol['vol_id']] = sim_vol
- return rc_dedup_dict.values()
-
- def initiators_granted_to_volume(self, vol_id, flags=0):
- if vol_id not in self.vol_dict.keys():
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
- rc_dedup_dict = dict()
- sim_ags = self.access_groups_granted_to_volume(vol_id, flags)
- for sim_ag in sim_ags:
- for init_id in sim_ag['init_ids']:
- rc_dedup_dict[init_id] = self.init_dict[init_id]
-
- if 'mask_init' in self.vol_dict[vol_id].keys():
- for init_id in self.vol_dict[vol_id]['mask_init']:
- rc_dedup_dict[init_id] = self.init_dict[init_id]
-
- return rc_dedup_dict.values()
-
def iscsi_chap_auth(self, init_id, in_user, in_pass, out_user, out_pass,
flags=0):
- if init_id not in self.init_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such Initiator: %s" % init_id)
+ # to_code
if self.init_dict[init_id]['init_type'] != Initiator.TYPE_ISCSI:
raise LsmError(ErrorNumber.UNSUPPORTED_INITIATOR_TYPE,
"Initiator %s is not an iSCSI IQN" % init_id)
@@ -1280,8 +1174,8 @@ class SimData(object):

def fs_clone(self, src_fs_id, dst_fs_name, snap_id, flags=0):
if src_fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % src_fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % src_fs_id)
if snap_id and snap_id not in self.snap_dict.keys():
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
@@ -1297,8 +1191,8 @@ class SimData(object):

def fs_file_clone(self, fs_id, src_fs_name, dst_fs_name, snap_id, flags=0):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
if snap_id and snap_id not in self.snap_dict.keys():
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
@@ -1307,8 +1201,8 @@ class SimData(object):

def fs_snapshots(self, fs_id, flags=0):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
rc = []
if 'snaps' in self.fs_dict[fs_id].keys():
for snap_id in self.fs_dict[fs_id]['snaps']:
@@ -1317,8 +1211,8 @@ class SimData(object):

def fs_snapshot_create(self, fs_id, snap_name, files, flags=0):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
if 'snaps' not in self.fs_dict[fs_id].keys():
self.fs_dict[fs_id]['snaps'] = []

@@ -1337,8 +1231,8 @@ class SimData(object):

def fs_snapshot_delete(self, fs_id, snap_id, flags=0):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
if snap_id not in self.snap_dict.keys():
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
@@ -1353,8 +1247,8 @@ class SimData(object):
def fs_snapshot_restore(self, fs_id, snap_id, files, restore_files,
flag_all_files, flags):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
if snap_id not in self.snap_dict.keys():
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
@@ -1363,8 +1257,8 @@ class SimData(object):

def fs_child_dependency(self, fs_id, files, flags=0):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
if 'snaps' not in self.fs_dict[fs_id].keys():
return False
if files is None or len(files) == 0:
@@ -1382,8 +1276,8 @@ class SimData(object):

def fs_child_dependency_rm(self, fs_id, files, flags=0):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
if 'snaps' not in self.fs_dict[fs_id].keys():
return None
if files is None or len(files) == 0:
@@ -1431,8 +1325,8 @@ class SimData(object):
def fs_export(self, fs_id, exp_path, root_hosts, rw_hosts, ro_hosts,
anon_uid, anon_gid, auth_type, options, flags=0):
if fs_id not in self.fs_dict.keys():
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
sim_exp = dict()
sim_exp['exp_id'] = self._next_exp_id()
sim_exp['fs_id'] = fs_id
diff --git a/plugin/sim/simulator.py b/plugin/sim/simulator.py
index cb3f08a..b452b6a 100644
--- a/plugin/sim/simulator.py
+++ b/plugin/sim/simulator.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2013 Red Hat, Inc.
+# Copyright (C) 2011-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
@@ -14,6 +14,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Author: tasleson
+# Gris Ge <***@redhat.com>

from lsm import (uri_parse, VERSION, Capabilities, Pool, INfs,
IStorageAreaNetwork, Error, search_property)
@@ -218,31 +219,10 @@ class SimPlugin(INfs, IStorageAreaNetwork):
volume.id, flags)
return [SimPlugin._sim_data_2_lsm(v) for v in sim_vols]

- def initiators(self, flags=0):
- return self.sim_array.inits(flags)
-
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- flags=0):
- return self.sim_array.initiator_grant(
- initiator_id, initiator_type, volume.id, access, flags)
-
- def initiator_revoke(self, initiator, volume, flags=0):
- return self.sim_array.initiator_revoke(initiator.id, volume.id, flags)
-
- def volumes_accessible_by_initiator(self, initiator, flags=0):
- sim_vols = self.sim_array.volumes_accessible_by_initiator(
- initiator.id, flags)
- return [SimPlugin._sim_data_2_lsm(v) for v in sim_vols]
-
- def initiators_granted_to_volume(self, volume, flags=0):
- sim_inits = self.sim_array.initiators_granted_to_volume(
- volume.id, flags)
- return [SimPlugin._sim_data_2_lsm(i) for i in sim_inits]
-
- def iscsi_chap_auth(self, initiator, in_user, in_password,
+ def iscsi_chap_auth(self, init_id, in_user, in_password,
out_user, out_password, flags=0):
return self.sim_array.iscsi_chap_auth(
- initiator.id, in_user, in_password, out_user, out_password, flags)
+ init_id, in_user, in_password, out_user, out_password, flags)

def volume_child_dependency(self, volume, flags=0):
return self.sim_array.volume_child_dependency(volume.id, flags)
diff --git a/plugin/smispy/eseries.py b/plugin/smispy/eseries.py
index 8aa3d18..2160159 100644
--- a/plugin/smispy/eseries.py
+++ b/plugin/smispy/eseries.py
@@ -81,71 +81,6 @@ class ESeries(Smis):
#doesn't work
return cap

- def _get_initiators_in_group(self, cim_grp):
- ag_init_ids = []
- cim_st_hwid_pros = self._property_list_of_id('Initiator')
- cim_st_hwids = self._get_cim_st_hwid_in_spc(cim_grp, cim_st_hwid_pros)
- ag_init_ids = [self._init_id(i) for i in cim_st_hwids]
- return ag_init_ids
-
- def _get_group_initiator_is_in(self, initiator_id):
- groups = self._get_access_groups()
-
- for g in groups:
- initiators = self._get_initiators_in_group(g)
- for i in initiators:
- if i == initiator_id:
- return g
-
- return None
-
- @handle_cim_errors
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- flags=0):
- ccs = self._get_class_instance('CIM_ControllerConfigurationService')
- lun = self._get_cim_instance_by_id('Volume', volume.id)
-
- #Need to check for existence of initiator, else create one
- initiator = self._initiator_lookup(initiator_id)
-
- in_params = {'LUNames': [lun['DeviceID']],
- 'DeviceAccesses': [pywbem.Uint16(2)]}
-
- if initiator is not None:
- #In this case we need to find the access group that contains the
- #initiator and then pass the
- group = self._get_group_initiator_is_in(initiator_id)
-
- if group is None:
- raise LsmError(ErrorNumber.UNSUPPORTED_PROVISIONING,
- "Unsupported provisioning")
-
- in_params['ProtocolControllers'] = [group.path]
- else:
- in_params['InitiatorPortIDs'] = [initiator_id]
-
- #Returns None or job id
- return self._pi("initiator_grant", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('ExposePaths', ccs.path,
- **in_params)))[0]
-
- @handle_cim_errors
- def initiator_revoke(self, initiator, volume, flags=0):
- (found, spc) = self._get_spc(initiator.id, volume.id)
-
- if found:
- ccs = self._get_class_instance(
- 'CIM_ControllerConfigurationService')
-
- in_params = dict(ProtocolController=spc.path,
- DeleteChildrenProtocolControllers=True,
- DeleteUnits=True)
-
- #Returns None or job id
- return self._pi("access_revoke", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('DeleteProtocolController',
- ccs.path, **in_params)))[0]
-
def _detach(self, vol, sync):

#Get the Configuration service for the system we are interested in.
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a596ca5..6d10973 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -25,7 +25,7 @@ import pywbem
from pywbem import CIMError

from lsm import (IStorageAreaNetwork, Error, uri_parse, LsmError, ErrorNumber,
- JobStatus, md5, Pool, Initiator, Volume, AccessGroup, System,
+ JobStatus, md5, Pool, Volume, AccessGroup, System,
Capabilities, Disk, OptionalData, txt_a, VERSION,
search_property)

@@ -71,7 +71,7 @@ def handle_cim_errors(method):
if 'Errno 113' in desc:
raise LsmError(ErrorNumber.NETWORK_HOSTDOWN,
'Host is down')
- raise LsmError(ErrorNumber.PLUGIN_ERROR, desc)
+ raise LsmError(ErrorNumber.LSM_BUG, desc)
except pywbem.cim_http.AuthError as ae:
raise LsmError(ErrorNumber.PLUGIN_AUTH_FAILED, "Unauthorized user")
except pywbem.cim_http.Error as te:
@@ -100,13 +100,19 @@ def _spec_ver_str_to_num(spec_ver_str):
return None


+def _merge_list(list_a, list_b):
+ return list(set(list_a + list_b))
+
+
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)


_INIT_TYPE_CONV = {
@@ -116,6 +122,7 @@ _INIT_TYPE_CONV = {
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,
}


@@ -124,6 +131,8 @@ def _dmtf_init_type_to_lsm(cim_init):
return _INIT_TYPE_CONV[cim_init['IDType']]
return AccessGroup.INIT_TYPE_UNKNOWN

+def _lsm_init_type_to_dmtf(lsm_init_type):
+ return _get_key(_INIT_TYPE_CONV, lsm_init_type)

def _get_key(dictionary, value):
keys = [k for k, v in dictionary.items() if v == value]
@@ -433,111 +442,69 @@ class Smis(IStorageAreaNetwork):
self.cim_rps = []
self.cim_root_profile_dict = dict()
self.fallback_mode = True # Means we cannot use profile register
+ self.all_vendor_namespaces = []

def _get_cim_instance_by_id(self, class_type, requested_id,
- flag_full_info=True, property_list=None):
+ property_list=None, raise_error=True):
"""
Find out the CIM_XXXX Instance which holding the requested_id
- If flag_full_info == True, we return a Instance with full info.
- If you want to save some query time, try set it as False
+ Return None when error and raise_error is False
"""
class_name = Smis._cim_class_name_of(class_type)
- property_list = Smis._property_list_of_id(class_type, property_list)
+ error_numer = Smis._not_found_error_of_class(class_type)
+ id_pros = Smis._property_list_of_id(class_type, property_list)

- cim_xxxs = self._c.EnumerateInstances(class_name,
- PropertyList=property_list,
- LocalOnly=False)
+ if property_list is None:
+ property_list = id_pros
+ else:
+ property_list = _merge_list(property_list, id_pros)
+
+ cim_xxxs = self._enumerate(class_name, property_list)
org_requested_id = requested_id
if class_type == 'Job':
(requested_id, ignore) = self._parse_job_id(requested_id)
for cim_xxx in cim_xxxs:
if self._id(class_type, cim_xxx) == requested_id:
- if flag_full_info:
- cim_xxx = self._c.GetInstance(cim_xxx.path,
- LocalOnly=False)
return cim_xxx
+ if raise_error is False:
+ return None

- raise LsmError(ErrorNumber.INVALID_ARGUMENT,
+ raise LsmError(error_numer,
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))

- def _get_class_instance(self, class_name, prop_name=None, prop_value=None,
- no_throw_on_missing=False):
+ 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:
- if prop_name:
- instances = self._c.EnumerateInstances(
- class_name, PropertyList=[prop_name], LocalOnly=False)
- else:
- instances = self._c.EnumerateInstances(class_name,
- LocalOnly=False)
+ cim_xxxs = self._enumerate(class_name, property_list)
except CIMError as ce:
error_code = tuple(ce)[0]

- if error_code == pywbem.CIM_ERR_INVALID_CLASS \
- and no_throw_on_missing:
+ if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
+ raise_error is False:
return None
else:
raise ce

- if prop_name is None:
- if len(instances) != 1:
- class_names = " ".join([x.classname for x in instances])
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
- "Expecting one instance of %s and got %s" %
- (class_name, class_names))
-
- return instances[0]
- else:
- for i in instances:
- if prop_name in i and i[prop_name] == prop_value:
- return i
-
- if no_throw_on_missing:
- return None
+ for cim_xxx in cim_xxxs:
+ if prop_name in cim_xxx and cim_xxx[prop_name] == prop_value:
+ return cim_xxx

- raise LsmError(ErrorNumber.INVALID_ARGUMENT,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
-
- def _get_spc(self, initiator_id, volume_id):
- """
- Retrieve the SCSIProtocolController for a given initiator and volume.
- This will return a non-none value when there is a mapping between the
- initiator and the volume.
- """
- init = self._get_class_instance('CIM_StorageHardwareID', 'StorageID',
- initiator_id)
-
- # Look at page 151 (1.5 smi-s spec.) in the block services books for
- # the SNIA_MappingProtocolControllerView
-
- if init:
- auths = self._c.Associators(init.path,
- AssocClass='CIM_AuthorizedSubject')
-
- if auths:
- for a in auths:
- spc = self._c.Associators(
- a.path, AssocClass='CIM_AuthorizedTarget')
- if spc and len(spc) > 0:
- logical_device = \
- self._c.Associators(
- spc[0].path,
- AssocClass='CIM_ProtocolControllerForUnit')
-
- if logical_device and len(logical_device) > 0:
- vol = self._c.GetInstance(logical_device[0].path,
- LocalOnly=False)
- if 'DeviceID' in vol and \
- md5(vol.path) == volume_id:
- return spc[0]
+ if raise_error:
+ raise LsmError(ErrorNumber.LSM_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):
@@ -595,6 +562,7 @@ class Smis(IStorageAreaNetwork):
namespace = None
if 'namespace' in u['parameters']:
namespace = u['parameters']['namespace']
+ self.all_vendor_namespaces = [namespace]
else:
namespace = Smis.SMIS_DEFAULT_NAMESPACE

@@ -650,6 +618,7 @@ class Smis(IStorageAreaNetwork):

if len(self.cim_rps) >= 1:
self.fallback_mode = False
+ self.all_vendor_namespaces = []
# Support 'Array' profile is step 0 for this whole plugin.
# We find out all 'Array' CIM_RegisteredProfile and stored
# them into self.cim_root_profile_dict
@@ -658,7 +627,7 @@ class Smis(IStorageAreaNetwork):
SNIA.SMIS_SPEC_VER_1_4,
strict=False):
raise LsmError(ErrorNumber.NO_SUPPORT,
- "SMI-S provider does not support "
+ "Target SMI-S provider does not support "
"SNIA SMI-S SPEC %s '%s' profile" %
(SNIA.SMIS_SPEC_VER_1_4,
SNIA.BLK_ROOT_PROFILE))
@@ -725,7 +694,7 @@ class Smis(IStorageAreaNetwork):
Interrogate the supported features of the replication service
"""
rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, True)
+ system.id, raise_error=False)
if rs:
rs_cap = self._c.Associators(
rs.path,
@@ -758,7 +727,7 @@ class Smis(IStorageAreaNetwork):

rs = self._get_class_instance("CIM_StorageConfigurationService",
'SystemName',
- system.id, True)
+ system.id, raise_error=False)

if rs:
rs_cap = self._c.Associators(
@@ -796,7 +765,7 @@ class Smis(IStorageAreaNetwork):
# Get the cim object that represents the system
cim_sys = None
cim_pcms = None
- cim_sys = self._cim_sys_of_id(system.id)
+ cim_sys = self._get_cim_instance_by_id('System', system.id)
if self.fallback_mode:

# Using 'ExposePathsSupported of
@@ -840,7 +809,6 @@ class Smis(IStorageAreaNetwork):

# Assume that the SMI-S we are talking to supports blocks
cap.set(Capabilities.BLOCK_SUPPORT)
- cap.set(Capabilities.INITIATORS)

self._scs_supported_capabilities(system, cap)
self._rs_supported_capabilities(system, cap)
@@ -885,8 +853,7 @@ class Smis(IStorageAreaNetwork):
'OperationalStatus']
cim_job_pros = self._property_list_of_id('Job', props)

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

job_state = cim_job['JobState']

@@ -934,12 +901,33 @@ class Smis(IStorageAreaNetwork):
return 'CIM_SCSIProtocolController'
if class_type == 'Initiator':
return 'CIM_StorageHardwareID'
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Smis._cim_class_name_of() got unknown " +
"class_type %s" % class_type)

@staticmethod
- def _property_list_of_id(class_type, requested_properties=None):
+ def _not_found_error_of_class(class_type):
+ if class_type == 'Volume':
+ return ErrorNumber.NOT_FOUND_VOLUME
+ if class_type == 'System':
+ return ErrorNumber.NOT_FOUND_SYSTEM
+ if class_type == 'Pool':
+ return ErrorNumber.NOT_FOUND_POOL
+ if class_type == 'Disk':
+ return ErrorNumber.NOT_FOUND_DISK
+ if class_type == 'Job':
+ return ErrorNumber.NOT_FOUND_JOB
+ if class_type == 'AccessGroup':
+ return ErrorNumber.NOT_FOUND_ACCESS_GROUP
+ if class_type == 'Initiator':
+ return ErrorNumber.INVALID_ARGUMENT
+ raise LsmError(ErrorNumber.LSM_BUG,
+ "Smis._cim_class_name_of() got unknown " +
+ "class_type %s" % class_type)
+
+
+ @staticmethod
+ def _property_list_of_id(class_type, extra_properties=None):
"""
Return a PropertyList which the ID of current class is basing on
"""
@@ -961,14 +949,12 @@ class Smis(IStorageAreaNetwork):
elif class_type == 'Initiator':
rc = ['StorageID']
else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Smis._cim_class_name_of() got unknown " +
"class_type %s" % class_type)

- if requested_properties:
- for p in requested_properties:
- if p not in rc:
- rc.extend([p])
+ if extra_properties:
+ rc = _merge_list(rc, extra_properties)
return rc

def _sys_id_child(self, cim_xxx):
@@ -1289,7 +1275,7 @@ class Smis(IStorageAreaNetwork):
PropertyList=pool_pros, LocalOnly=False)
return self._new_pool(cim_new_pool)
else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Got not new Pool from out of InvokeMethod" +
"when CreateOrModifyElementFromStoragePool")

@@ -1399,72 +1385,16 @@ class Smis(IStorageAreaNetwork):
rc.extend([vol])
return search_property(rc, search_key, search_value)

- def _systems(self, system_name=None):
- """
- Returns a list of system objects (CIM)
- """
- cim_syss = []
- cim_scss_path = []
- try:
- # Note: Please be informed, if PropertyList is an empty list,
- # XIV will return NOTHING, so use EnumerateInstanceNames()
- # when you need nothing but the CIMInstanceName
- cim_scss_path = \
- self._c.EnumerateInstanceNames(
- 'CIM_StorageConfigurationService')
- except CIMError as e:
- # If array does not support CIM_StorageConfigurationService
- # we use CIM_ComputerSystem which is mandatory.
- # We might get some non-storage array listed as system.
- # but we would like to take that risk instead of
- # skipping basic support of old SMIS provider.
- if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
- cim_syss = self._c.EnumerateInstances(
- 'CIM_ComputerSystem',
- PropertyList=['Name', 'ElementName', 'OperationalStatus'],
- LocalOnly=False)
- else:
- raise e
- if not cim_syss:
- for cim_scs_path in cim_scss_path:
- cim_tmp = \
- self._c.Associators(cim_scs_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ComputerSystem',
- PropertyList=['Name',
- 'ElementName',
- 'OperationalStatus'])
- if cim_tmp and cim_tmp[0]:
- cim_syss.extend([cim_tmp[0]])
-
- # Filtering
- if system_name is not None:
- for cim_sys in cim_syss:
- if cim_sys['Name'] == system_name:
- return [cim_sys]
-
- elif self.system_list:
- cim_filterd_syss = []
- for cim_sys in cim_syss:
- if cim_sys['Name'] in self.system_list:
- cim_filterd_syss.extend([cim_sys])
- return cim_filterd_syss
- else:
- return cim_syss
-
def _cim_pools_of(self, cim_sys_path, property_list=None):
- pros = []
if property_list is None:
- pros = ['Primordial']
+ property_list = ['Primordial']
else:
- pros = property_list
- if 'Primordial' not in pros:
- pros.extend(['Primordial'])
+ property_list = _merge_list(property_list, ['Primordial'])

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

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

@@ -1540,7 +1470,7 @@ class Smis(IStorageAreaNetwork):
for key, value in opt_pro_dict.items():
pool.optional_data.set(key, value)
else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Failed to retrieve pool information " +
"from CIM_StoragePool: %s" % cim_pool.path)
return search_property(rc, search_key, search_value)
@@ -1631,61 +1561,6 @@ class Smis(IStorageAreaNetwork):

return [Smis._cim_sys_2_lsm_sys(s) for s in cim_syss]

- def _new_init(self, cim_init):
- """
- Generate Initiator object from CIM_StorageHardwareID
- """
- init_id = self._init_id(cim_init)
- init_type = cim_init['IDType']
- init_name = cim_init['ElementName']
- return Initiator(init_id, init_type, init_name)
-
- def _new_init_pros(self):
- """
- Return a list of properties needed to created Initiator from
- CIM_StorageHardwareID
- """
- cim_init_pros = self._property_list_of_id('Initiator',
- ['IDType', 'ElementName'])
- return cim_init_pros
-
- @handle_cim_errors
- def initiators(self, flags=0):
- """
- Return all initiators generated from CIM_StorageHardwareID.
- Following SNIA SMI-S 'Masking and Mapping Profile':
- CIM_ComputerSystem
- | (CIM_HostedService)
- v
- CIM_StorageHardwareIDManagementService
- | (CIM_ConcreteDependency)
- v
- CIM_StorageHardwareID
- This is supported from SNIA SMI-S 1.3rev6 to latest(1.6rev4).
- """
- rc_inits = []
- cim_init_pros = self._new_init_pros()
- try:
- for cim_sys in self._systems():
- cim_init_mss_path = self._c.AssociatorNames(
- cim_sys.path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_StorageHardwareIDManagementService')
- for cim_init_ms_path in cim_init_mss_path:
- cim_inits = self._c.Associators(
- cim_init_ms_path,
- AssocClass='CIM_ConcreteDependency',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=cim_init_pros)
- rc_inits.extend([self._new_init(i) for i in cim_inits])
- 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:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- 'Initiator is not supported by this array')
- return rc_inits
-
@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
flags=0):
@@ -1699,7 +1574,7 @@ class Smis(IStorageAreaNetwork):
# Get the Configuration service for the system we are interested in.
scs = self._get_class_instance('CIM_StorageConfigurationService',
'SystemName', pool.system_id)
- sp = self._get_cim_instance_by_id('Pool', pool.id, False)
+ sp = self._get_cim_instance_by_id('Pool', pool.id)

in_params = {'ElementName': volume_name,
'ElementType': pywbem.Uint16(2),
@@ -1728,7 +1603,7 @@ class Smis(IStorageAreaNetwork):

def _detach(self, vol, sync):
rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- vol.system_id, True)
+ vol.system_id, raise_error=False)

if rs:
in_params = {'Operation': pywbem.Uint16(8),
@@ -1845,7 +1720,7 @@ class Smis(IStorageAreaNetwork):
rc = [None, None]

rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system_id, True)
+ system_id, raise_error=False)

if rs:
rs_cap = self._c.Associators(
@@ -1901,7 +1776,7 @@ class Smis(IStorageAreaNetwork):
volume_src.system_id, True)

if pool is not None:
- cim_pool = self._get_cim_instance_by_id('Pool', pool.id, False)
+ cim_pool = self._get_cim_instance_by_id('Pool', pool.id)
else:
cim_pool = None

@@ -1928,7 +1803,7 @@ class Smis(IStorageAreaNetwork):
# Check for storage configuration service
rs = self._get_class_instance("CIM_StorageConfigurationService",
'SystemName', volume_src.system_id,
- True)
+ raise_error=False)

ct = Volume.REPLICATE_CLONE
if rep_type == Volume.REPLICATE_CLONE:
@@ -1963,35 +1838,15 @@ class Smis(IStorageAreaNetwork):
def volume_offline(self, volume, flags=0):
return None

- def _initiator_create(self, name, init_id, id_type):
- """
- Create initiator object
- """
- hardware = self._get_class_instance(
- 'CIM_StorageHardwareIDManagementService')
-
- in_params = {'ElementName': name,
- 'StorageID': init_id,
- 'IDType': pywbem.Uint16(id_type)}
-
- (rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- hardware.path, **in_params)
- if not rc:
- init = self._get_class_instance('CIM_StorageHardwareID',
- 'StorageID', init_id)
- return self._new_init(init)
-
- raise LsmError(ErrorNumber.PLUGIN_ERROR, 'Error: ' + str(rc) +
- ' on initiator_create!')
-
@handle_cim_errors
def volume_mask(self, access_group, volume, flags=0):
"""
Grant access to a volume to an group
"""
- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', access_group.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)
+ lun = self._get_cim_instance_by_id('Volume', volume.id, ['Name'])
spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)

if not lun:
@@ -2009,7 +1864,7 @@ class Smis(IStorageAreaNetwork):

# Returns None or job id
return self._pi("access_grant", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('ExposePaths', ccs.path,
+ *(self._c.InvokeMethod('ExposePaths', cim_ccs.path,
**in_params)))[0]

def _wait(self, job):
@@ -2026,9 +1881,10 @@ class Smis(IStorageAreaNetwork):

@handle_cim_errors
def volume_unmask(self, access_group, volume, flags=0):
- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)
+ lun = self._get_cim_instance_by_id('Volume', volume.id, ['Name'])
spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)

if not lun:
@@ -2041,7 +1897,7 @@ class Smis(IStorageAreaNetwork):
hide_params = {'LUNames': [lun['Name']],
'ProtocolControllers': [spc.path]}
return self._pi("HidePaths", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('HidePaths', ccs.path,
+ *(self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)))[0]

def _is_access_group(self, cim_ag):
@@ -2096,7 +1952,7 @@ class Smis(IStorageAreaNetwork):
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Got %d instance of " % len(cim_ccss_path) +
"ControllerConfigurationService from %s" %
cim_sys.path + " in _cim_ags_of()")
@@ -2220,55 +2076,91 @@ class Smis(IStorageAreaNetwork):

return search_property(rc, search_key, search_value)

- def _initiator_lookup(self, initiator_id):
+ def _initiator_create(self, cim_sys_path, init_id, dmtf_id_type):
"""
- Looks up an initiator by initiator id
- returns None or object instance
+ Create a CIM_StorageHardwareID.
+ Raise error if failed. Return if pass.
"""
- initiator = None
- for i in self.initiators():
- if i.id == initiator_id:
- initiator = i
- break
- return initiator
+ cim_hw_srvs = self._c.AssociatorNames(
+ cim_sys_path,
+ ResultClass='CIM_StorageHardwareIDManagementService',
+ AssocClass='CIM_HostedService')
+ if len(cim_hw_srvs) == 0:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support "
+ "access_group_initiator_add(): No "
+ "CIM_StorageHardwareIDManagementService to create"
+ "new initiator")
+ if len(cim_hw_srvs) != 1:
+ raise LsmError(ErrorNumber.LSM_BUG,
+ "_initiator_create(): Got more than one "
+ "CIM_StorageHardwareIDManagementService")
+
+ in_params = {#'ElementName': init_id,
+ 'StorageID': init_id,
+ 'IDType': pywbem.Uint16(dmtf_id_type)}
+ print in_params
+
+ (rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
+ cim_hw_srvs[0], **in_params)
+ if not rc:
+ return
+
+ # Ideally, we should handle CIM Error here in stead of raise
+ # LSM_BUG error. Let's wait user report on bug.
+ raise LsmError(ErrorNumber.LSM_BUG,
+ 'Error on _initiator_create(): rc: "%s", out: "%s"'
+ % (str(rc), out))

@handle_cim_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
flags=0):
- # Check to see if we have this initiator already, if we don't create
- # it and then add to the view.
-
- spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)
+ # CIM_StorageHardwareIDManagementService.CreateStorageHardwareID()
+ # is mandatory since 1.4rev6
+ if not self.fallback_mode:
+ self._profile_is_supported(SNIA.MASK_PROFILE,
+ SNIA.SMIS_SPEC_VER_1_4,
+ strict=False,
+ raise_error=True)

- # This need rework when removing lsm.Initiator class
- initiator = self._initiator_lookup(init_id)
- lsm_init_type = _lsm_init_type_to_dmtf(init_type)
+ cim_sys = self._get_cim_instance_by_id('System',
+ access_group.system_id)

- if not initiator:
- initiator = self._initiator_create(init_id, init_id,
- lsm_init_type)
+ # Check to see if we have this initiator already, if we don't create
+ # it and then add to the view.
+ if self._get_cim_instance_by_id(
+ 'Initiator', init_id, raise_error=False) is None:
+ dmtf_id_type = _lsm_init_type_to_dmtf(init_type)
+ if dmtf_id_type is None:
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S Plugin does not support init_type %d"
+ % init_type)
+ self._initiator_create(cim_sys.path, init_id, dmtf_id_type)

- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', access_group.system_id)
+ cim_ag = self._get_cim_instance_by_id('AccessGroup', access_group.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)

- in_params = {'InitiatorPortIDs': [initiator.id],
- 'ProtocolControllers': [spc.path]}
+ in_params = {'InitiatorPortIDs': [init_id],
+ 'ProtocolControllers': [cim_ag.path]}

# Returns None or job id
return self._pi("access_group_initiator_add", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('ExposePaths', ccs.path,
+ *(self._c.InvokeMethod('ExposePaths', cim_ccs.path,
**in_params)))[0]

@handle_cim_errors
def access_group_initiator_delete(self, access_group, init_id, flags=0):
- spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)
- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', access_group.system_id)
+ cim_ag = self._get_cim_instance_by_id('AccessGroup', access_group.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)

hide_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [spc.path]}
+ 'ProtocolControllers': [cim_ag.path]}
return self._pi("HidePaths", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('HidePaths', ccs.path,
+ *(self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)))[0]

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

# See if we should delete the job
if not cim_job['DeleteOnCompletion']:
@@ -2285,6 +2178,30 @@ class Smis(IStorageAreaNetwork):
except CIMError:
pass

+ def _enumerate(self, class_name, property_list):
+ """
+ Please do the filter of "sytems=" in URI by yourself.
+ """
+ if len(self.all_vendor_namespaces) == 0:
+ # We need to find out the vendor spaces.
+ # We do it here to save plugin_register() time.
+ # Only non-fallback mode can goes there.
+ cim_syss = self._root_cim_syss()
+ all_vendor_namespaces = []
+ for cim_sys in cim_syss:
+ if cim_sys.path.namespace not in all_vendor_namespaces:
+ all_vendor_namespaces.extend([cim_sys.path.namespace])
+ self.all_vendor_namespaces = all_vendor_namespaces
+ rc = []
+ for vendor_namespace in self.all_vendor_namespaces:
+ rc.extend(
+ self._c.EnumerateInstances(
+ class_name,
+ namespace=vendor_namespace,
+ PropertyList=property_list,
+ LocalOnly=False))
+ return rc
+
@handle_cim_errors
def disks(self, search_key=None, search_value=None, flags=0):
"""
@@ -2300,37 +2217,22 @@ class Smis(IStorageAreaNetwork):
by ourself in case URI contain 'system=xxx'.
"""
rc = []
- cim_sys_pros = self._property_list_of_id("System")
if not self.fallback_mode:
self._profile_is_supported(SNIA.DISK_LITE_PROFILE,
SNIA.SMIS_SPEC_VER_1_4,
strict=False,
raise_error=True)
- cim_syss = self._root_cim_syss(cim_sys_pros)
-
- if len(cim_syss) < 1:
- return []
-
- all_vendor_namespaces = []
- for cim_sys in cim_syss:
- if cim_sys.path.namespace not in all_vendor_namespaces:
- all_vendor_namespaces.extend([cim_sys.path.namespace])
-
cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
- for vendor_namespace in all_vendor_namespaces:
- cim_disks = self._c.EnumerateInstances(
- 'CIM_DiskDrive',
- namespace=vendor_namespace,
- PropertyList=cim_disk_pros)
- for cim_disk in cim_disks:
- if self.system_list:
- if self._sys_id_child(cim_disk) not in self.system_list:
- continue
- cim_ext_pros = Smis._new_disk_cim_ext_pros(flags)
- cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path,
- cim_ext_pros)
-
- rc.extend([self._new_disk(cim_disk, cim_ext, flags)])
+ cim_disks = self._enumerate('CIM_DiskDrive', cim_disk_pros)
+ for cim_disk in cim_disks:
+ if self.system_list:
+ if self._sys_id_child(cim_disk) not in self.system_list:
+ continue
+ cim_ext_pros = Smis._new_disk_cim_ext_pros(flags)
+ cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path,
+ cim_ext_pros)
+
+ rc.extend([self._new_disk(cim_disk, cim_ext, flags)])
return search_property(rc, search_key, search_value)

@staticmethod
@@ -2459,7 +2361,7 @@ class Smis(IStorageAreaNetwork):
ResultClass='CIM_PhysicalPackage',
PropertyList=cim_phy_pkg_pros)
if not (cim_phy_pkgs and cim_phy_pkgs[0]):
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Failed to find out the CIM_PhysicalPackage " +
"of CIM_DiskDrive %s" % cim_disk.path)
cim_phy_pkg = cim_phy_pkgs[0]
@@ -2478,7 +2380,7 @@ class Smis(IStorageAreaNetwork):
status_info,
cim_disk['ErrorDescription'])
else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"CIM_DiskDrive %s " % cim_disk.id +
"has ErrorCleared == False but " +
"does not have " +
@@ -2511,13 +2413,12 @@ class Smis(IStorageAreaNetwork):
cim_pri_ext # The CIM_Instance of Primordial CIM_StorageExtent
Exceptions:
LsmError
- ErrorNumber.INTERNAL_ERROR # Failed to find out pri cim_ext
+ ErrorNumber.LSM_BUG # Failed to find out pri cim_ext
"""
if property_list is None:
property_list = ['Primordial']
else:
- if 'Primordial' not in property_list:
- property_list.extend(['Primordial'])
+ property_list = _merge_list(property_list, ['Primordial'])

cim_exts = self._c.Associators(
cim_disk_path,
@@ -2530,7 +2431,7 @@ class Smis(IStorageAreaNetwork):
# each CIM_DiskDrive
return cim_exts[0]
else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Failed to find out Primordial " +
"CIM_StorageExtent for CIM_DiskDrive %s " %
cim_disk_path)
@@ -2748,7 +2649,7 @@ class Smis(IStorageAreaNetwork):
elif len(cim_disks) == 2:
return None
else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Found two or more CIM_DiskDrive associated to " +
"requested CIM_StorageExtent %s" %
cim_pri_ext_path)
@@ -2990,7 +2891,6 @@ class Smis(IStorageAreaNetwork):
"""
Delete a Pool via CIM_StorageConfigurationService.DeleteStoragePool
"""
- cim_sys_pros = self._property_list_of_id("System")
if not self.fallback_mode and \
self._profile_is_supported(SNIA.BLK_SRVS_PROFILE,
SNIA.SMIS_SPEC_VER_1_4,
@@ -3000,9 +2900,10 @@ class Smis(IStorageAreaNetwork):
(SNIA.BLK_SRVS_PROFILE,
SNIA.SMIS_SPEC_VER_1_4))

- cim_sys = self._cim_sys_of_id(pool.system_id)
- cim_pool = self._get_cim_pool_by_id(cim_sys.path, pool.id)
- cim_scs = self._get_cim_scs(cim_sys.path)
+ cim_pool = self._get_cim_instance_by_id('Pool', pool.id)
+ cim_scs = self._get_class_instance(
+ 'CIM_StorageConfigurationService',
+ 'SystemName', pool.system_id)

in_params = {'Pool': cim_pool.path}

@@ -3031,7 +2932,7 @@ class Smis(IStorageAreaNetwork):
(SNIA.BLK_SRVS_PROFILE,
SNIA.SMIS_SPEC_VER_1_4))

- cim_sys = self._cim_sys_of_id(system.id)
+ cim_sys = self._get_cim_instance_by_id('System', system.id)

# we does not support defining thinp_type yet.
# just using whatever provider set.
@@ -3082,7 +2983,9 @@ class Smis(IStorageAreaNetwork):
in_params['Goal'] = self._cim_st_path_for_goal(
raid_type, cim_sys.path)

- cim_scs = self._get_cim_scs(cim_sys.path)
+ cim_scs = self._get_class_instance(
+ 'CIM_StorageConfigurationService',
+ 'SystemName', system.id)

in_params = self._pool_chg_paras_check(in_params, cim_sys.path)
return self._pi("pool_create", Smis.JOB_RETRIEVE_POOL,
@@ -3091,46 +2994,6 @@ class Smis(IStorageAreaNetwork):
cim_scs.path, **in_params)))

@handle_cim_errors
- def _pri_cim_ext_of_disk_ids(self, disk_ids):
- """
- Usage:
- Find out the Primordial CIM_StorageSetting of Disk.
- Parameter:
- disk_ids # a list of Disk.id
- Returns:
- [a , b] # a list of items.
- or
- [] # disk_ids is NULL
- Exception:
- LsmError
- ErrorNumber.INVALID_DISK # Disk ID invalid.
- ErrorNumber.INVALID_DISK # No Disk found.
- """
- if len(disk_ids) == 0:
- return []
- cim_disks = self._c.EnumerateInstances('CIM_DiskDrive',
- PropertyList=['SystemName',
- 'DeviceID'],
- LocalOnly=False)
- if len(cim_disks) == 0:
- raise LsmError(ErrorNumber.INVALID_DISK, "No disk found")
-
- disk_id_2_cim = {}
- for cim_disk in cim_disks:
- disk_id_2_cim[self._disk_id(cim_disk)] = cim_disk
-
- cim_pri_exts = []
- for disk_id in disk_ids:
- if disk_id in disk_id_2_cim.keys():
- cim_disk = disk_id_2_cim[disk_id]
- cim_pri_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path)
- cim_pri_exts.extend([cim_pri_ext])
- else:
- raise LsmError(ErrorNumber.INVALID_DISK,
- "Disk with ID %s cannot be found\n" % disk_id)
- return cim_pri_exts
-
- @handle_cim_errors
def _find_preset_cim_st(self, cim_cap_path, raid_type):
"""
Usage:
@@ -3324,37 +3187,6 @@ class Smis(IStorageAreaNetwork):
"type or add different RAID type tier")
return new_in_params

- def _get_cim_scs(self, cim_sys_path, property_list=None):
- """
- Usage:
- Find out the CIM_StorageConfigurationService base on
- CIM_ComputerSystem
- Base on SNIA SMI-S 1.6rev4, Block book, Clause 5: Block Services
- Package, Figure 8 - StoragePool Manipulation Instance Diagram
- This is only one CIM_StorageConfigurationService associated to
- CIM_ComputerSystem
- Parameter:
- cim_sys_path # CIMInstanceName of CIM_ComputerSystem
- property_list # the list of properties required in return
- # CIMInstance
- Returns:
- cim_scs
- """
- pros = []
- if property_list is not None:
- pros = property_list
- cim_scss = self._c.Associators(
- cim_sys_path,
- ResultClass='CIM_StorageConfigurationService',
- PropertyList=pros)
- if cim_scss and len(cim_scss) >= 0:
- return cim_scss[0]
- else:
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
- "Failed to find out " +
- "CIM_StorageConfigurationService of " +
- "CIM_ComputerSystem %s" % cim_sys_path)
-
def _profile_is_supported(self, profile_name, spec_ver, strict=False,
raise_error=False):
"""
@@ -3426,7 +3258,11 @@ class Smis(IStorageAreaNetwork):
this is assumption should work. Tested on EMC SMI-S provider which
provide 1.4, 1.5, 1.6 root profile.
"""
- property_list = self._property_list_of_id('System', property_list)
+ id_pros = self._property_list_of_id('System', property_list)
+ if property_list is None:
+ property_list = id_pros
+ else:
+ property_list = _merge_list(property_list, id_pros)

cim_syss = []
if self.fallback_mode:
@@ -3497,29 +3333,3 @@ class Smis(IStorageAreaNetwork):
return needed_cim_syss
else:
return cim_syss
-
- def _cim_sys_of_id(self, system_id, property_list=None):
- """
- Return a CIMInstance of CIM_ComputerSystem for given system id.
- """
- property_list = self._property_list_of_id("System", property_list)
- cim_syss = self._root_cim_syss(property_list)
-
- for cim_sys in cim_syss:
- if self._sys_id(cim_sys) == system_id:
- return cim_sys
- raise LsmError(ErrorNumber.NOT_FOUND_SYSTEM,
- "System %s not found" % system_id)
-
- def _get_cim_pool_by_id(self, cim_sys_path, pool_id, property_list=None):
- """
- Return a CIMInstance of CIM_StoragePool for given pool id.
- """
- property_list = self._property_list_of_id("Pool", property_list)
- cim_pools = self._cim_pools_of(cim_sys_path, property_list)
- for cim_pool in cim_pools:
- if self._pool_id(cim_pool) == pool_id:
- return cim_pool
-
- raise LsmError(ErrorNumber.NOT_FOUND_POOL,
- "System %s not found" % pool_id)
diff --git a/plugin/targetd/targetd.py b/plugin/targetd/targetd.py
index a996d95..ed4c945 100644
--- a/plugin/targetd/targetd.py
+++ b/plugin/targetd/targetd.py
@@ -20,7 +20,7 @@

import copy

-from lsm import (Pool, Volume, System, Capabilities, Initiator,
+from lsm import (Pool, Volume, System, Capabilities,
IStorageAreaNetwork, INfs, FileSystem, FsSnapshot, NfsExport,
LsmError, ErrorNumber, uri_parse, md5, VERSION,
common_urllib2_error_handler, search_property,
@@ -260,15 +260,6 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
lsm_ags = self.access_groups(flags=flags)
return [x for x in lsm_ags if x.id in ag_ids]

- @handle_errors
- def initiators(self, flags=0):
- inits = []
- for init in set(i['initiator_wwn']
- for i in self._jsonrequest("export_list")):
- inits.append(Initiator(init, Initiator.TYPE_ISCSI, init))
-
- return inits
-
def _get_volume(self, pool_id, volume_name):
vol = [v for v in self._jsonrequest("vol_list", dict(pool=pool_id))
if v['name'] == volume_name][0]
@@ -336,10 +327,10 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
return not self.volume_online(volume)

@handle_errors
- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
out_password, flags=0):
self._jsonrequest("initiator_set_auth",
- dict(initiator_wwn=initiator.id,
+ dict(initiator_wwn=init_id,
in_user=in_user,
in_pass=in_password,
out_user=out_user,
@@ -348,60 +339,6 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
return None

@handle_errors
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- flags=0):
- if initiator_type != Initiator.TYPE_ISCSI:
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
- # find lowest unused lun and use that
- used_luns = [x['lun'] for x in self._jsonrequest("export_list")]
- lun = 0
- while True:
- if lun in used_luns:
- lun += 1
- else:
- break
-
- self._jsonrequest("export_create",
- dict(pool=volume.pool_id,
- vol=volume.name,
- initiator_wwn=initiator_id, lun=lun))
-
- @handle_errors
- def initiator_revoke(self, initiator, volume, flags=0):
- self._jsonrequest("export_destroy",
- dict(pool=volume.pool_id,
- vol=volume.name,
- initiator_wwn=initiator.id))
-
- @handle_errors
- def volumes_accessible_by_initiator(self, initiator, flags=0):
- exports = [x for x in self._jsonrequest("export_list")
- if initiator.id == x['initiator_wwn']]
-
- vols = []
- for export in exports:
- vols.append(Volume(export['vol_uuid'], export['vol_name'],
- export['vol_uuid'], 512,
- export['vol_size'] / 512,
- Volume.STATUS_OK, self.system.id,
- export['pool']))
-
- return vols
-
- @handle_errors
- def initiators_granted_to_volume(self, volume, flags=0):
- exports = [x for x in self._jsonrequest("export_list")
- if volume.id == x['vol_uuid']]
-
- inits = []
- for export in exports:
- name = export['initiator_wwn']
- inits.append(Initiator(name, Initiator.TYPE_ISCSI, name))
-
- return inits
-
- @handle_errors
def fs(self, search_key=None, search_value=None, flags=0):
rc = []
for fs in self._jsonrequest("fs_list"):
diff --git a/plugin/v7k/ibmv7k.py b/plugin/v7k/ibmv7k.py
index bfe17ef..de63a99 100644
--- a/plugin/v7k/ibmv7k.py
+++ b/plugin/v7k/ibmv7k.py
@@ -17,7 +17,7 @@

import paramiko

-from lsm import (Capabilities, ErrorNumber, IStorageAreaNetwork, Initiator,
+from lsm import (Capabilities, ErrorNumber, IStorageAreaNetwork,
LsmError, Pool, System, VERSION, Volume, uri_parse,
search_property, AccessGroup)

@@ -278,102 +278,6 @@ class IbmV7k(IStorageAreaNetwork):

return Initiator(lsm_init_id, lsm_init_type, v7k_init['name'])

- def _map_lsm_init_id_to_v7k(self, lsm_init_id):
- gi = self._get_initiators()
-
- v7k_init_id = None
- for i in gi.itervalues():
- v7kinit = self._get_initiator(i['id'])
- if 'WWPN' in v7kinit and v7kinit['WWPN'] == lsm_init_id:
- v7k_init_id = v7kinit['id']
-
- if 'iscsi_name' in v7kinit and v7kinit['iscsi_name'] == \
- lsm_init_id:
- v7k_init_id = v7kinit['id']
-
- if not v7k_init_id:
- raise LsmError(ErrorNumber.NOT_FOUND_INITIATOR,
- "Initiator not found")
-
- return v7k_init_id
-
- def _get_volumes_accessible_by_initiator(self, init_id):
- # init_id passed is the lsm's init id. Convert it to v7k id.
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
-
- ssh_cmd = 'lshostvdiskmap -delim ! %s' % v7k_init_id
- return self._execute_command_and_parse_concise(ssh_cmd)
-
- def _get_initiators_granted_to_volume(self, v):
- ssh_cmd = 'lsvdiskhostmap -delim ! %s' % v
- return self._execute_command_and_parse_concise(ssh_cmd)
-
- def _initiator_create(self, init_id, init_type):
- if init_type == Initiator.TYPE_PORT_WWN:
- type_option = '-hbawwpn'
- elif init_type == Initiator.TYPE_ISCSI:
- type_option = '-iscsiname'
- else:
- raise LsmError(ErrorNumber.UNSUPPORTED_INITIATOR_TYPE,
- "Initiator type not supported")
-
- ssh_cmd = 'mkhost %s %s' % (type_option, init_id)
- return self._execute_command(ssh_cmd)
-
- def _initiator_create_is_success(self, stdout):
- if 'successfully created' in stdout:
- return True
- return False
-
- def _initiator_grant(self, init_id, init_type, vol_id, force):
- # init_id passed is the lsm's init id. Convert it to v7k id.
- try:
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
- except LsmError as le:
- if le.code == ErrorNumber.NOT_FOUND_INITIATOR:
- # Auto add the initiator
- exit_code, stdout, stderr = self._initiator_create(init_id,
- init_type)
- if self._initiator_create_is_success(stdout):
- # If success, get the v7k id for the new init
- # This should not cause an exception this time!
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
- else:
- raise LsmError(ErrorNumber.PLUGIN_ERROR,
- "Error creating initiator")
- else:
- raise le
-
- ssh_cmd = 'mkvdiskhostmap %s -host %s %s' % \
- ('-force' if force else '', v7k_init_id, vol_id)
- return self._execute_command(ssh_cmd)
-
- def _initiator_grant_is_success(self, stdout):
- if 'successfully created' in stdout:
- return True
- return False
-
- def _initiator_delete(self, v7k_init_id, force=True):
- ssh_cmd = 'rmhost %s %s' % ('-force' if force else '', v7k_init_id)
- self._execute_command(ssh_cmd)
-
- def _initiator_revoke(self, init_id, vol_id):
- # init_id passed is the lsm's init id. Convert it to v7k id.
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
-
- ssh_cmd = 'rmvdiskhostmap -host %s %s' % (v7k_init_id, vol_id)
- self._execute_command(ssh_cmd)
-
- # Auto remove initiator (if no mapping present)
- # v7k rmhost raises exception, if host is being removed with mappings
- # present... unless -force is specified. So exploit that fact here.
- try:
- self._initiator_delete(v7k_init_id, force=False)
- except LsmError:
- pass
-
- return
-
def plugin_register(self, uri, password, timeout, flags=0):
self.password = password
self.tmo = timeout
@@ -440,14 +344,6 @@ class IbmV7k(IStorageAreaNetwork):
[self._volume(v) for v in gv.itervalues()],
search_key, search_value)

- def initiators(self, flags=0):
- init_list = []
- gi = self._get_initiators()
- for i in gi.itervalues():
- init = self._get_initiator(i['id'])
- init_list.append(self._initiator(init))
- return init_list
-
@staticmethod
def _v7k_init_to_lsm_ag(v7k_init, system_id):
lsm_init_id = None
@@ -498,47 +394,3 @@ class IbmV7k(IStorageAreaNetwork):
# TODO: How to pass -force param ? For now, assume -force
self._delete_volume(volume.id, force=True)
return None
-
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- flags=0):
- # TODO: How to pass -force param ? For now, assume -force.
- # -force allows multiple vdisk-to-host assignments,
- # which are not normally allowed
-
- # NOTE: V7000 doesn't provide a way to pass access param,
- # access is always rw, if ro, raise error.
- if access != Volume.ACCESS_READ_WRITE:
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Only RW access to the volume is supported")
-
- exit_code, stdout, stderr = self._initiator_grant(initiator_id,
- initiator_type,
- volume.id,
- force=True)
- return self._initiator_grant_is_success(stdout)
-
- def initiator_revoke(self, initiator, volume, flags=0):
- self._initiator_revoke(initiator.id, volume.id)
- return
-
- def volumes_accessible_by_initiator(self, initiator, flags=0):
- gvabi = self._get_volumes_accessible_by_initiator(initiator.id)
-
- vol_list = []
- for vol in gvabi.itervalues():
- gv = self._get_volume(vol['vdisk_id'])
- v = self._volume(gv)
- vol_list.append(v)
-
- return vol_list
-
- def initiators_granted_to_volume(self, volume, flags=0):
- gigtv = self._get_initiators_granted_to_volume(volume.id)
-
- init_list = []
- for init in gigtv.itervalues():
- gi = self._get_initiator(init['host_id'])
- i = self._initiator(gi)
- init_list.append(i)
-
- return init_list
--
1.8.3.1
Tony Asleson
2014-06-17 18:41:03 UTC
Permalink
Post by Gris Ge
'Masking and Mapping' not supported.
Well we did have support with the initiator code previously, can we make
this work by doing the same thing you did with targetd?

Thanks,
Tony
Gris Ge
2014-06-18 13:31:49 UTC
Permalink
* Enable access_groups() support by forcing fallback mode.
* Disable access_group_initiator_delete() support as we got a unexpected
behaviour when testing. The whole SPC will be removed when deleting one
initiator, this will cause data lose.
* Only tested by access_groups() and access_group_initiator_add().
Volume masking and unmasking is not tested due to hardware access issue.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/eseries.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/plugin/smispy/eseries.py b/plugin/smispy/eseries.py
index 2160159..bcec9b7 100644
--- a/plugin/smispy/eseries.py
+++ b/plugin/smispy/eseries.py
@@ -19,10 +19,54 @@ from smis import Smis
import pywbem
import time
from lsm.plugin.smispy.smis import handle_cim_errors
-from lsm import LsmError, ErrorNumber, Capabilities
+from lsm import LsmError, ErrorNumber, Capabilities, uri_parse


class ESeries(Smis):
+ def plugin_register(self, uri, password, timeout, flags=0):
+ """
+ The only difference we did here compare to supper method:
+ we force to be fallback mode.
+ NetApp-E support 'Masking and Mapping' profile but not expose it
+ via CIM_RegisteredProfile.
+ """
+ protocol = 'http'
+ port = Smis.IAAN_WBEM_HTTP_PORT
+ u = uri_parse(uri, ['scheme', 'netloc', 'host'], None)
+
+ if u['scheme'].lower() == 'smispy+ssl':
+ protocol = 'https'
+ port = Smis.IAAN_WBEM_HTTPS_PORT
+
+ if 'port' in u:
+ port = u['port']
+
+ # smisproxy.py already make sure namespace defined.
+ namespace = u['parameters']['namespace']
+ self.all_vendor_namespaces = [namespace]
+
+ url = "%s://%s:%s" % (protocol, u['host'], port)
+ self.system_list = None
+ if 'systems' in u['parameters']:
+ self.system_list = split(u['parameters']["systems"], ":")
+
+ self._c = pywbem.WBEMConnection(url, (u['username'], password),
+ namespace)
+ if "no_ssl_verify" in u["parameters"] \
+ and u["parameters"]["no_ssl_verify"] == 'yes':
+ try:
+ self._c = pywbem.WBEMConnection(
+ url,
+ (u['username'], password),
+ namespace,
+ no_verification=True)
+ except TypeError:
+ # pywbem is not holding fix from
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1039801
+ pass
+
+ self.tmo = timeout
+ self.fallback_mode = True

def _deal_volume_associations(self, vol, lun):
"""
@@ -121,3 +165,14 @@ class ESeries(Smis):
time.sleep(0.125)
except LsmError as e:
pass
+
+ @handle_cim_errors
+ def access_group_initiator_delete(self, access_group, init_id, flags=0):
+ """
+ When using HidePaths to remove initiator, the whole SPC will be
+ removed. Before we find a workaround for this, I would like to have
+ this method disabled as NO_SUPPORT.
+ """
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S plugin does not support "
+ "access_group_initiator_delete() against NetApp-E")
--
1.8.3.1
Tony Asleson
2014-06-20 22:22:01 UTC
Permalink
Patch committed, thank you!

-Tony
Post by Gris Ge
* Enable access_groups() support by forcing fallback mode.
* Disable access_group_initiator_delete() support as we got a unexpected
behaviour when testing. The whole SPC will be removed when deleting one
initiator, this will cause data lose.
* Only tested by access_groups() and access_group_initiator_add().
Volume masking and unmasking is not tested due to hardware access issue.
---
plugin/smispy/eseries.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/plugin/smispy/eseries.py b/plugin/smispy/eseries.py
index 2160159..bcec9b7 100644
--- a/plugin/smispy/eseries.py
+++ b/plugin/smispy/eseries.py
@@ -19,10 +19,54 @@ from smis import Smis
import pywbem
import time
from lsm.plugin.smispy.smis import handle_cim_errors
-from lsm import LsmError, ErrorNumber, Capabilities
+from lsm import LsmError, ErrorNumber, Capabilities, uri_parse
+ """
+ we force to be fallback mode.
+ NetApp-E support 'Masking and Mapping' profile but not expose it
+ via CIM_RegisteredProfile.
+ """
+ protocol = 'http'
+ port = Smis.IAAN_WBEM_HTTP_PORT
+ u = uri_parse(uri, ['scheme', 'netloc', 'host'], None)
+
+ protocol = 'https'
+ port = Smis.IAAN_WBEM_HTTPS_PORT
+
+ port = u['port']
+
+ # smisproxy.py already make sure namespace defined.
+ namespace = u['parameters']['namespace']
+ self.all_vendor_namespaces = [namespace]
+
+ url = "%s://%s:%s" % (protocol, u['host'], port)
+ self.system_list = None
+ self.system_list = split(u['parameters']["systems"], ":")
+
+ self._c = pywbem.WBEMConnection(url, (u['username'], password),
+ namespace)
+ if "no_ssl_verify" in u["parameters"] \
+ self._c = pywbem.WBEMConnection(
+ url,
+ (u['username'], password),
+ namespace,
+ no_verification=True)
+ # pywbem is not holding fix from
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1039801
+ pass
+
+ self.tmo = timeout
+ self.fallback_mode = True
"""
time.sleep(0.125)
pass
+
+ """
+ When using HidePaths to remove initiator, the whole SPC will be
+ removed. Before we find a workaround for this, I would like to have
+ this method disabled as NO_SUPPORT.
+ """
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S plugin does not support "
+ "access_group_initiator_delete() against NetApp-E")
Gris Ge
2014-06-18 13:31:49 UTC
Permalink
* Enable access_groups() support by forcing fallback mode.
* Disable access_group_initiator_delete() support as we got a unexpected
behaviour when testing. The whole SPC will be removed when deleting one
initiator, this will cause data lose.
* Only tested by access_groups() and access_group_initiator_add().
Volume masking and unmasking is not tested due to hardware access issue.

Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/eseries.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)

diff --git a/plugin/smispy/eseries.py b/plugin/smispy/eseries.py
index 2160159..bcec9b7 100644
--- a/plugin/smispy/eseries.py
+++ b/plugin/smispy/eseries.py
@@ -19,10 +19,54 @@ from smis import Smis
import pywbem
import time
from lsm.plugin.smispy.smis import handle_cim_errors
-from lsm import LsmError, ErrorNumber, Capabilities
+from lsm import LsmError, ErrorNumber, Capabilities, uri_parse


class ESeries(Smis):
+ def plugin_register(self, uri, password, timeout, flags=0):
+ """
+ The only difference we did here compare to supper method:
+ we force to be fallback mode.
+ NetApp-E support 'Masking and Mapping' profile but not expose it
+ via CIM_RegisteredProfile.
+ """
+ protocol = 'http'
+ port = Smis.IAAN_WBEM_HTTP_PORT
+ u = uri_parse(uri, ['scheme', 'netloc', 'host'], None)
+
+ if u['scheme'].lower() == 'smispy+ssl':
+ protocol = 'https'
+ port = Smis.IAAN_WBEM_HTTPS_PORT
+
+ if 'port' in u:
+ port = u['port']
+
+ # smisproxy.py already make sure namespace defined.
+ namespace = u['parameters']['namespace']
+ self.all_vendor_namespaces = [namespace]
+
+ url = "%s://%s:%s" % (protocol, u['host'], port)
+ self.system_list = None
+ if 'systems' in u['parameters']:
+ self.system_list = split(u['parameters']["systems"], ":")
+
+ self._c = pywbem.WBEMConnection(url, (u['username'], password),
+ namespace)
+ if "no_ssl_verify" in u["parameters"] \
+ and u["parameters"]["no_ssl_verify"] == 'yes':
+ try:
+ self._c = pywbem.WBEMConnection(
+ url,
+ (u['username'], password),
+ namespace,
+ no_verification=True)
+ except TypeError:
+ # pywbem is not holding fix from
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1039801
+ pass
+
+ self.tmo = timeout
+ self.fallback_mode = True

def _deal_volume_associations(self, vol, lun):
"""
@@ -121,3 +165,14 @@ class ESeries(Smis):
time.sleep(0.125)
except LsmError as e:
pass
+
+ @handle_cim_errors
+ def access_group_initiator_delete(self, access_group, init_id, flags=0):
+ """
+ When using HidePaths to remove initiator, the whole SPC will be
+ removed. Before we find a workaround for this, I would like to have
+ this method disabled as NO_SUPPORT.
+ """
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S plugin does not support "
+ "access_group_initiator_delete() against NetApp-E")
--
1.8.3.1
Tony Asleson
2014-06-18 21:43:27 UTC
Permalink
Patch committed.

Thanks,
Tony
Post by Gris Ge
* Remove lsm.Initiator and related methods from plugins.
* Update iscsi_chap_auth().
* SMI-S plugin now fully support interop namespace.
* Removed some unused methods from SMI-S plugin.
lsmcli list --type access_groups
lsmcli ag-add-init --ag <AG_ID> --init <INIT_ID> --init-type WWPN|iSCSI
lsmcli ag-del-init --ag <AG_ID> --init <INIT_ID>
lsmcli volume-mask --vol <VOL_ID> --ag <AG_ID>
lsmcli list --type volumes --ag <AG_ID>
lsmcli list --type access_groups --vol <VOL_ID>
lsmcli volume-unmask --vol <VOL_ID> --ag <AG_ID>
Nexentastor 3.1.5
ONTAP 8.1.2 7-mode
SimArray 2.4
EMC VNX(full test)
EMC VMAX, FUJITSU ETERNUS, HDS AMS[1], IBM XIV, NetApp ONTAP[2]
'Masking and Mapping' not supported.
lsmcli volume-mask --vol <VOL_ID> --init <INIT_ID> --init-type iSCSI
lsmcli list --type volumes --ag <AG_ID>
lsmcli list --type access_groups --vol <VOL_ID>
lsmcli volume-unmask --vol <VOL_ID> --ag <AG_ID>
[1] HDS AMS marked 'other' type of access_group, need investigation, might be
iSCSI target port.
[2] NetApp ONTAP SMI-S provider does not provider initiator ID when call
access_groups(), need investigation.
---
plugin/nstor/nstor.py | 91 +------
plugin/ontap/na.py | 2 +-
plugin/ontap/ontap.py | 74 ++----
plugin/sim/simarray.py | 196 ++++-----------
plugin/sim/simulator.py | 28 +--
plugin/smispy/eseries.py | 65 -----
plugin/smispy/smis.py | 622 ++++++++++++++++------------------------------
plugin/targetd/targetd.py | 69 +----
plugin/v7k/ibmv7k.py | 150 +----------
9 files changed, 302 insertions(+), 995 deletions(-)
diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index f655a5e..c47a670 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -30,7 +30,7 @@ import time
import traceback
from lsm import (AccessGroup, Capabilities, ErrorNumber, FileSystem, INfs,
- IStorageAreaNetwork, Initiator, LsmError, NfsExport, Pool,
+ IStorageAreaNetwork, LsmError, NfsExport, Pool,
FsSnapshot, System, VERSION, Volume, md5, Error,
common_urllib2_error_handler, search_property)
return search_property(vol_list, search_key, search_value)
@handle_nstor_errors
- """
- Return an array of initiator objects
- """
- i_list = []
- i_list.append(Initiator(initiator_id,
- Initiator.TYPE_ISCSI, initiator_id))
- return i_list
-
def volume_create(self, pool, volume_name, size_bytes, provisioning,
"""
# return
@handle_nstor_errors
- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
"""
Register a user/password for the specified initiator for CHAP
self._request("create_initiator", "iscsitarget",
- [initiator.name,
+ [init_id,
{'initiatorchapuser': in_user,
'initiatorchapsecret': in_password}])
self._request("modify_initiator", "iscsitarget",
- [initiator.name,
+ [init_id,
{'initiatorchapuser': in_user,
'initiatorchapsecret': in_password}])
self._request("modify_initiator", "iscsitarget",
- [initiator.name,
+ [init_id,
{'initiatorchapuser': in_user,
'initiatorchapsecret': in_password}])
return
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- """
- Allows an initiator to access a volume.
- """
- hg_name = NexentaStor._calc_group(initiator_id)
- self.access_group_create(hg_name, initiator_id, initiator_type,
- 'NA')
- pass
- self._volume_mask(hg_name, volume.name)
- return
-
return self._request("list_lun_mapping_entries", "scsidisk",
[volume_name])
- """
- Revokes access to a volume for the specified initiator
- """
- ag_name = NexentaStor._calc_group(initiator.name)
- views = self._get_views(volume.name)
- view_number = -1
- view_number = view['entry_number']
- raise LsmError(ErrorNumber.NO_MAPPING, "There is no such mapping "
- "for volume %s" %
- volume.name)
- self._request("remove_lun_mapping_entry", "scsidisk",
- [volume.name, view_number])
- self._request("destroy_hostgroup", "stmf", [ag_name])
- return
-
self._request("add_lun_mapping_entry", "scsidisk",
[volume_name, {'host_group': group_name}])
"""
Adds an initiator to an access group
"""
raise LsmError(ErrorNumber.NO_SUPPORT,
"Nstor only support iSCSI Access Group")
self._request("promote", "volume", [clone_name])
return None
-
- """
- Returns a list of volumes that the initiator has access to.
- """
- ag_name = NexentaStor._calc_group(initiator.name)
- volumes = []
- all_volumes_list = self.volumes()
- volumes.append(vol)
- return volumes
-
- """
- Returns a list of initiators that have access to the specified volume.
- """
- ag_list = self.access_groups()
- i_list = self.initiators()
- initiators_id = []
- initiators_id.extend(ag.initiators)
- initiators = []
- initiators.append(i)
- return initiators
diff --git a/plugin/ontap/na.py b/plugin/ontap/na.py
index 0986a9c..214cc0d 100644
--- a/plugin/ontap/na.py
+++ b/plugin/ontap/na.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2013 Red Hat, Inc.
+# Copyright (C) 2012-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
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index cde128f..203dfe7 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -23,7 +23,7 @@ import urlparse
import sys
import na
-from lsm import (Volume, Initiator, FileSystem, FsSnapshot, NfsExport,
+from lsm import (Volume, FileSystem, FsSnapshot, NfsExport,
AccessGroup, System, Capabilities, Disk, Pool, OptionalData,
IStorageAreaNetwork, INfs, LsmError, ErrorNumber, JobStatus,
md5, Error, VERSION, common_urllib2_error_handler,
return [self.sys_info]
- """
- We will list all the initiators that are in all the groups.
- """
- rc = []
- groups = self.f.igroups()
-
- #Get the initiator in the group
- inits = na.to_list(g['initiators']['initiator-info'])
-
- init = i['initiator-name']
-
- init_type = Initiator.TYPE_ISCSI
- init_type = Initiator.TYPE_PORT_WWN
-
- name = init
- rc.append(Initiator(init, init_type, name))
-
- return rc
-
return self._lun(self.f.luns_get_specific(pool_id, vol_name, None)[0])
return self.f.lun_offline(volume.name)
@handle_ontap_errors
- self.f.lun_map(group.name, volume.name)
+ self.f.lun_map(access_group.name, volume.name)
return None
@handle_ontap_errors
- self.f.lun_unmap(group.name, volume.name)
+ self.f.lun_unmap(access_group.name, volume.name)
return None
@staticmethod
[self._access_group(g) for g in groups], search_key, search_value)
@handle_ontap_errors
- def access_group_create(self, name, initiator_id, id_type, system_id,
+ def access_group_create(self, name, init_id, init_type, system_id,
cur_groups = self.access_groups()
raise LsmError(ErrorNumber.EXISTS_ACCESS_GROUP,
- "Access group exists!")
+ "Access group with the same name exists!")
self.f.igroup_create(name, 'iscsi')
self.f.igroup_create(name, 'fcp')
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "ONTAP only support iSCSI and FC/FCoE, but got "
+ "init_type: %d" % init_type)
- self.f.igroup_add_initiator(name, initiator_id)
+ self.f.igroup_add_initiator(name, init_id)
groups = self.access_groups()
"Unable to find group just created!")
@handle_ontap_errors
- return self.f.igroup_delete(group.name)
+ return self.f.igroup_delete(access_group.name)
@handle_ontap_errors
- def access_group_initiator_add(self, group, initiator_id, id_type,
+ def access_group_initiator_add(self, access_group, init_id, init_type,
- return self.f.igroup_add_initiator(group.name, initiator_id)
+ return self.f.igroup_add_initiator(access_group.name, init_id)
@handle_ontap_errors
- return self.f.igroup_del_initiator(group.name, initiator_id)
+ return self.f.igroup_del_initiator(access_group.name, init_id)
@handle_ontap_errors
rc = []
- luns = self.f.lun_initiator_list_map_info(group.initiators[0],
- group.name)
+ luns = self.f.lun_initiator_list_map_info(access_group.init_ids[0],
+ access_group.name)
rc = [self._lun(l) for l in luns]
return rc
return [self._access_group(g) for g in groups]
@handle_ontap_errors
- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
if out_user and out_password and \
"out_user and out_password only supported if "
"inbound is supplied")
- self.f.iscsi_initiator_add_auth(initiator.id, in_user, in_password,
+ self.f.iscsi_initiator_add_auth(init_id, in_user, in_password,
out_user, out_password)
@staticmethod
diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index c7cc2cc..0ccc4dc 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2013 Red Hat, Inc.
+# Copyright (C) 2011-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
@@ -27,8 +27,8 @@ import time
from lsm import (size_human_2_size_bytes, size_bytes_2_size_human)
from lsm import (System, Volume, Disk, Pool, FileSystem, AccessGroup,
- Initiator, FsSnapshot, NfsExport, OptionalData, md5,
- LsmError, ErrorNumber, JobStatus)
+ FsSnapshot, NfsExport, OptionalData, md5, LsmError,
+ ErrorNumber, JobStatus)
# Used for format width for disks
D_FMT = 5
sim_ags = self.data.access_groups_granted_to_volume(vol_id, flags)
return [SimArray._sim_ag_2_lsm(a) for a in sim_ags]
- return Initiator(sim_init['init_id'], sim_init['init_type'],
- sim_init['name'])
-
- sim_inits = self.data.inits()
- return [SimArray._sim_init_2_lsm(a) for a in sim_inits]
-
- return self.data.initiator_grant(
- init_id, init_type, vol_id, access, flags)
-
- return self.data.initiator_revoke(init_id, vol_id, flags)
-
- sim_vols = self.data.volumes_accessible_by_initiator(init_id, flags)
- return [SimArray._sim_vol_2_lsm(v) for v in sim_vols]
-
- sim_inits = self.data.initiators_granted_to_volume(vol_id, flags)
- return [SimArray._sim_init_2_lsm(i) for i in sim_inits]
-
def iscsi_chap_auth(self, init_id, in_user, in_pass, out_user, out_pass,
return self.data.iscsi_chap_auth(init_id, in_user, in_pass, out_user,
}
}
- self.init_dict = {
- Initiator.id = sim_init,
- }
- sim_init = {
- 'init_id': Initiator.id,
- 'init_type': Initiator.TYPE_XXXX,
- 'name': SimData.SIM_DATA_INIT_NAME,
- 'sys_id': SimData.SIM_DATA_SYS_ID,
- }
-
self.ag_dict ={
AccessGroup.id = sim_ag,
}
}
"""
SIM_DATA_BLK_SIZE = 512
- SIM_DATA_VERSION = "2.3"
+ SIM_DATA_VERSION = "2.4"
SIM_DATA_SYS_ID = 'sim-01'
SIM_DATA_INIT_NAME = 'NULL'
SIM_DATA_TMO = 30000 # ms
return self.ag_dict.values()
+ self._check_dup_name(
+ self.vol_dict.values(), vol_name, ErrorNumber.EXISTS_VOLUME)
size_bytes = SimData._block_rounding(size_bytes)
# check free size
free_space = self.pool_free_space(pool_id)
return self.ag_dict.values()
+ raise LsmError(ErrorNumber.EXISTS_INITIATOR,
+ "init_id %s already exist in other "
+ % init_id +
+ "access group %s" % sim_ag['ag_id'])
+ used_names = [x['name'] for x in sim_list]
+ raise LsmError(error_num, "Name '%s' already in use" % name)
+
+ self._check_dup_name(
+ self.ag_dict.values(), name, ErrorNumber.EXISTS_ACCESS_GROUP)
+ self._check_dup_init(init_id)
sim_ag = dict()
- sim_init = dict()
- sim_init['init_id'] = init_id
- sim_init['init_type'] = init_type
- sim_init['name'] = SimData.SIM_DATA_INIT_NAME
- sim_init['sys_id'] = SimData.SIM_DATA_SYS_ID
- self.init_dict[init_id] = sim_init
-
sim_ag['init_ids'] = [init_id]
sim_ag['init_type'] = init_type
sim_ag['sys_id'] = SimData.SIM_DATA_SYS_ID
raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
"Access group not found")
- sim_init = dict()
- sim_init['init_id'] = init_id
- sim_init['init_type'] = init_type
- sim_init['name'] = SimData.SIM_DATA_INIT_NAME
- sim_init['sys_id'] = SimData.SIM_DATA_SYS_ID
- self.init_dict[init_id] = sim_init
- return self.ag_dict[ag_id]
+ return None
- self.ag_dict[ag_id]['init_ids'].extend([init_id])
+ self._check_dup_init(init_id)
+ self.ag_dict[ag_id]['init_ids'].extend([init_id])
return None
raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
"Access group not found: %s" % ag_id)
- return None
new_init_ids = []
return None
- raise LsmError(ErrorNumber.NOT_FOUND_ACCESS_GROUP,
- "Access group not found: %s" % ag_id)
+ # We don't check wether ag_id is valid
rc = []
return rc
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
+ # We don't check wether vold_id is valid
sim_ags = []
ag_ids = self.vol_dict[vol_id]['mask'].keys()
sim_ags.extend([self.ag_dict[ag_id]])
return sim_ags
- return self.init_dict.values()
-
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
- sim_init = dict()
- sim_init['init_id'] = init_id
- sim_init['init_type'] = init_type
- sim_init['name'] = SimData.SIM_DATA_INIT_NAME
- sim_init['sys_id'] = SimData.SIM_DATA_SYS_ID
- self.init_dict[init_id] = sim_init
- self.vol_dict[vol_id]['mask_init'] = dict()
-
- self.vol_dict[vol_id]['mask_init'][init_id] = access
- return None
-
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such Initiator: %s" % init_id)
-
- del self.vol_dict[vol_id]['mask_init'][init_id]
-
- return None
-
"""
Find out the access groups defined initiator belong to.
rc.extend([sim_ag['ag_id']])
return rc
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such Initiator: %s" % init_id)
- rc_dedup_dict = dict()
- ag_ids = self._ag_ids_of_init(init_id)
- sim_vols = self.volumes_accessible_by_access_group(ag_id)
- rc_dedup_dict[sim_vol['vol_id']] = sim_vol
-
- rc_dedup_dict[sim_vol['vol_id']] = sim_vol
- return rc_dedup_dict.values()
-
- raise LsmError(ErrorNumber.INVALID_VOLUME,
- "No such Volume: %s" % vol_id)
- rc_dedup_dict = dict()
- sim_ags = self.access_groups_granted_to_volume(vol_id, flags)
- rc_dedup_dict[init_id] = self.init_dict[init_id]
-
- rc_dedup_dict[init_id] = self.init_dict[init_id]
-
- return rc_dedup_dict.values()
-
def iscsi_chap_auth(self, init_id, in_user, in_pass, out_user, out_pass,
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such Initiator: %s" % init_id)
+ # to_code
raise LsmError(ErrorNumber.UNSUPPORTED_INITIATOR_TYPE,
"Initiator %s is not an iSCSI IQN" % init_id)
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % src_fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % src_fs_id)
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
rc = []
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
self.fs_dict[fs_id]['snaps'] = []
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
def fs_snapshot_restore(self, fs_id, snap_id, files, restore_files,
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
raise LsmError(ErrorNumber.INVALID_SS,
"No such Snapshot: %s" % snap_id)
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
return False
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
return None
def fs_export(self, fs_id, exp_path, root_hosts, rw_hosts, ro_hosts,
- raise LsmError(ErrorNumber.INVALID_INIT,
- "No such File System: %s" % fs_id)
+ raise LsmError(ErrorNumber.NOT_FOUND_FS,
+ "File System: %s not found" % fs_id)
sim_exp = dict()
sim_exp['exp_id'] = self._next_exp_id()
sim_exp['fs_id'] = fs_id
diff --git a/plugin/sim/simulator.py b/plugin/sim/simulator.py
index cb3f08a..b452b6a 100644
--- a/plugin/sim/simulator.py
+++ b/plugin/sim/simulator.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2013 Red Hat, Inc.
+# Copyright (C) 2011-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
@@ -14,6 +14,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Author: tasleson
from lsm import (uri_parse, VERSION, Capabilities, Pool, INfs,
IStorageAreaNetwork, Error, search_property)
volume.id, flags)
return [SimPlugin._sim_data_2_lsm(v) for v in sim_vols]
- return self.sim_array.inits(flags)
-
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- return self.sim_array.initiator_grant(
- initiator_id, initiator_type, volume.id, access, flags)
-
- return self.sim_array.initiator_revoke(initiator.id, volume.id, flags)
-
- sim_vols = self.sim_array.volumes_accessible_by_initiator(
- initiator.id, flags)
- return [SimPlugin._sim_data_2_lsm(v) for v in sim_vols]
-
- sim_inits = self.sim_array.initiators_granted_to_volume(
- volume.id, flags)
- return [SimPlugin._sim_data_2_lsm(i) for i in sim_inits]
-
- def iscsi_chap_auth(self, initiator, in_user, in_password,
+ def iscsi_chap_auth(self, init_id, in_user, in_password,
return self.sim_array.iscsi_chap_auth(
- initiator.id, in_user, in_password, out_user, out_password, flags)
+ init_id, in_user, in_password, out_user, out_password, flags)
return self.sim_array.volume_child_dependency(volume.id, flags)
diff --git a/plugin/smispy/eseries.py b/plugin/smispy/eseries.py
index 8aa3d18..2160159 100644
--- a/plugin/smispy/eseries.py
+++ b/plugin/smispy/eseries.py
#doesn't work
return cap
- ag_init_ids = []
- cim_st_hwid_pros = self._property_list_of_id('Initiator')
- cim_st_hwids = self._get_cim_st_hwid_in_spc(cim_grp, cim_st_hwid_pros)
- ag_init_ids = [self._init_id(i) for i in cim_st_hwids]
- return ag_init_ids
-
- groups = self._get_access_groups()
-
- initiators = self._get_initiators_in_group(g)
- return g
-
- return None
-
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- ccs = self._get_class_instance('CIM_ControllerConfigurationService')
- lun = self._get_cim_instance_by_id('Volume', volume.id)
-
- #Need to check for existence of initiator, else create one
- initiator = self._initiator_lookup(initiator_id)
-
- in_params = {'LUNames': [lun['DeviceID']],
- 'DeviceAccesses': [pywbem.Uint16(2)]}
-
- #In this case we need to find the access group that contains the
- #initiator and then pass the
- group = self._get_group_initiator_is_in(initiator_id)
-
- raise LsmError(ErrorNumber.UNSUPPORTED_PROVISIONING,
- "Unsupported provisioning")
-
- in_params['ProtocolControllers'] = [group.path]
- in_params['InitiatorPortIDs'] = [initiator_id]
-
- #Returns None or job id
- return self._pi("initiator_grant", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('ExposePaths', ccs.path,
- **in_params)))[0]
-
- (found, spc) = self._get_spc(initiator.id, volume.id)
-
- ccs = self._get_class_instance(
- 'CIM_ControllerConfigurationService')
-
- in_params = dict(ProtocolController=spc.path,
- DeleteChildrenProtocolControllers=True,
- DeleteUnits=True)
-
- #Returns None or job id
- return self._pi("access_revoke", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('DeleteProtocolController',
- ccs.path, **in_params)))[0]
-
#Get the Configuration service for the system we are interested in.
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index a596ca5..6d10973 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -25,7 +25,7 @@ import pywbem
from pywbem import CIMError
from lsm import (IStorageAreaNetwork, Error, uri_parse, LsmError, ErrorNumber,
- JobStatus, md5, Pool, Initiator, Volume, AccessGroup, System,
+ JobStatus, md5, Pool, Volume, AccessGroup, System,
Capabilities, Disk, OptionalData, txt_a, VERSION,
search_property)
raise LsmError(ErrorNumber.NETWORK_HOSTDOWN,
'Host is down')
- raise LsmError(ErrorNumber.PLUGIN_ERROR, desc)
+ raise LsmError(ErrorNumber.LSM_BUG, desc)
raise LsmError(ErrorNumber.PLUGIN_AUTH_FAILED, "Unauthorized user")
return None
+ return list(set(list_a + list_b))
+
+
+ # 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)
_INIT_TYPE_CONV = {
@@ -116,6 +122,7 @@ _INIT_TYPE_CONV = {
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,
}
return _INIT_TYPE_CONV[cim_init['IDType']]
return AccessGroup.INIT_TYPE_UNKNOWN
+ return _get_key(_INIT_TYPE_CONV, lsm_init_type)
keys = [k for k, v in dictionary.items() if v == value]
self.cim_rps = []
self.cim_root_profile_dict = dict()
self.fallback_mode = True # Means we cannot use profile register
+ self.all_vendor_namespaces = []
def _get_cim_instance_by_id(self, class_type, requested_id,
"""
Find out the CIM_XXXX Instance which holding the requested_id
- If flag_full_info == True, we return a Instance with full info.
- If you want to save some query time, try set it as False
+ Return None when error and raise_error is False
"""
class_name = Smis._cim_class_name_of(class_type)
- property_list = Smis._property_list_of_id(class_type, property_list)
+ error_numer = Smis._not_found_error_of_class(class_type)
+ id_pros = Smis._property_list_of_id(class_type, property_list)
- cim_xxxs = self._c.EnumerateInstances(class_name,
- PropertyList=property_list,
- LocalOnly=False)
+ property_list = id_pros
+ property_list = _merge_list(property_list, id_pros)
+
+ cim_xxxs = self._enumerate(class_name, property_list)
org_requested_id = requested_id
(requested_id, ignore) = self._parse_job_id(requested_id)
- cim_xxx = self._c.GetInstance(cim_xxx.path,
- LocalOnly=False)
return cim_xxx
+ return None
- raise LsmError(ErrorNumber.INVALID_ARGUMENT,
+ raise LsmError(error_numer,
"Cannot find %s Instance with " % class_name +
"%s ID '%s'" % (class_type, org_requested_id))
- def _get_class_instance(self, class_name, prop_name=None, prop_value=None,
+ def _get_class_instance(self, class_name, prop_name, prop_value,
"""
Gets an instance of a class that optionally matches a specific
property name and value
"""
instances = None
+ property_list = [prop_name]
+ property_list = _merge_list(property_list, [prop_name])
- instances = self._c.EnumerateInstances(
- class_name, PropertyList=[prop_name], LocalOnly=False)
- instances = self._c.EnumerateInstances(class_name,
- LocalOnly=False)
+ cim_xxxs = self._enumerate(class_name, property_list)
error_code = tuple(ce)[0]
- if error_code == pywbem.CIM_ERR_INVALID_CLASS \
+ if error_code == pywbem.CIM_ERR_INVALID_CLASS and \
return None
raise ce
- class_names = " ".join([x.classname for x in instances])
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
- "Expecting one instance of %s and got %s" %
- (class_name, class_names))
-
- return instances[0]
- return i
-
- return None
+ return cim_xxx
- raise LsmError(ErrorNumber.INVALID_ARGUMENT,
- "Unable to find class instance %s " % class_name +
- "with property %s " % prop_name +
- "with value %s" % prop_value)
-
- """
- Retrieve the SCSIProtocolController for a given initiator and volume.
- This will return a non-none value when there is a mapping between the
- initiator and the volume.
- """
- init = self._get_class_instance('CIM_StorageHardwareID', 'StorageID',
- initiator_id)
-
- # Look at page 151 (1.5 smi-s spec.) in the block services books for
- # the SNIA_MappingProtocolControllerView
-
- auths = self._c.Associators(init.path,
- AssocClass='CIM_AuthorizedSubject')
-
- spc = self._c.Associators(
- a.path, AssocClass='CIM_AuthorizedTarget')
- logical_device = \
- self._c.Associators(
- spc[0].path,
- AssocClass='CIM_ProtocolControllerForUnit')
-
- vol = self._c.GetInstance(logical_device[0].path,
- LocalOnly=False)
- if 'DeviceID' in vol and \
- return spc[0]
+ raise LsmError(ErrorNumber.LSM_BUG,
+ "Unable to find class instance %s " % class_name +
+ "with property %s " % prop_name +
+ "with value %s" % prop_value)
return None
namespace = None
namespace = u['parameters']['namespace']
+ self.all_vendor_namespaces = [namespace]
namespace = Smis.SMIS_DEFAULT_NAMESPACE
self.fallback_mode = False
+ self.all_vendor_namespaces = []
# Support 'Array' profile is step 0 for this whole plugin.
# We find out all 'Array' CIM_RegisteredProfile and stored
# them into self.cim_root_profile_dict
SNIA.SMIS_SPEC_VER_1_4,
raise LsmError(ErrorNumber.NO_SUPPORT,
- "SMI-S provider does not support "
+ "Target SMI-S provider does not support "
"SNIA SMI-S SPEC %s '%s' profile" %
(SNIA.SMIS_SPEC_VER_1_4,
SNIA.BLK_ROOT_PROFILE))
Interrogate the supported features of the replication service
"""
rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system.id, True)
+ system.id, raise_error=False)
rs_cap = self._c.Associators(
rs.path,
rs = self._get_class_instance("CIM_StorageConfigurationService",
'SystemName',
- system.id, True)
+ system.id, raise_error=False)
rs_cap = self._c.Associators(
# Get the cim object that represents the system
cim_sys = None
cim_pcms = None
- cim_sys = self._cim_sys_of_id(system.id)
+ cim_sys = self._get_cim_instance_by_id('System', system.id)
# Using 'ExposePathsSupported of
# Assume that the SMI-S we are talking to supports blocks
cap.set(Capabilities.BLOCK_SUPPORT)
- cap.set(Capabilities.INITIATORS)
self._scs_supported_capabilities(system, cap)
self._rs_supported_capabilities(system, cap)
'OperationalStatus']
cim_job_pros = self._property_list_of_id('Job', props)
- cim_job = self._get_cim_instance_by_id('Job', job_id, False,
- cim_job_pros)
+ cim_job = self._get_cim_instance_by_id('Job', job_id, cim_job_pros)
job_state = cim_job['JobState']
return 'CIM_SCSIProtocolController'
return 'CIM_StorageHardwareID'
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Smis._cim_class_name_of() got unknown " +
"class_type %s" % class_type)
@staticmethod
+ return ErrorNumber.NOT_FOUND_VOLUME
+ return ErrorNumber.NOT_FOUND_SYSTEM
+ return ErrorNumber.NOT_FOUND_POOL
+ return ErrorNumber.NOT_FOUND_DISK
+ return ErrorNumber.NOT_FOUND_JOB
+ return ErrorNumber.NOT_FOUND_ACCESS_GROUP
+ return ErrorNumber.INVALID_ARGUMENT
+ raise LsmError(ErrorNumber.LSM_BUG,
+ "Smis._cim_class_name_of() got unknown " +
+ "class_type %s" % class_type)
+
+
"""
Return a PropertyList which the ID of current class is basing on
"""
rc = ['StorageID']
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Smis._cim_class_name_of() got unknown " +
"class_type %s" % class_type)
- rc.extend([p])
+ rc = _merge_list(rc, extra_properties)
return rc
PropertyList=pool_pros, LocalOnly=False)
return self._new_pool(cim_new_pool)
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Got not new Pool from out of InvokeMethod" +
"when CreateOrModifyElementFromStoragePool")
rc.extend([vol])
return search_property(rc, search_key, search_value)
- """
- Returns a list of system objects (CIM)
- """
- cim_syss = []
- cim_scss_path = []
- # Note: Please be informed, if PropertyList is an empty list,
- # XIV will return NOTHING, so use EnumerateInstanceNames()
- # when you need nothing but the CIMInstanceName
- cim_scss_path = \
- self._c.EnumerateInstanceNames(
- 'CIM_StorageConfigurationService')
- # If array does not support CIM_StorageConfigurationService
- # we use CIM_ComputerSystem which is mandatory.
- # We might get some non-storage array listed as system.
- # but we would like to take that risk instead of
- # skipping basic support of old SMIS provider.
- cim_syss = self._c.EnumerateInstances(
- 'CIM_ComputerSystem',
- PropertyList=['Name', 'ElementName', 'OperationalStatus'],
- LocalOnly=False)
- raise e
- cim_tmp = \
- self._c.Associators(cim_scs_path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_ComputerSystem',
- PropertyList=['Name',
- 'ElementName',
- 'OperationalStatus'])
- cim_syss.extend([cim_tmp[0]])
-
- # Filtering
- return [cim_sys]
-
- cim_filterd_syss = []
- cim_filterd_syss.extend([cim_sys])
- return cim_filterd_syss
- return cim_syss
-
- pros = []
- pros = ['Primordial']
+ property_list = ['Primordial']
- pros = property_list
- pros.extend(['Primordial'])
+ property_list = _merge_list(property_list, ['Primordial'])
cim_pools = self._c.Associators(cim_sys_path,
AssocClass='CIM_HostedStoragePool',
ResultClass='CIM_StoragePool',
- PropertyList=pros)
+ PropertyList=property_list)
return [p for p in cim_pools if not p["Primordial"]]
pool.optional_data.set(key, value)
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Failed to retrieve pool information " +
"from CIM_StoragePool: %s" % cim_pool.path)
return search_property(rc, search_key, search_value)
return [Smis._cim_sys_2_lsm_sys(s) for s in cim_syss]
- """
- Generate Initiator object from CIM_StorageHardwareID
- """
- init_id = self._init_id(cim_init)
- init_type = cim_init['IDType']
- init_name = cim_init['ElementName']
- return Initiator(init_id, init_type, init_name)
-
- """
- Return a list of properties needed to created Initiator from
- CIM_StorageHardwareID
- """
- cim_init_pros = self._property_list_of_id('Initiator',
- ['IDType', 'ElementName'])
- return cim_init_pros
-
- """
- Return all initiators generated from CIM_StorageHardwareID.
- CIM_ComputerSystem
- | (CIM_HostedService)
- v
- CIM_StorageHardwareIDManagementService
- | (CIM_ConcreteDependency)
- v
- CIM_StorageHardwareID
- This is supported from SNIA SMI-S 1.3rev6 to latest(1.6rev4).
- """
- rc_inits = []
- cim_init_pros = self._new_init_pros()
- cim_init_mss_path = self._c.AssociatorNames(
- cim_sys.path,
- AssocClass='CIM_HostedService',
- ResultClass='CIM_StorageHardwareIDManagementService')
- cim_inits = self._c.Associators(
- cim_init_ms_path,
- AssocClass='CIM_ConcreteDependency',
- ResultClass='CIM_StorageHardwareID',
- PropertyList=cim_init_pros)
- rc_inits.extend([self._new_init(i) for i in cim_inits])
- error_code = tuple(ce)[0]
- if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
- raise LsmError(ErrorNumber.NO_SUPPORT,
- 'Initiator is not supported by this array')
- return rc_inits
-
@handle_cim_errors
def volume_create(self, pool, volume_name, size_bytes, provisioning,
# Get the Configuration service for the system we are interested in.
scs = self._get_class_instance('CIM_StorageConfigurationService',
'SystemName', pool.system_id)
- sp = self._get_cim_instance_by_id('Pool', pool.id, False)
+ sp = self._get_cim_instance_by_id('Pool', pool.id)
in_params = {'ElementName': volume_name,
'ElementType': pywbem.Uint16(2),
rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- vol.system_id, True)
+ vol.system_id, raise_error=False)
in_params = {'Operation': pywbem.Uint16(8),
rc = [None, None]
rs = self._get_class_instance("CIM_ReplicationService", 'SystemName',
- system_id, True)
+ system_id, raise_error=False)
rs_cap = self._c.Associators(
volume_src.system_id, True)
- cim_pool = self._get_cim_instance_by_id('Pool', pool.id, False)
+ cim_pool = self._get_cim_instance_by_id('Pool', pool.id)
cim_pool = None
# Check for storage configuration service
rs = self._get_class_instance("CIM_StorageConfigurationService",
'SystemName', volume_src.system_id,
- True)
+ raise_error=False)
ct = Volume.REPLICATE_CLONE
return None
- """
- Create initiator object
- """
- hardware = self._get_class_instance(
- 'CIM_StorageHardwareIDManagementService')
-
- in_params = {'ElementName': name,
- 'StorageID': init_id,
- 'IDType': pywbem.Uint16(id_type)}
-
- (rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- hardware.path, **in_params)
- init = self._get_class_instance('CIM_StorageHardwareID',
- 'StorageID', init_id)
- return self._new_init(init)
-
- raise LsmError(ErrorNumber.PLUGIN_ERROR, 'Error: ' + str(rc) +
- ' on initiator_create!')
-
@handle_cim_errors
"""
Grant access to a volume to an group
"""
- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', access_group.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)
+ lun = self._get_cim_instance_by_id('Volume', volume.id, ['Name'])
spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)
# Returns None or job id
return self._pi("access_grant", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('ExposePaths', ccs.path,
+ *(self._c.InvokeMethod('ExposePaths', cim_ccs.path,
**in_params)))[0]
@handle_cim_errors
- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', volume.system_id)
- lun = self._get_cim_instance_by_id('Volume', volume.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)
+ lun = self._get_cim_instance_by_id('Volume', volume.id, ['Name'])
spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)
hide_params = {'LUNames': [lun['Name']],
'ProtocolControllers': [spc.path]}
return self._pi("HidePaths", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('HidePaths', ccs.path,
+ *(self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)))[0]
raise LsmError(ErrorNumber.NO_SUPPORT,
'AccessGroup is not supported by this array')
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Got %d instance of " % len(cim_ccss_path) +
"ControllerConfigurationService from %s" %
cim_sys.path + " in _cim_ags_of()")
return search_property(rc, search_key, search_value)
"""
- Looks up an initiator by initiator id
- returns None or object instance
+ Create a CIM_StorageHardwareID.
+ Raise error if failed. Return if pass.
"""
- initiator = None
- initiator = i
- break
- return initiator
+ cim_hw_srvs = self._c.AssociatorNames(
+ cim_sys_path,
+ ResultClass='CIM_StorageHardwareIDManagementService',
+ AssocClass='CIM_HostedService')
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "Target SMI-S provider does not support "
+ "access_group_initiator_add(): No "
+ "CIM_StorageHardwareIDManagementService to create"
+ "new initiator")
+ raise LsmError(ErrorNumber.LSM_BUG,
+ "_initiator_create(): Got more than one "
+ "CIM_StorageHardwareIDManagementService")
+
+ in_params = {#'ElementName': init_id,
+ 'StorageID': init_id,
+ 'IDType': pywbem.Uint16(dmtf_id_type)}
+ print in_params
+
+ (rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
+ cim_hw_srvs[0], **in_params)
+ return
+
+ # Ideally, we should handle CIM Error here in stead of raise
+ # LSM_BUG error. Let's wait user report on bug.
+ raise LsmError(ErrorNumber.LSM_BUG,
+ 'Error on _initiator_create(): rc: "%s", out: "%s"'
+ % (str(rc), out))
@handle_cim_errors
def access_group_initiator_add(self, access_group, init_id, init_type,
- # Check to see if we have this initiator already, if we don't create
- # it and then add to the view.
-
- spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)
+ # CIM_StorageHardwareIDManagementService.CreateStorageHardwareID()
+ # is mandatory since 1.4rev6
+ self._profile_is_supported(SNIA.MASK_PROFILE,
+ SNIA.SMIS_SPEC_VER_1_4,
+ strict=False,
+ raise_error=True)
- # This need rework when removing lsm.Initiator class
- initiator = self._initiator_lookup(init_id)
- lsm_init_type = _lsm_init_type_to_dmtf(init_type)
+ cim_sys = self._get_cim_instance_by_id('System',
+ access_group.system_id)
- initiator = self._initiator_create(init_id, init_id,
- lsm_init_type)
+ # Check to see if we have this initiator already, if we don't create
+ # it and then add to the view.
+ if self._get_cim_instance_by_id(
+ dmtf_id_type = _lsm_init_type_to_dmtf(init_type)
+ raise LsmError(ErrorNumber.NO_SUPPORT,
+ "SMI-S Plugin does not support init_type %d"
+ % init_type)
+ self._initiator_create(cim_sys.path, init_id, dmtf_id_type)
- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', access_group.system_id)
+ cim_ag = self._get_cim_instance_by_id('AccessGroup', access_group.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)
- in_params = {'InitiatorPortIDs': [initiator.id],
- 'ProtocolControllers': [spc.path]}
+ in_params = {'InitiatorPortIDs': [init_id],
+ 'ProtocolControllers': [cim_ag.path]}
# Returns None or job id
return self._pi("access_group_initiator_add", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('ExposePaths', ccs.path,
+ *(self._c.InvokeMethod('ExposePaths', cim_ccs.path,
**in_params)))[0]
@handle_cim_errors
- spc = self._get_cim_instance_by_id('AccessGroup', access_group.id)
- ccs = self._get_class_instance('CIM_ControllerConfigurationService',
- 'SystemName', access_group.system_id)
+ cim_ag = self._get_cim_instance_by_id('AccessGroup', access_group.id)
+ cim_ccs = self._get_class_instance(
+ 'CIM_ControllerConfigurationService',
+ 'SystemName', access_group.system_id)
hide_params = {'InitiatorPortIDs': [init_id],
- 'ProtocolControllers': [spc.path]}
+ 'ProtocolControllers': [cim_ag.path]}
return self._pi("HidePaths", Smis.JOB_RETRIEVE_NONE,
- *(self._c.InvokeMethod('HidePaths', ccs.path,
+ *(self._c.InvokeMethod('HidePaths', cim_ccs.path,
**hide_params)))[0]
@handle_cim_errors
"""
Frees the resources given a job number.
"""
- cim_job = self._get_cim_instance_by_id('Job', job_id)
+ cim_job = self._get_cim_instance_by_id('Job', job_id,
+ ['DeleteOnCompletion'])
# See if we should delete the job
pass
+ """
+ Please do the filter of "sytems=" in URI by yourself.
+ """
+ # We need to find out the vendor spaces.
+ # We do it here to save plugin_register() time.
+ # Only non-fallback mode can goes there.
+ cim_syss = self._root_cim_syss()
+ all_vendor_namespaces = []
+ all_vendor_namespaces.extend([cim_sys.path.namespace])
+ self.all_vendor_namespaces = all_vendor_namespaces
+ rc = []
+ rc.extend(
+ self._c.EnumerateInstances(
+ class_name,
+ namespace=vendor_namespace,
+ PropertyList=property_list,
+ LocalOnly=False))
+ return rc
+
@handle_cim_errors
"""
by ourself in case URI contain 'system=xxx'.
"""
rc = []
- cim_sys_pros = self._property_list_of_id("System")
self._profile_is_supported(SNIA.DISK_LITE_PROFILE,
SNIA.SMIS_SPEC_VER_1_4,
strict=False,
raise_error=True)
- cim_syss = self._root_cim_syss(cim_sys_pros)
-
- return []
-
- all_vendor_namespaces = []
- all_vendor_namespaces.extend([cim_sys.path.namespace])
-
cim_disk_pros = Smis._new_disk_cim_disk_pros(flags)
- cim_disks = self._c.EnumerateInstances(
- 'CIM_DiskDrive',
- namespace=vendor_namespace,
- PropertyList=cim_disk_pros)
- continue
- cim_ext_pros = Smis._new_disk_cim_ext_pros(flags)
- cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path,
- cim_ext_pros)
-
- rc.extend([self._new_disk(cim_disk, cim_ext, flags)])
+ cim_disks = self._enumerate('CIM_DiskDrive', cim_disk_pros)
+ continue
+ cim_ext_pros = Smis._new_disk_cim_ext_pros(flags)
+ cim_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path,
+ cim_ext_pros)
+
+ rc.extend([self._new_disk(cim_disk, cim_ext, flags)])
return search_property(rc, search_key, search_value)
@staticmethod
ResultClass='CIM_PhysicalPackage',
PropertyList=cim_phy_pkg_pros)
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Failed to find out the CIM_PhysicalPackage " +
"of CIM_DiskDrive %s" % cim_disk.path)
cim_phy_pkg = cim_phy_pkgs[0]
status_info,
cim_disk['ErrorDescription'])
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"CIM_DiskDrive %s " % cim_disk.id +
"has ErrorCleared == False but " +
"does not have " +
cim_pri_ext # The CIM_Instance of Primordial CIM_StorageExtent
LsmError
- ErrorNumber.INTERNAL_ERROR # Failed to find out pri cim_ext
+ ErrorNumber.LSM_BUG # Failed to find out pri cim_ext
"""
property_list = ['Primordial']
- property_list.extend(['Primordial'])
+ property_list = _merge_list(property_list, ['Primordial'])
cim_exts = self._c.Associators(
cim_disk_path,
# each CIM_DiskDrive
return cim_exts[0]
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Failed to find out Primordial " +
"CIM_StorageExtent for CIM_DiskDrive %s " %
cim_disk_path)
return None
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
+ raise LsmError(ErrorNumber.LSM_BUG,
"Found two or more CIM_DiskDrive associated to " +
"requested CIM_StorageExtent %s" %
cim_pri_ext_path)
"""
Delete a Pool via CIM_StorageConfigurationService.DeleteStoragePool
"""
- cim_sys_pros = self._property_list_of_id("System")
if not self.fallback_mode and \
self._profile_is_supported(SNIA.BLK_SRVS_PROFILE,
SNIA.SMIS_SPEC_VER_1_4,
(SNIA.BLK_SRVS_PROFILE,
SNIA.SMIS_SPEC_VER_1_4))
- cim_sys = self._cim_sys_of_id(pool.system_id)
- cim_pool = self._get_cim_pool_by_id(cim_sys.path, pool.id)
- cim_scs = self._get_cim_scs(cim_sys.path)
+ cim_pool = self._get_cim_instance_by_id('Pool', pool.id)
+ cim_scs = self._get_class_instance(
+ 'CIM_StorageConfigurationService',
+ 'SystemName', pool.system_id)
in_params = {'Pool': cim_pool.path}
(SNIA.BLK_SRVS_PROFILE,
SNIA.SMIS_SPEC_VER_1_4))
- cim_sys = self._cim_sys_of_id(system.id)
+ cim_sys = self._get_cim_instance_by_id('System', system.id)
# we does not support defining thinp_type yet.
# just using whatever provider set.
in_params['Goal'] = self._cim_st_path_for_goal(
raid_type, cim_sys.path)
- cim_scs = self._get_cim_scs(cim_sys.path)
+ cim_scs = self._get_class_instance(
+ 'CIM_StorageConfigurationService',
+ 'SystemName', system.id)
in_params = self._pool_chg_paras_check(in_params, cim_sys.path)
return self._pi("pool_create", Smis.JOB_RETRIEVE_POOL,
cim_scs.path, **in_params)))
@handle_cim_errors
- """
- Find out the Primordial CIM_StorageSetting of Disk.
- disk_ids # a list of Disk.id
- [a , b] # a list of items.
- or
- [] # disk_ids is NULL
- LsmError
- ErrorNumber.INVALID_DISK # Disk ID invalid.
- ErrorNumber.INVALID_DISK # No Disk found.
- """
- return []
- cim_disks = self._c.EnumerateInstances('CIM_DiskDrive',
- PropertyList=['SystemName',
- 'DeviceID'],
- LocalOnly=False)
- raise LsmError(ErrorNumber.INVALID_DISK, "No disk found")
-
- disk_id_2_cim = {}
- disk_id_2_cim[self._disk_id(cim_disk)] = cim_disk
-
- cim_pri_exts = []
- cim_disk = disk_id_2_cim[disk_id]
- cim_pri_ext = self._pri_cim_ext_of_cim_disk(cim_disk.path)
- cim_pri_exts.extend([cim_pri_ext])
- raise LsmError(ErrorNumber.INVALID_DISK,
- "Disk with ID %s cannot be found\n" % disk_id)
- return cim_pri_exts
-
"""
"type or add different RAID type tier")
return new_in_params
- """
- Find out the CIM_StorageConfigurationService base on
- CIM_ComputerSystem
- Base on SNIA SMI-S 1.6rev4, Block book, Clause 5: Block Services
- Package, Figure 8 - StoragePool Manipulation Instance Diagram
- This is only one CIM_StorageConfigurationService associated to
- CIM_ComputerSystem
- cim_sys_path # CIMInstanceName of CIM_ComputerSystem
- property_list # the list of properties required in return
- # CIMInstance
- cim_scs
- """
- pros = []
- pros = property_list
- cim_scss = self._c.Associators(
- cim_sys_path,
- ResultClass='CIM_StorageConfigurationService',
- PropertyList=pros)
- return cim_scss[0]
- raise LsmError(ErrorNumber.INTERNAL_ERROR,
- "Failed to find out " +
- "CIM_StorageConfigurationService of " +
- "CIM_ComputerSystem %s" % cim_sys_path)
-
def _profile_is_supported(self, profile_name, spec_ver, strict=False,
"""
this is assumption should work. Tested on EMC SMI-S provider which
provide 1.4, 1.5, 1.6 root profile.
"""
- property_list = self._property_list_of_id('System', property_list)
+ id_pros = self._property_list_of_id('System', property_list)
+ property_list = id_pros
+ property_list = _merge_list(property_list, id_pros)
cim_syss = []
return needed_cim_syss
return cim_syss
-
- """
- Return a CIMInstance of CIM_ComputerSystem for given system id.
- """
- property_list = self._property_list_of_id("System", property_list)
- cim_syss = self._root_cim_syss(property_list)
-
- return cim_sys
- raise LsmError(ErrorNumber.NOT_FOUND_SYSTEM,
- "System %s not found" % system_id)
-
- """
- Return a CIMInstance of CIM_StoragePool for given pool id.
- """
- property_list = self._property_list_of_id("Pool", property_list)
- cim_pools = self._cim_pools_of(cim_sys_path, property_list)
- return cim_pool
-
- raise LsmError(ErrorNumber.NOT_FOUND_POOL,
- "System %s not found" % pool_id)
diff --git a/plugin/targetd/targetd.py b/plugin/targetd/targetd.py
index a996d95..ed4c945 100644
--- a/plugin/targetd/targetd.py
+++ b/plugin/targetd/targetd.py
@@ -20,7 +20,7 @@
import copy
-from lsm import (Pool, Volume, System, Capabilities, Initiator,
+from lsm import (Pool, Volume, System, Capabilities,
IStorageAreaNetwork, INfs, FileSystem, FsSnapshot, NfsExport,
LsmError, ErrorNumber, uri_parse, md5, VERSION,
common_urllib2_error_handler, search_property,
lsm_ags = self.access_groups(flags=flags)
return [x for x in lsm_ags if x.id in ag_ids]
- inits = []
- for init in set(i['initiator_wwn']
- inits.append(Initiator(init, Initiator.TYPE_ISCSI, init))
-
- return inits
-
vol = [v for v in self._jsonrequest("vol_list", dict(pool=pool_id))
if v['name'] == volume_name][0]
return not self.volume_online(volume)
@handle_errors
- def iscsi_chap_auth(self, initiator, in_user, in_password, out_user,
+ def iscsi_chap_auth(self, init_id, in_user, in_password, out_user,
self._jsonrequest("initiator_set_auth",
- dict(initiator_wwn=initiator.id,
+ dict(initiator_wwn=init_id,
in_user=in_user,
in_pass=in_password,
out_user=out_user,
return None
@handle_errors
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- raise LsmError(ErrorNumber.NO_SUPPORT, "Not supported")
-
- # find lowest unused lun and use that
- used_luns = [x['lun'] for x in self._jsonrequest("export_list")]
- lun = 0
- lun += 1
- break
-
- self._jsonrequest("export_create",
- dict(pool=volume.pool_id,
- vol=volume.name,
- initiator_wwn=initiator_id, lun=lun))
-
- self._jsonrequest("export_destroy",
- dict(pool=volume.pool_id,
- vol=volume.name,
- initiator_wwn=initiator.id))
-
- exports = [x for x in self._jsonrequest("export_list")
- if initiator.id == x['initiator_wwn']]
-
- vols = []
- vols.append(Volume(export['vol_uuid'], export['vol_name'],
- export['vol_uuid'], 512,
- export['vol_size'] / 512,
- Volume.STATUS_OK, self.system.id,
- export['pool']))
-
- return vols
-
- exports = [x for x in self._jsonrequest("export_list")
- if volume.id == x['vol_uuid']]
-
- inits = []
- name = export['initiator_wwn']
- inits.append(Initiator(name, Initiator.TYPE_ISCSI, name))
-
- return inits
-
rc = []
diff --git a/plugin/v7k/ibmv7k.py b/plugin/v7k/ibmv7k.py
index bfe17ef..de63a99 100644
--- a/plugin/v7k/ibmv7k.py
+++ b/plugin/v7k/ibmv7k.py
@@ -17,7 +17,7 @@
import paramiko
-from lsm import (Capabilities, ErrorNumber, IStorageAreaNetwork, Initiator,
+from lsm import (Capabilities, ErrorNumber, IStorageAreaNetwork,
LsmError, Pool, System, VERSION, Volume, uri_parse,
search_property, AccessGroup)
return Initiator(lsm_init_id, lsm_init_type, v7k_init['name'])
- gi = self._get_initiators()
-
- v7k_init_id = None
- v7kinit = self._get_initiator(i['id'])
- v7k_init_id = v7kinit['id']
-
- if 'iscsi_name' in v7kinit and v7kinit['iscsi_name'] == \
- v7k_init_id = v7kinit['id']
-
- raise LsmError(ErrorNumber.NOT_FOUND_INITIATOR,
- "Initiator not found")
-
- return v7k_init_id
-
- # init_id passed is the lsm's init id. Convert it to v7k id.
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
-
- ssh_cmd = 'lshostvdiskmap -delim ! %s' % v7k_init_id
- return self._execute_command_and_parse_concise(ssh_cmd)
-
- ssh_cmd = 'lsvdiskhostmap -delim ! %s' % v
- return self._execute_command_and_parse_concise(ssh_cmd)
-
- type_option = '-hbawwpn'
- type_option = '-iscsiname'
- raise LsmError(ErrorNumber.UNSUPPORTED_INITIATOR_TYPE,
- "Initiator type not supported")
-
- ssh_cmd = 'mkhost %s %s' % (type_option, init_id)
- return self._execute_command(ssh_cmd)
-
- return True
- return False
-
- # init_id passed is the lsm's init id. Convert it to v7k id.
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
- # Auto add the initiator
- exit_code, stdout, stderr = self._initiator_create(init_id,
- init_type)
- # If success, get the v7k id for the new init
- # This should not cause an exception this time!
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
- raise LsmError(ErrorNumber.PLUGIN_ERROR,
- "Error creating initiator")
- raise le
-
- ssh_cmd = 'mkvdiskhostmap %s -host %s %s' % \
- ('-force' if force else '', v7k_init_id, vol_id)
- return self._execute_command(ssh_cmd)
-
- return True
- return False
-
- ssh_cmd = 'rmhost %s %s' % ('-force' if force else '', v7k_init_id)
- self._execute_command(ssh_cmd)
-
- # init_id passed is the lsm's init id. Convert it to v7k id.
- v7k_init_id = self._map_lsm_init_id_to_v7k(init_id)
-
- ssh_cmd = 'rmvdiskhostmap -host %s %s' % (v7k_init_id, vol_id)
- self._execute_command(ssh_cmd)
-
- # Auto remove initiator (if no mapping present)
- # v7k rmhost raises exception, if host is being removed with mappings
- # present... unless -force is specified. So exploit that fact here.
- self._initiator_delete(v7k_init_id, force=False)
- pass
-
- return
-
self.password = password
self.tmo = timeout
[self._volume(v) for v in gv.itervalues()],
search_key, search_value)
- init_list = []
- gi = self._get_initiators()
- init = self._get_initiator(i['id'])
- init_list.append(self._initiator(init))
- return init_list
-
@staticmethod
lsm_init_id = None
# TODO: How to pass -force param ? For now, assume -force
self._delete_volume(volume.id, force=True)
return None
-
- def initiator_grant(self, initiator_id, initiator_type, volume, access,
- # TODO: How to pass -force param ? For now, assume -force.
- # -force allows multiple vdisk-to-host assignments,
- # which are not normally allowed
-
- # NOTE: V7000 doesn't provide a way to pass access param,
- # access is always rw, if ro, raise error.
- raise LsmError(ErrorNumber.NO_SUPPORT,
- "Only RW access to the volume is supported")
-
- exit_code, stdout, stderr = self._initiator_grant(initiator_id,
- initiator_type,
- volume.id,
- force=True)
- return self._initiator_grant_is_success(stdout)
-
- self._initiator_revoke(initiator.id, volume.id)
- return
-
- gvabi = self._get_volumes_accessible_by_initiator(initiator.id)
-
- vol_list = []
- gv = self._get_volume(vol['vdisk_id'])
- v = self._volume(gv)
- vol_list.append(v)
-
- return vol_list
-
- gigtv = self._get_initiators_granted_to_volume(volume.id)
-
- init_list = []
- gi = self._get_initiator(init['host_id'])
- i = self._initiator(gi)
- init_list.append(i)
-
- return init_list
Gris Ge
2014-06-17 12:47:34 UTC
Permalink
* Removed these lsmcli commands:
list --type INITIATORS
access-revoke
access-grant
volumes-accessible-initiator
initiators-granted-volume
volume-access-group
# Replaced by "list --type VOLUMES --ag <AG_ID>"
# It's much easier to understand what type of resource you are requesting.
access-group-volume
# Replaced by "list --type ACCESS_GROUPS --vol <VOL_ID>"

* Renamed these lsmcli commands:
access-group-add -> ag-add-init
access-group-remove -> ag-del-init
# Just make commands shorter and less confusing.

* Manpage updated.

Signed-off-by: Gris Ge <***@redhat.com>
---
doc/man/lsmcli.1.in | 58 ++----------
tools/lsmcli/cmdline.py | 210 ++++++++-----------------------------------
tools/lsmcli/data_display.py | 50 +----------
3 files changed, 48 insertions(+), 270 deletions(-)

diff --git a/doc/man/lsmcli.1.in b/doc/man/lsmcli.1.in
index 96f1725..697ec75 100644
--- a/doc/man/lsmcli.1.in
+++ b/doc/man/lsmcli.1.in
@@ -155,7 +155,7 @@ List information on LSM objects
\fB--type\fR \fI<TYPE>\fR
Required. Valid values are:
.br
-\fBVOLUMES\fR, \fBINITIATORS\fR, \fBPOOLS\fR, \fBFS\fR, \fBSNAPSHOTS\fR,
+\fBVOLUMES\fR, \fBPOOLS\fR, \fBFS\fR, \fBSNAPSHOTS\fR,
\fBEXPORTS\fR, \fBDISKS\fR,
.br
\fBNFS_CLIENT_AUTH\fR, \fBACCESS_GROUPS\fR,
@@ -181,6 +181,9 @@ resources: \fBVOLUMES\fR, \fBPOOLS\fR, \fBFS\fR.
\fB--vol\fR \fI<VOL_ID>\fR
Search resources from volume with VOL_ID. Only supported by these types of
resources: \fBVOLUMES\fR, \fBACCESS_GROUPS\fR.
+.br
+To query volume maksing status, please use this command:
+ lsmcli list --type ACCESS_GROUPS --vol <VOL_ID>
.TP
\fB--disk\fR \fI<DISK_ID>\fR
Search resources from disk with DISK_ID. Only supported by these types of
@@ -189,6 +192,9 @@ resources: \fBDISK\fR.
\fB--ag\fR \fI<AG_ID>\fR
Search resources from access group with AG_ID. Only supported by these types
of resources: \fBACCESS_GROUPS\fR, \fBVOLUMES\fR.
+.br
+To query volume maksing status, please use this command:
+ lsmcli list --type VOLUMES --ag <AG_ID>
.TP
\fB--fs\fR \fI<FS_ID>\fR
Search resources from file system with FS_ID. Only supported by these types
@@ -317,18 +323,6 @@ Removes volume dependencies(like replication).
\fB--vol\fR \fI<VOL_ID>\fR
Required. The ID of volume to remove dependency.

-.SS volume-access-group
-Lists the access group(s) that have access to the provided volume.
-.TP 15
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to query access.
-
-.SS volumes-accessible-initiator
-Lists the initiator(s) that have access to the provided volume.
-.TP 15
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to query access.
-
.SS volume-mask
.TP 15
Grant access group RW access to certain volume. Like LUN masking
@@ -367,7 +361,7 @@ Required. The initiator type. Valid values are: \fBWWPN\fR, \fBWWNN\fR,
\fB--sys\fR \fI<SYS_ID>\fR
Required. The ID of system where this access group should reside on.

-.SS access-group-add
+.SS ag-add-init
Adds an initiator to an access group.
.TP 15
\fB--ag\fR \fI<AG_ID>\fR
@@ -380,7 +374,7 @@ Required. ID of initiator to add.
Required. The initiator type. Valid values are: \fBWWPN\fR, \fBWWNN\fR,
\fBISCSI\fR, \fBHOSTNAME\fR, \fBSAS\fR.

-.SS access-group-remove
+.SS ag-del-init
Removes an initiator from an access group.
.TP 15
\fB--ag\fR \fI<AG_ID>\fR
@@ -395,40 +389,6 @@ Delete an access group.
\fB--ag\fR \fI<AG_ID>\fR
Required. ID of access group to delete.

-.SS access-grant
-Grants access to an initiator to a volume
-.TP 15
-\fB--init\fR \fI<INIT_ID>\fR
-Required. ID of initiator to grant access.
-.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.
-.TP
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to grant access.
-
-.SS access-revoke
-Removes access for an initiator to a volume
-.TP 15
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to revoke.
-.TP
-\fB--init\fR \fI<INIT_ID>\fR
-Required. ID of initiator to revoke.
-
-.SS access-group-volumes
-Lists the volumes that the access group has been granted access to.
-.TP 15
-\fB--ag\fR \fI<AG_ID>\fR
-Required. The ID of access group to query.
-
-.SS initiators-granted-volume
-Lists the initiators that have been granted access to specified volume
-.TP 15
-\fB--init\fR \fI<INIT_ID>\fR
-Required. The ID of initiator to query.
-
.SS iscsi-chap
Configures ISCSI inbound/outbound CHAP authentication
.TP 15
diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index ef3561b..27c673f 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -27,7 +27,7 @@ from argparse import ArgumentParser
from argparse import RawTextHelpFormatter

from lsm import (Client, Pool, VERSION, LsmError, Capabilities, Disk,
- Initiator, Volume, JobStatus, ErrorNumber, BlockRange,
+ Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
AccessGroup, FileSystem, NfsExport, System, FsSnapshot)

@@ -35,7 +35,7 @@ from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
pool_raid_type_str_to_type, pool_member_type_str_to_type,
vol_provision_str_to_type, vol_rep_type_str_to_type,
- vol_access_type_str_to_type, ag_init_type_str_to_lsm)
+ ag_init_type_str_to_lsm)


## Wraps the invocation to the command line
@@ -89,25 +89,26 @@ class ArgError(Exception):
# @param the_id the id to match
# @param friendly_name - name to put in the exception saying what we
# couldn't find
-def _get_item(l, the_id, friendly_name='item'):
+def _get_item(l, the_id, friendly_name='item', raise_error=True):
for item in l:
if item.id == the_id:
return item
- raise ArgError('%s with id %s not found!' % (friendly_name, the_id))
+ if raise_error:
+ raise ArgError('%s with id %s not found!' % (friendly_name, the_id))
+ else:
+ return None

-list_choices = ['VOLUMES', 'INITIATORS', 'POOLS', 'FS', 'SNAPSHOTS',
+list_choices = ['VOLUMES', 'POOLS', 'FS', 'SNAPSHOTS',
'EXPORTS', "NFS_CLIENT_AUTH", 'ACCESS_GROUPS',
'SYSTEMS', 'DISKS', 'PLUGINS']

-initiator_id_types = ('WWPN', 'WWNN', 'ISCSI', 'HOSTNAME', 'SAS')
-initiator_id_help = "Initiator ID type: " + ", ".join(initiator_id_types)
+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)

-access_types = ('RO', 'RW')
-access_help = "Access type: %s. Default value is RW." % ", ".join(access_types)
-
replicate_types = ('SNAPSHOT', 'CLONE', 'COPY', 'MIRROR_ASYNC', 'MIRROR_SYNC')
replicate_help = "replication type: " + ", ".join(replicate_types)

@@ -167,11 +168,9 @@ disk_id_filter_opt = dict(name='--disk', metavar='<DISK_ID>',
help='Search by Disk ID')

size_opt = dict(name='--size', metavar='<SIZE>', help=size_help)
-access_opt = dict(name='--access', metavar='<ACCESS>', help=access_help,
- choices=access_types, type=str.upper)

-init_type_opt = dict(name="--init-type", help=initiator_id_help,
- metavar='<INIT_TYPE>', choices=initiator_id_types,
+init_type_opt = dict(name="--init-type", help=init_id_help,
+ metavar='<INIT_TYPE>', choices=init_types,
type=str.upper)

cmds = (
@@ -326,23 +325,6 @@ cmds = (
),

dict(
- name='volume-access-group',
- help='Lists the access group(s) that have access to volume',
- args=[
- dict(vol_id_opt),
- ],
- ),
-
- dict(
- name='volumes-accessible-initiator',
- help='Lists the volumes that are accessible by the initiator',
- args=[
- dict(init_id_opt),
- ],
- ),
-
-
- dict(
name='volume-mask',
help='Grants access to an access group to a volume, '
'like LUN Masking',
@@ -355,9 +337,9 @@ cmds = (
help='Initiator ID, only used when access-group-create is '
'not supported'),
dict(name="--init-type", type=str.upper,
- metavar='<INIT_TYPE>', choices=initiator_id_types,
+ metavar='<INIT_TYPE>', choices=init_types,
help="%s only used when access-group-create is not supported"
- % initiator_id_help),
+ % init_id_help),
],
),

@@ -385,7 +367,7 @@ cmds = (
),

dict(
- name='access-group-add',
+ name='ag-add-init',
help='Add an initiator into existing access group',
args=[
dict(ag_id_opt),
@@ -394,7 +376,7 @@ cmds = (
],
),
dict(
- name='access-group-remove',
+ name='ag-del-init',
help='Remove an initiator from existing access group',
args=[
dict(ag_id_opt),
@@ -411,46 +393,6 @@ cmds = (
),

dict(
- name='access-grant',
- help='Grants access to an initiator to a volume',
- args=[
- dict(init_id_opt),
- dict(init_type_opt),
- dict(vol_id_opt),
- ],
- optional=[
- dict(access_opt),
- ],
- ),
-
- dict(
- name='access-revoke',
- help='Removes access for an initiator to a volume',
- args=[
- dict(init_id_opt),
- dict(vol_id_opt),
- ],
- ),
-
- dict(
- name='access-group-volumes',
- help='Lists the volumes that the access group has'
- ' been granted access to',
- args=[
- dict(ag_id_opt),
- ],
- ),
-
- dict(
- name='initiators-granted-volume',
- help='Lists the initiators that have been '
- 'granted access to specified volume',
- args=[
- dict(vol_id_opt),
- ],
- ),
-
- dict(
name='iscsi-chap',
help='Configures iSCSI inbound/outbound CHAP authentication',
args=[
@@ -955,9 +897,12 @@ class CmdLine:
search_key = 'id'
if search_key == 'access_group_id':
lsm_ag = _get_item(self.c.access_groups(), args.ag,
- "Access Group ID")
- return self.display_data(
- self.c.volumes_accessible_by_access_group(lsm_ag, flags))
+ "Access Group ID", raise_error=False)
+ if lsm_ag:
+ return self.display_data(
+ self.c.volumes_accessible_by_access_group(lsm_ag, flags))
+ else:
+ return self.display_data([])
elif search_key and search_key not in Volume.SUPPORTED_SEARCH_KEYS:
raise ArgError("Search key '%s' is not supported by "
"volume listing." % search_key)
@@ -990,8 +935,6 @@ class CmdLine:
flags |= FsSnapshot.FLAG_RETRIEVE_FULL_INFO
fs = _get_item(self.c.fs(), args.fs, 'filesystem')
self.display_data(self.c.fs_snapshots(fs, flags))
- elif args.type == 'INITIATORS':
- self.display_data(self.c.initiators())
elif args.type == 'EXPORTS':
if args.optional:
flags |= NfsExport.FLAG_RETRIEVE_FULL_INFO
@@ -1011,9 +954,12 @@ class CmdLine:
search_key = 'id'
if search_key == 'volume_id':
lsm_vol = _get_item(self.c.volumes(), args.vol,
- "Volume ID")
- return self.display_data(
- self.c.access_groups_granted_to_volume(lsm_vol, flags))
+ "Volume ID", raise_error=False)
+ if lsm_vol:
+ return self.display_data(
+ self.c.access_groups_granted_to_volume(lsm_vol, flags))
+ else:
+ return self.display_data([])
elif search_key and \
search_key not in AccessGroup.SUPPORTED_SEARCH_KEYS:
raise ArgError("Search key '%s' is not supported by "
@@ -1041,80 +987,36 @@ class CmdLine:
else:
raise ArgError("unsupported listing type=%s" % args.type)

- ## Converts type initiator type to enumeration type.
- # @param type String representation of type
- # @returns Enumerated value
- @staticmethod
- def _init_type_to_enum(init_type):
- if init_type == 'WWPN':
- init = Initiator.TYPE_PORT_WWN
- elif init_type == 'WWNN':
- init = Initiator.TYPE_NODE_WWN
- elif init_type == 'ISCSI':
- init = Initiator.TYPE_ISCSI
- elif init_type == 'HOSTNAME':
- init = Initiator.TYPE_HOSTNAME
- elif init_type == 'SAS':
- init = Initiator.TYPE_SAS
- else:
- raise ArgError("invalid initiator type " + init_type)
- return init
-
## Creates an access group.
def access_group_create(self, args):
- init_enum = CmdLine._init_type_to_enum(args.init_type)
+ init_type = ag_init_type_str_to_lsm(args.init_type)
access_group = self.c.access_group_create(args.name, args.init,
- init_enum, args.sys)
+ init_type, args.sys)
self.display_data([access_group])

def _add_rm_access_grp_init(self, args, op):
- agl = self.c.access_groups()
- group = _get_item(agl, args.ag, "access group id")
+ lsm_ag = _get_item(self.c.access_groups(), args.ag, "access group id")

if op:
- init = CmdLine._init_type_to_enum(args.init_type)
- self.c.access_group_initiator_add(
- group, args.init, init)
+ init_type = ag_init_type_str_to_lsm(args.init_type)
+ self.c.access_group_initiator_add(lsm_ag, args.init, init_type)
else:
- init = _get_item(self.c.initiators(), args.init, "initiator id")
- self.c.access_group_initiator_delete(group, init.id)
+ self.c.access_group_initiator_delete(lsm_ag, args.init)

## Adds an initiator from an access group
- def access_group_add(self, args):
+ def ag_add_init(self, args):
self._add_rm_access_grp_init(args, True)

## Removes an initiator from an access group
- def access_group_remove(self, args):
+ def ag_del_init(self, args):
self._add_rm_access_grp_init(args, False)

- def access_group_volumes(self, args):
- agl = self.c.access_groups()
- group = _get_item(agl, args.ag, "access group id")
- vols = self.c.volumes_accessible_by_access_group(group)
- self.display_data(vols)
-
- def volumes_accessible_initiator(self, args):
- init = _get_item(self.c.initiators(), args.init, "initiator id")
- volumes = self.c.volumes_accessible_by_initiator(init)
- self.display_data(volumes)
-
- def initiators_granted_volume(self, args):
- vol = _get_item(self.c.volumes(), args.vol, "volume id")
- initiators = self.c.initiators_granted_to_volume(vol)
- self.display_data(initiators)
-
def iscsi_chap(self, args):
- init = _get_item(self.c.initiators(), args.init, "initiator id")
- self.c.iscsi_chap_auth(init, args.in_user,
+ self.c.iscsi_chap_auth(args.init, args.in_user,
self.args.in_pass,
self.args.out_user,
self.args.out_pass)

- def volume_access_group(self, args):
- vol = _get_item(self.c.volumes(), args.vol, "volume id")
- groups = self.c.access_groups_granted_to_volume(vol)
- self.display_data(groups)
-
## Used to delete access group
def access_group_delete(self, args):
agl = self.c.access_groups()
@@ -1203,9 +1105,6 @@ class CmdLine:
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("INITIATORS", cap.supported(Capabilities.INITIATORS))
- self._cp("INITIATORS_GRANTED_TO_VOLUME",
- cap.supported(Capabilities.INITIATORS_GRANTED_TO_VOLUME))
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))
@@ -1230,10 +1129,6 @@ class CmdLine:
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_INITIATOR_GRANT",
- cap.supported(Capabilities.VOLUME_INITIATOR_GRANT))
- self._cp("VOLUME_INITIATOR_REVOKE",
- cap.supported(Capabilities.VOLUME_INITIATOR_REVOKE))
self._cp("VOLUME_THIN",
cap.supported(Capabilities.VOLUME_THIN))
self._cp("VOLUME_ISCSI_CHAP_AUTHENTICATION",
@@ -1255,8 +1150,6 @@ class CmdLine:
self._cp("VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP",
cap.supported(
Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP))
- self._cp("VOLUME_ACCESSIBLE_BY_INITIATOR",
- cap.supported(Capabilities.VOLUME_ACCESSIBLE_BY_INITIATOR))
self._cp("ACCESS_GROUPS_GRANTED_TO_VOLUME",
cap.supported(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME))
self._cp("VOLUME_CHILD_DEPENDENCY",
@@ -1468,33 +1361,6 @@ class CmdLine:
s = _get_item(self.c.systems(), args.sys, "system id")
out(self.c.volume_replicate_range_block_size(s))

- ## Used to grant or revoke access to a volume to an initiator.
- # @param grant bool, if True we grant, else we un-grant.
- def _access(self, grant, args):
- v = _get_item(self.c.volumes(), args.vol, "volume id")
- initiator_id = args.init
-
- if grant:
- i_type = CmdLine._init_type_to_enum(args.init_type)
- access = 'DEFAULT'
- if args.access is not None:
- access = vol_access_type_str_to_type(args.access)
-
- self.c.initiator_grant(initiator_id, i_type, v, access)
- else:
- initiator = _get_item(self.c.initiators(), initiator_id,
- "initiator id")
-
- self.c.initiator_revoke(initiator, v)
-
- ## Grant access to volume to an initiator
- def access_grant(self, args):
- return self._access(True, args)
-
- ## Revoke access to volume to an initiator
- def access_revoke(self, args):
- return self._access(False, args)
-
def volume_mask(self, args):
if not args.ag and not args.init:
raise ArgError('Neither --ag nor --init is defined. '
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 685e119..ba79de2 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -20,7 +20,7 @@ from collections import OrderedDict
from datetime import datetime

from lsm import (size_bytes_2_size_human, LsmError, ErrorNumber,
- System, Pool, Disk, Volume, AccessGroup, Initiator,
+ System, Pool, Disk, Volume, AccessGroup,
FileSystem, FsSnapshot, NfsExport)

BIT_MAP_STRING_SPLITTER = ','
@@ -243,16 +243,6 @@ def vol_rep_type_str_to_type(vol_rep_type_str):
return _str_to_enum(vol_rep_type_str, _VOL_REP_TYPE_CONV)


-_VOL_ACCESS_TYPE_CONV = {
- Volume.ACCESS_READ_WRITE: 'RW',
- Volume.ACCESS_READ_ONLY: 'RO'
-}
-
-
-def vol_access_type_str_to_type(vol_access_type_str):
- return _str_to_enum(vol_access_type_str, _VOL_ACCESS_TYPE_CONV)
-
-
def vol_status_to_str(vol_status):
return _bit_map_to_str(vol_status, _VOL_STATUS_CONV)

@@ -296,20 +286,6 @@ def disk_status_to_str(disk_status):
return _bit_map_to_str(disk_status, _DISK_STATUS_CONV)


-_INIT_TYPE_CONV = {
- Initiator.TYPE_OTHER: 'Other',
- Initiator.TYPE_PORT_WWN: 'Port WWN',
- Initiator.TYPE_NODE_WWN: 'Node WWN',
- Initiator.TYPE_HOSTNAME: 'Hostname',
- Initiator.TYPE_ISCSI: 'iSCSI',
- Initiator.TYPE_SAS: "SAS"
-}
-
-
-def init_type_to_str(init_type):
- return _enum_type_to_str(init_type, _INIT_TYPE_CONV)
-
-
_AG_INIT_TYPE_CONV = {
AccessGroup.INIT_TYPE_UNKNOWN: 'Unknown',
AccessGroup.INIT_TYPE_OTHER: 'Other',
@@ -535,30 +511,6 @@ class DisplayData(object):
'value_conv_human': AG_VALUE_CONV_HUMAN,
}

- # lsm.Initiator
- INIT_MAN_HEADER = OrderedDict()
- INIT_MAN_HEADER['id'] = 'ID'
- INIT_MAN_HEADER['name'] = 'Name'
- INIT_MAN_HEADER['type'] = 'Initiator Type'
-
- INIT_COLUMN_KEYS = INIT_MAN_HEADER.keys()
-
- INIT_OPT_HEADER = OrderedDict()
-
- INIT_VALUE_CONV_ENUM = {
- 'type': init_type_to_str,
- }
-
- INIT_VALUE_CONV_HUMAN = []
-
- VALUE_CONVERT[Initiator] = {
- 'mandatory_headers': INIT_MAN_HEADER,
- 'column_keys': INIT_COLUMN_KEYS,
- 'optional_headers': INIT_OPT_HEADER,
- 'value_conv_enum': INIT_VALUE_CONV_ENUM,
- 'value_conv_human': INIT_VALUE_CONV_HUMAN,
- }
-
# lsm.FileSystem
FS_MAN_HEADER = OrderedDict()
FS_MAN_HEADER['id'] = 'ID'
--
1.8.3.1
Tony Asleson
2014-06-17 22:30:00 UTC
Permalink
Post by Gris Ge
list --type INITIATORS
access-revoke
access-grant
volumes-accessible-initiator
initiators-granted-volume
volume-access-group
# Replaced by "list --type VOLUMES --ag <AG_ID>"
# It's much easier to understand what type of resource you are requesting.
access-group-volume
# Replaced by "list --type ACCESS_GROUPS --vol <VOL_ID>"
The man page and help text need to be expanded to include this
functionality.
Post by Gris Ge
access-group-add -> ag-add-init
access-group-remove -> ag-del-init
# Just make commands shorter and less confusing.
These should be noun-verb. If we are going to shorten these, I would
prefer we shorten all the access group commands to match so that they
are consistent. Also we previously decided to use 'delete' not 'del'.

access-group-create -> ag-create
access-group-delete -> ag-delete
ag-add-init -> ag-init-add
ag-del-init -> ag-init-delete

Regards,
Tony
Gris Ge
2014-06-18 13:34:04 UTC
Permalink
Post by Tony Asleson
Post by Gris Ge
volume-access-group
# Replaced by "list --type VOLUMES --ag <AG_ID>"
# It's much easier to understand what type of resource you are requesting.
access-group-volume
# Replaced by "list --type ACCESS_GROUPS --vol <VOL_ID>"
The man page and help text need to be expanded to include this
functionality.
Manpage already included:
To query volume maksing status, please use this command:
lsmcli --type VOLUMES --ag <AG_ID>
Post by Tony Asleson
These should be noun-verb. If we are going to shorten these, I would
prefer we shorten all the access group commands to match so that they
are consistent. Also we previously decided to use 'delete' not 'del'.
access-group-create -> ag-create
access-group-delete -> ag-delete
ag-add-init -> ag-init-add
ag-del-init -> ag-init-delete
Will update it once we get holding patches committed.
Post by Tony Asleson
Regards,
Tony
--
Gris Ge
Tony Asleson
2014-06-18 21:44:30 UTC
Permalink
Patch *not* committed.

However, parts of this patch were needed to keep things working so the
needed parts got committed in a patch included in one of my patch sets.

Thanks,
Tony
Post by Gris Ge
list --type INITIATORS
access-revoke
access-grant
volumes-accessible-initiator
initiators-granted-volume
volume-access-group
# Replaced by "list --type VOLUMES --ag <AG_ID>"
# It's much easier to understand what type of resource you are requesting.
access-group-volume
# Replaced by "list --type ACCESS_GROUPS --vol <VOL_ID>"
access-group-add -> ag-add-init
access-group-remove -> ag-del-init
# Just make commands shorter and less confusing.
* Manpage updated.
---
doc/man/lsmcli.1.in | 58 ++----------
tools/lsmcli/cmdline.py | 210 ++++++++-----------------------------------
tools/lsmcli/data_display.py | 50 +----------
3 files changed, 48 insertions(+), 270 deletions(-)
diff --git a/doc/man/lsmcli.1.in b/doc/man/lsmcli.1.in
index 96f1725..697ec75 100644
--- a/doc/man/lsmcli.1.in
+++ b/doc/man/lsmcli.1.in
@@ -155,7 +155,7 @@ List information on LSM objects
\fB--type\fR \fI<TYPE>\fR
.br
-\fBVOLUMES\fR, \fBINITIATORS\fR, \fBPOOLS\fR, \fBFS\fR, \fBSNAPSHOTS\fR,
+\fBVOLUMES\fR, \fBPOOLS\fR, \fBFS\fR, \fBSNAPSHOTS\fR,
\fBEXPORTS\fR, \fBDISKS\fR,
.br
\fBNFS_CLIENT_AUTH\fR, \fBACCESS_GROUPS\fR,
@@ -181,6 +181,9 @@ resources: \fBVOLUMES\fR, \fBPOOLS\fR, \fBFS\fR.
\fB--vol\fR \fI<VOL_ID>\fR
Search resources from volume with VOL_ID. Only supported by these types of
resources: \fBVOLUMES\fR, \fBACCESS_GROUPS\fR.
+.br
+ lsmcli list --type ACCESS_GROUPS --vol <VOL_ID>
.TP
\fB--disk\fR \fI<DISK_ID>\fR
Search resources from disk with DISK_ID. Only supported by these types of
@@ -189,6 +192,9 @@ resources: \fBDISK\fR.
\fB--ag\fR \fI<AG_ID>\fR
Search resources from access group with AG_ID. Only supported by these types
of resources: \fBACCESS_GROUPS\fR, \fBVOLUMES\fR.
+.br
+ lsmcli list --type VOLUMES --ag <AG_ID>
.TP
\fB--fs\fR \fI<FS_ID>\fR
Search resources from file system with FS_ID. Only supported by these types
@@ -317,18 +323,6 @@ Removes volume dependencies(like replication).
\fB--vol\fR \fI<VOL_ID>\fR
Required. The ID of volume to remove dependency.
-.SS volume-access-group
-Lists the access group(s) that have access to the provided volume.
-.TP 15
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to query access.
-
-.SS volumes-accessible-initiator
-Lists the initiator(s) that have access to the provided volume.
-.TP 15
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to query access.
-
.SS volume-mask
.TP 15
Grant access group RW access to certain volume. Like LUN masking
@@ -367,7 +361,7 @@ Required. The initiator type. Valid values are: \fBWWPN\fR, \fBWWNN\fR,
\fB--sys\fR \fI<SYS_ID>\fR
Required. The ID of system where this access group should reside on.
-.SS access-group-add
+.SS ag-add-init
Adds an initiator to an access group.
.TP 15
\fB--ag\fR \fI<AG_ID>\fR
@@ -380,7 +374,7 @@ Required. ID of initiator to add.
Required. The initiator type. Valid values are: \fBWWPN\fR, \fBWWNN\fR,
\fBISCSI\fR, \fBHOSTNAME\fR, \fBSAS\fR.
-.SS access-group-remove
+.SS ag-del-init
Removes an initiator from an access group.
.TP 15
\fB--ag\fR \fI<AG_ID>\fR
@@ -395,40 +389,6 @@ Delete an access group.
\fB--ag\fR \fI<AG_ID>\fR
Required. ID of access group to delete.
-.SS access-grant
-Grants access to an initiator to a volume
-.TP 15
-\fB--init\fR \fI<INIT_ID>\fR
-Required. ID of initiator to grant access.
-.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.
-.TP
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to grant access.
-
-.SS access-revoke
-Removes access for an initiator to a volume
-.TP 15
-\fB--vol\fR \fI<VOL_ID>\fR
-Required. The ID of volume to revoke.
-.TP
-\fB--init\fR \fI<INIT_ID>\fR
-Required. ID of initiator to revoke.
-
-.SS access-group-volumes
-Lists the volumes that the access group has been granted access to.
-.TP 15
-\fB--ag\fR \fI<AG_ID>\fR
-Required. The ID of access group to query.
-
-.SS initiators-granted-volume
-Lists the initiators that have been granted access to specified volume
-.TP 15
-\fB--init\fR \fI<INIT_ID>\fR
-Required. The ID of initiator to query.
-
.SS iscsi-chap
Configures ISCSI inbound/outbound CHAP authentication
.TP 15
diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index ef3561b..27c673f 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -27,7 +27,7 @@ from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
from lsm import (Client, Pool, VERSION, LsmError, Capabilities, Disk,
- Initiator, Volume, JobStatus, ErrorNumber, BlockRange,
+ Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
AccessGroup, FileSystem, NfsExport, System, FsSnapshot)
@@ -35,7 +35,7 @@ from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
pool_raid_type_str_to_type, pool_member_type_str_to_type,
vol_provision_str_to_type, vol_rep_type_str_to_type,
- vol_access_type_str_to_type, ag_init_type_str_to_lsm)
+ ag_init_type_str_to_lsm)
## Wraps the invocation to the command line
# couldn't find
return item
- raise ArgError('%s with id %s not found!' % (friendly_name, the_id))
+ raise ArgError('%s with id %s not found!' % (friendly_name, the_id))
+ return None
-list_choices = ['VOLUMES', 'INITIATORS', 'POOLS', 'FS', 'SNAPSHOTS',
+list_choices = ['VOLUMES', 'POOLS', 'FS', 'SNAPSHOTS',
'EXPORTS', "NFS_CLIENT_AUTH", 'ACCESS_GROUPS',
'SYSTEMS', 'DISKS', 'PLUGINS']
-initiator_id_types = ('WWPN', 'WWNN', 'ISCSI', 'HOSTNAME', 'SAS')
-initiator_id_help = "Initiator ID type: " + ", ".join(initiator_id_types)
+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)
-access_types = ('RO', 'RW')
-access_help = "Access type: %s. Default value is RW." % ", ".join(access_types)
-
replicate_types = ('SNAPSHOT', 'CLONE', 'COPY', 'MIRROR_ASYNC', 'MIRROR_SYNC')
replicate_help = "replication type: " + ", ".join(replicate_types)
@@ -167,11 +168,9 @@ disk_id_filter_opt = dict(name='--disk', metavar='<DISK_ID>',
help='Search by Disk ID')
size_opt = dict(name='--size', metavar='<SIZE>', help=size_help)
-access_opt = dict(name='--access', metavar='<ACCESS>', help=access_help,
- choices=access_types, type=str.upper)
-init_type_opt = dict(name="--init-type", help=initiator_id_help,
- metavar='<INIT_TYPE>', choices=initiator_id_types,
+init_type_opt = dict(name="--init-type", help=init_id_help,
+ metavar='<INIT_TYPE>', choices=init_types,
type=str.upper)
cmds = (
@@ -326,23 +325,6 @@ cmds = (
),
dict(
- name='volume-access-group',
- help='Lists the access group(s) that have access to volume',
- args=[
- dict(vol_id_opt),
- ],
- ),
-
- dict(
- name='volumes-accessible-initiator',
- help='Lists the volumes that are accessible by the initiator',
- args=[
- dict(init_id_opt),
- ],
- ),
-
-
- dict(
name='volume-mask',
help='Grants access to an access group to a volume, '
'like LUN Masking',
@@ -355,9 +337,9 @@ cmds = (
help='Initiator ID, only used when access-group-create is '
'not supported'),
dict(name="--init-type", type=str.upper,
- metavar='<INIT_TYPE>', choices=initiator_id_types,
+ metavar='<INIT_TYPE>', choices=init_types,
help="%s only used when access-group-create is not supported"
- % initiator_id_help),
+ % init_id_help),
],
),
@@ -385,7 +367,7 @@ cmds = (
),
dict(
- name='access-group-add',
+ name='ag-add-init',
help='Add an initiator into existing access group',
args=[
dict(ag_id_opt),
@@ -394,7 +376,7 @@ cmds = (
],
),
dict(
- name='access-group-remove',
+ name='ag-del-init',
help='Remove an initiator from existing access group',
args=[
dict(ag_id_opt),
@@ -411,46 +393,6 @@ cmds = (
),
dict(
- name='access-grant',
- help='Grants access to an initiator to a volume',
- args=[
- dict(init_id_opt),
- dict(init_type_opt),
- dict(vol_id_opt),
- ],
- optional=[
- dict(access_opt),
- ],
- ),
-
- dict(
- name='access-revoke',
- help='Removes access for an initiator to a volume',
- args=[
- dict(init_id_opt),
- dict(vol_id_opt),
- ],
- ),
-
- dict(
- name='access-group-volumes',
- help='Lists the volumes that the access group has'
- ' been granted access to',
- args=[
- dict(ag_id_opt),
- ],
- ),
-
- dict(
- name='initiators-granted-volume',
- help='Lists the initiators that have been '
- 'granted access to specified volume',
- args=[
- dict(vol_id_opt),
- ],
- ),
-
- dict(
name='iscsi-chap',
help='Configures iSCSI inbound/outbound CHAP authentication',
args=[
search_key = 'id'
lsm_ag = _get_item(self.c.access_groups(), args.ag,
- "Access Group ID")
- return self.display_data(
- self.c.volumes_accessible_by_access_group(lsm_ag, flags))
+ "Access Group ID", raise_error=False)
+ return self.display_data(
+ self.c.volumes_accessible_by_access_group(lsm_ag, flags))
+ return self.display_data([])
raise ArgError("Search key '%s' is not supported by "
"volume listing." % search_key)
flags |= FsSnapshot.FLAG_RETRIEVE_FULL_INFO
fs = _get_item(self.c.fs(), args.fs, 'filesystem')
self.display_data(self.c.fs_snapshots(fs, flags))
- self.display_data(self.c.initiators())
flags |= NfsExport.FLAG_RETRIEVE_FULL_INFO
search_key = 'id'
lsm_vol = _get_item(self.c.volumes(), args.vol,
- "Volume ID")
- return self.display_data(
- self.c.access_groups_granted_to_volume(lsm_vol, flags))
+ "Volume ID", raise_error=False)
+ return self.display_data(
+ self.c.access_groups_granted_to_volume(lsm_vol, flags))
+ return self.display_data([])
elif search_key and \
raise ArgError("Search key '%s' is not supported by "
raise ArgError("unsupported listing type=%s" % args.type)
- ## Converts type initiator type to enumeration type.
- init = Initiator.TYPE_PORT_WWN
- init = Initiator.TYPE_NODE_WWN
- init = Initiator.TYPE_ISCSI
- init = Initiator.TYPE_HOSTNAME
- init = Initiator.TYPE_SAS
- raise ArgError("invalid initiator type " + init_type)
- return init
-
## Creates an access group.
- init_enum = CmdLine._init_type_to_enum(args.init_type)
+ init_type = ag_init_type_str_to_lsm(args.init_type)
access_group = self.c.access_group_create(args.name, args.init,
- init_enum, args.sys)
+ init_type, args.sys)
self.display_data([access_group])
- agl = self.c.access_groups()
- group = _get_item(agl, args.ag, "access group id")
+ lsm_ag = _get_item(self.c.access_groups(), args.ag, "access group id")
- init = CmdLine._init_type_to_enum(args.init_type)
- self.c.access_group_initiator_add(
- group, args.init, init)
+ init_type = ag_init_type_str_to_lsm(args.init_type)
+ self.c.access_group_initiator_add(lsm_ag, args.init, init_type)
- init = _get_item(self.c.initiators(), args.init, "initiator id")
- self.c.access_group_initiator_delete(group, init.id)
+ self.c.access_group_initiator_delete(lsm_ag, args.init)
## Adds an initiator from an access group
self._add_rm_access_grp_init(args, True)
## Removes an initiator from an access group
self._add_rm_access_grp_init(args, False)
- agl = self.c.access_groups()
- group = _get_item(agl, args.ag, "access group id")
- vols = self.c.volumes_accessible_by_access_group(group)
- self.display_data(vols)
-
- init = _get_item(self.c.initiators(), args.init, "initiator id")
- volumes = self.c.volumes_accessible_by_initiator(init)
- self.display_data(volumes)
-
- vol = _get_item(self.c.volumes(), args.vol, "volume id")
- initiators = self.c.initiators_granted_to_volume(vol)
- self.display_data(initiators)
-
- init = _get_item(self.c.initiators(), args.init, "initiator id")
- self.c.iscsi_chap_auth(init, args.in_user,
+ self.c.iscsi_chap_auth(args.init, args.in_user,
self.args.in_pass,
self.args.out_user,
self.args.out_pass)
- vol = _get_item(self.c.volumes(), args.vol, "volume id")
- groups = self.c.access_groups_granted_to_volume(vol)
- self.display_data(groups)
-
## Used to delete access group
agl = self.c.access_groups()
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("INITIATORS", cap.supported(Capabilities.INITIATORS))
- self._cp("INITIATORS_GRANTED_TO_VOLUME",
- cap.supported(Capabilities.INITIATORS_GRANTED_TO_VOLUME))
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_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_INITIATOR_GRANT",
- cap.supported(Capabilities.VOLUME_INITIATOR_GRANT))
- self._cp("VOLUME_INITIATOR_REVOKE",
- cap.supported(Capabilities.VOLUME_INITIATOR_REVOKE))
self._cp("VOLUME_THIN",
cap.supported(Capabilities.VOLUME_THIN))
self._cp("VOLUME_ISCSI_CHAP_AUTHENTICATION",
self._cp("VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP",
cap.supported(
Capabilities.VOLUMES_ACCESSIBLE_BY_ACCESS_GROUP))
- self._cp("VOLUME_ACCESSIBLE_BY_INITIATOR",
- cap.supported(Capabilities.VOLUME_ACCESSIBLE_BY_INITIATOR))
self._cp("ACCESS_GROUPS_GRANTED_TO_VOLUME",
cap.supported(Capabilities.ACCESS_GROUPS_GRANTED_TO_VOLUME))
self._cp("VOLUME_CHILD_DEPENDENCY",
s = _get_item(self.c.systems(), args.sys, "system id")
out(self.c.volume_replicate_range_block_size(s))
- ## Used to grant or revoke access to a volume to an initiator.
- v = _get_item(self.c.volumes(), args.vol, "volume id")
- initiator_id = args.init
-
- i_type = CmdLine._init_type_to_enum(args.init_type)
- access = 'DEFAULT'
- access = vol_access_type_str_to_type(args.access)
-
- self.c.initiator_grant(initiator_id, i_type, v, access)
- initiator = _get_item(self.c.initiators(), initiator_id,
- "initiator id")
-
- self.c.initiator_revoke(initiator, v)
-
- ## Grant access to volume to an initiator
- return self._access(True, args)
-
- ## Revoke access to volume to an initiator
- return self._access(False, args)
-
raise ArgError('Neither --ag nor --init is defined. '
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 685e119..ba79de2 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -20,7 +20,7 @@ from collections import OrderedDict
from datetime import datetime
from lsm import (size_bytes_2_size_human, LsmError, ErrorNumber,
- System, Pool, Disk, Volume, AccessGroup, Initiator,
+ System, Pool, Disk, Volume, AccessGroup,
FileSystem, FsSnapshot, NfsExport)
BIT_MAP_STRING_SPLITTER = ','
return _str_to_enum(vol_rep_type_str, _VOL_REP_TYPE_CONV)
-_VOL_ACCESS_TYPE_CONV = {
- Volume.ACCESS_READ_WRITE: 'RW',
- Volume.ACCESS_READ_ONLY: 'RO'
-}
-
-
- return _str_to_enum(vol_access_type_str, _VOL_ACCESS_TYPE_CONV)
-
-
return _bit_map_to_str(vol_status, _VOL_STATUS_CONV)
return _bit_map_to_str(disk_status, _DISK_STATUS_CONV)
-_INIT_TYPE_CONV = {
- Initiator.TYPE_OTHER: 'Other',
- Initiator.TYPE_PORT_WWN: 'Port WWN',
- Initiator.TYPE_NODE_WWN: 'Node WWN',
- Initiator.TYPE_HOSTNAME: 'Hostname',
- Initiator.TYPE_ISCSI: 'iSCSI',
- Initiator.TYPE_SAS: "SAS"
-}
-
-
- return _enum_type_to_str(init_type, _INIT_TYPE_CONV)
-
-
_AG_INIT_TYPE_CONV = {
AccessGroup.INIT_TYPE_UNKNOWN: 'Unknown',
AccessGroup.INIT_TYPE_OTHER: 'Other',
'value_conv_human': AG_VALUE_CONV_HUMAN,
}
- # lsm.Initiator
- INIT_MAN_HEADER = OrderedDict()
- INIT_MAN_HEADER['id'] = 'ID'
- INIT_MAN_HEADER['name'] = 'Name'
- INIT_MAN_HEADER['type'] = 'Initiator Type'
-
- INIT_COLUMN_KEYS = INIT_MAN_HEADER.keys()
-
- INIT_OPT_HEADER = OrderedDict()
-
- INIT_VALUE_CONV_ENUM = {
- 'type': init_type_to_str,
- }
-
- INIT_VALUE_CONV_HUMAN = []
-
- VALUE_CONVERT[Initiator] = {
- 'mandatory_headers': INIT_MAN_HEADER,
- 'column_keys': INIT_COLUMN_KEYS,
- 'optional_headers': INIT_OPT_HEADER,
- 'value_conv_enum': INIT_VALUE_CONV_ENUM,
- 'value_conv_human': INIT_VALUE_CONV_HUMAN,
- }
-
# lsm.FileSystem
FS_MAN_HEADER = OrderedDict()
FS_MAN_HEADER['id'] = 'ID'
Loading...