Discussion:
[Libstoragemgmt-devel] [PATCH] Targetd Plugin: Add access group create/delete support
Gris Ge
2014-11-07 11:40:51 UTC
Permalink
* Please don't commit this patch until targetd accept my patch for adding
initiator related methods.

* Use targetd new method to do access group create and delete.

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

diff --git a/plugin/targetd/targetd.py b/plugin/targetd/targetd.py
index b40aa4c..7379530 100644
--- a/plugin/targetd/targetd.py
+++ b/plugin/targetd/targetd.py
@@ -38,6 +38,8 @@ PATH = "/targetrpc"
# Current sector size in liblvm
_LVM_SECTOR_SIZE = 512

+_TGT_ERROR_METHOD_NOT_FOUND = 32601
+
def handle_errors(method):
def target_wrapper(*args, **kwargs):
try:
@@ -212,20 +214,113 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
'targetd'))
return search_property(pools, search_key, search_value)

+ def _tgt_init_to_lsm_ag(self, tgt_init):
+ init_id = tgt_init['initiator_wwn']
+ ag_id = md5(init_id)
+ init_type = AccessGroup.INIT_TYPE_ISCSI_IQN
+ ag_name = 'N/A'
+ init_ids = [init_id]
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, self.system.id)
+
+
@handle_errors
def access_groups(self, search_key=None, search_value=None, flags=0):
rc = []
- for init_id in set(i['initiator_wwn']
- for i in self._jsonrequest("export_list")):
- ag_id = md5(init_id)
- init_type = AccessGroup.INIT_TYPE_ISCSI_IQN
- ag_name = 'N/A'
- init_ids = [init_id]
- rc.extend(
- [AccessGroup(ag_id, ag_name, init_ids, init_type,
- self.system.id)])
+ try:
+ for tgt_init in self._jsonrequest("initiators"):
+ rc.append(self._tgt_init_to_lsm_ag(tgt_init))
+ except TargetdError as te:
+ if te.errno == _TGT_ERROR_METHOD_NOT_FOUND:
+ # Use old way
+ for init_id in set(i['initiator_wwn']
+ for i in self._jsonrequest("export_list")):
+ ag_id = md5(init_id)
+ init_type = AccessGroup.INIT_TYPE_ISCSI_IQN
+ ag_name = 'N/A'
+ init_ids = [init_id]
+ rc.append(
+ AccessGroup(
+ ag_id, ag_name, init_ids, init_type,
+ self.system.id))
+ else:
+ raise
+
return search_property(rc, search_key, search_value)

+ @handle_errors
+ def access_group_create(self, name, init_id, init_type, system, flags=0):
+ if system.id != self.system.id:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System %s not found" % system.id)
+ if init_type != AccessGroup.INIT_TYPE_ISCSI_IQN:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Targetd only support creating iSCSI IQN access group")
+
+ # Pre-check for exist initiators.
+ cur_access_groups = self.access_groups()
+ for cur_access_group in cur_access_groups:
+ if cur_access_group.init_ids[0] == init_id:
+ raise LsmError(
+ ErrorNumber.EXISTS_INITIATOR,
+ "Defined initiator already exists in other access group")
+ try:
+ tgt_init = self._jsonrequest(
+ "initiator_create", dict(initiator_wwn=init_id))
+ except TargetdError as te:
+ if te.errno == _TGT_ERROR_METHOD_NOT_FOUND:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Please upgrade your targetd to support access group "
+ "create")
+ else:
+ raise
+ return self._tgt_init_to_lsm_ag(tgt_init)
+
+ @handle_errors
+ def access_group_delete(self, access_group, flags=0):
+ if len(access_group.init_ids) != 1:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Provided access group has no initiator or more than 1"
+ "initiators: %s" % access_group.init_ids)
+
+ # Pre-check for existence
+ flag_found = False
+ cur_access_groups = self.access_groups()
+ for cur_access_group in cur_access_groups:
+ if cur_access_group.init_ids[0] == access_group.init_ids[0]:
+ flag_found = True
+ break
+
+ if flag_found is False:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_ACCESS_GROUP,
+ "Access Group not found")
+
+ masked_volumes = self.volumes_accessible_by_access_group(access_group)
+
+ if len(masked_volumes) != 0:
+ raise LsmError(
+ ErrorNumber.IS_MASKED,
+ "Cannot delete access group with volume masked")
+ try:
+ self._jsonrequest(
+ 'initiator_delete',
+ dict(initiator_wwn=access_group.init_ids[0]))
+ except TargetdError as te:
+ if te.errno == _TGT_ERROR_METHOD_NOT_FOUND:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Please upgrade your targetd to support access group "
+ "delete")
+ else:
+ raise
+
+ return
+
def _mask_infos(self):
"""
Return a list of tgt_mask:
--
1.8.3.1


------------------------------------------------------------------------------
Gris Ge
2014-11-14 09:38:47 UTC
Permalink
* Please don't commit this patch until targetd accept my patch for adding
initiator related methods.

* Use targetd new method to do access group create and delete.

Changes in V2:

* Update access_group_create() as targetd will not return anything
on initiator_create() method.

* Update volume_unmask() to ensure access group will not be deleted by
add it back when access_group_create() is supported.

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

diff --git a/plugin/targetd/targetd.py b/plugin/targetd/targetd.py
index 7027b6d..a40464a 100644
--- a/plugin/targetd/targetd.py
+++ b/plugin/targetd/targetd.py
@@ -38,6 +38,8 @@
# Current sector size in liblvm
_LVM_SECTOR_SIZE = 512

+_TGT_ERROR_METHOD_NOT_FOUND = 32601
+
def handle_errors(method):
def target_wrapper(*args, **kwargs):
try:
@@ -213,20 +215,120 @@ def pools(self, search_key=None, search_value=None, flags=0):
'targetd'))
return search_property(pools, search_key, search_value)

+ def _tgt_init_to_lsm_ag(self, tgt_init):
+ init_id = tgt_init['initiator_wwn']
+ ag_id = md5(init_id)
+ init_type = AccessGroup.INIT_TYPE_ISCSI_IQN
+ ag_name = 'N/A'
+ init_ids = [init_id]
+ return AccessGroup(
+ ag_id, ag_name, init_ids, init_type, self.system.id)
+
+
@handle_errors
def access_groups(self, search_key=None, search_value=None, flags=0):
rc = []
- for init_id in set(i['initiator_wwn']
- for i in self._jsonrequest("export_list")):
- ag_id = md5(init_id)
- init_type = AccessGroup.INIT_TYPE_ISCSI_IQN
- ag_name = 'N/A'
- init_ids = [init_id]
- rc.extend(
- [AccessGroup(ag_id, ag_name, init_ids, init_type,
- self.system.id)])
+ try:
+ for tgt_init in self._jsonrequest("initiators"):
+ rc.append(self._tgt_init_to_lsm_ag(tgt_init))
+ except TargetdError as te:
+ if te.errno == _TGT_ERROR_METHOD_NOT_FOUND:
+ # Use old way
+ for init_id in set(i['initiator_wwn']
+ for i in self._jsonrequest("export_list")):
+ ag_id = md5(init_id)
+ init_type = AccessGroup.INIT_TYPE_ISCSI_IQN
+ ag_name = 'N/A'
+ init_ids = [init_id]
+ rc.append(
+ AccessGroup(
+ ag_id, ag_name, init_ids, init_type,
+ self.system.id))
+ else:
+ raise
+
return search_property(rc, search_key, search_value)

+ @handle_errors
+ def access_group_create(self, name, init_id, init_type, system, flags=0):
+ if system.id != self.system.id:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System %s not found" % system.id)
+ if init_type != AccessGroup.INIT_TYPE_ISCSI_IQN:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Targetd only support creating iSCSI IQN access group")
+
+ # Pre-check for exist initiators.
+ cur_access_groups = self.access_groups()
+ for cur_access_group in cur_access_groups:
+ if cur_access_group.init_ids[0] == init_id:
+ raise LsmError(
+ ErrorNumber.EXISTS_INITIATOR,
+ "Defined initiator already exists in other access group")
+ try:
+ self._jsonrequest(
+ "initiator_create", dict(initiator_wwn=init_id))
+ except TargetdError as te:
+ if te.errno == _TGT_ERROR_METHOD_NOT_FOUND:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Please upgrade your targetd to support access group "
+ "create")
+ else:
+ raise
+ for tgt_init in self._jsonrequest("initiators"):
+ if tgt_init['initiator_wwn'] == init_id:
+ return self._tgt_init_to_lsm_ag(tgt_init)
+
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "access_group_create(): Failed to find out the newly created "
+ "initiator")
+
+ @handle_errors
+ def access_group_delete(self, access_group, flags=0):
+ if len(access_group.init_ids) != 1:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Provided access group has no initiator or more than 1"
+ "initiators: %s" % access_group.init_ids)
+
+ # Pre-check for existence
+ flag_found = False
+ cur_access_groups = self.access_groups()
+ for cur_access_group in cur_access_groups:
+ if cur_access_group.init_ids[0] == access_group.init_ids[0]:
+ flag_found = True
+ break
+
+ if flag_found is False:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_ACCESS_GROUP,
+ "Access Group not found")
+
+ masked_volumes = self.volumes_accessible_by_access_group(access_group)
+
+ if len(masked_volumes) != 0:
+ raise LsmError(
+ ErrorNumber.IS_MASKED,
+ "Cannot delete access group with volume masked")
+ try:
+ self._jsonrequest(
+ 'initiator_delete',
+ dict(initiator_wwn=access_group.init_ids[0]))
+ except TargetdError as te:
+ if te.errno == _TGT_ERROR_METHOD_NOT_FOUND:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Please upgrade your targetd to support access group "
+ "delete")
+ else:
+ raise
+
+ return
+
def _mask_infos(self):
"""
Return a list of tgt_mask:
@@ -288,6 +390,20 @@ def volume_unmask(self, volume, access_group, flags=0):
dict(pool=volume.pool_id,
vol=volume.name,
initiator_wwn=access_group.init_ids[0]))
+ # As export_destroy will remove access group if no volume masked.
+ # This is not the way of LSM when access_group_create() is supported.
+ # We add it back if access_group_create() is supported.
+ try:
+ self.access_group_create(
+ 'N/A', access_group.init_ids[0], access_group.init_type,
+ self.system)
+ except LsmError as lsm_error:
+ if lsm_error.code == ErrorNumber.NO_SUPPORT or \
+ lsm_error.code == ErrorNumber.EXISTS_INITIATOR:
+ pass
+ else:
+ raise
+
return None

@handle_errors
--
1.8.3.1
Tony Asleson
2014-11-17 22:12:05 UTC
Permalink
Post by Gris Ge
* Please don't commit this patch until targetd accept my patch for adding
initiator related methods.
I posted a comment on targetd mailing list concerning those changes.

Thanks,
Tony

Loading...