99
1010from __future__ import division
1111
12+ import ast
1213import logging
1314import os
1415import re
@@ -189,7 +190,6 @@ def __init__(self, params, root_dir):
189190 self .luns = None
190191 self .iscsi_lun_attrs = params .get ("iscsi_lun_attrs" )
191192 self .restart_tgtd = "yes" == params .get ("restart_tgtd" , "no" )
192- self .allow_multipath = "yes" == params .get ("iscsi_allow_multipath" , "no" )
193193 if params .get ("portal_ip" ):
194194 self .portal_ip = params .get ("portal_ip" )
195195 else :
@@ -651,6 +651,7 @@ def export_target(self):
651651 self .device ,
652652 self .emulated_image ,
653653 )
654+ output = process .run (device_cmd ).stdout_text
654655 try :
655656 output = process .run (device_cmd ).stdout_text
656657 except process .CmdError as e :
@@ -664,8 +665,8 @@ def export_target(self):
664665 else :
665666 raise e
666667 if (
667- not self .allow_multipath
668- and "Created %s" % self .iscsi_backend not in output
668+ not self .allow_multipath
669+ and "Created %s" % self .iscsi_backend not in output
669670 ):
670671 raise exceptions .TestFail (
671672 "Failed to create %s %s. (%s)"
@@ -833,5 +834,175 @@ def create_iSCSI(params, root_dir=data_dir.get_tmp_dir()):
833834 )
834835 iscsi_instance = IscsiTGT (params , root_dir )
835836 else :
836- iscsi_instance = IscsiLIO (params , root_dir )
837+ iscsi_instance = (
838+ MultiTargetsIscsiLIO (params , root_dir )
839+ if not params .get ("target" ) and params .get ("targets_luns" )
840+ else IscsiLIO (params , root_dir )
841+ )
837842 return iscsi_instance
843+
844+
845+ class MultiTargetsIscsiLIO (IscsiLIO ):
846+ """
847+ Iscsi class supporting multi-targets for the LIO backend used in RHEL7.
848+ """
849+
850+ def __init__ (self , params , root_dir ):
851+ """
852+ Init the object based on the params and root_dir.
853+ Note: 'targets_luns' in params is introduced at this class.
854+ The structure of 'targets_luns':
855+ targets_luns =
856+ {
857+ ${target01}: {
858+ ${lun01} : {"emulated_image": ..., ...},
859+ ${lun02} : {"emulated_image": ..., ...},
860+ },
861+ ${target02}: {
862+ ${lun01} : {"emulated_image": ..., ...},
863+ ${lun02} : {"emulated_image": ..., ...},
864+ },
865+ ...
866+ }
867+ If there's only one lun without any special assigned requests,
868+ lun should be set to "default_lun", for example:
869+ targets_luns = { ${target01}: { "default_lun": {...}}}
870+
871+ :param params: parameters dict for iSCSI
872+ :param root_dir: path for image
873+ """
874+ self ._targets_luns = ast .literal_eval (params .get ("targets_luns" ))
875+ # stores the iscsiLIO objects based on each targets
876+ self ._targets_mapping = {}
877+ # param_in_lun = (
878+ # "emulated_image",
879+ # "image_size",
880+ # "iscsi_lun_attrs",
881+ # )
882+ for target in self ._targets_luns .keys ():
883+ single_target_param = params .copy ()
884+ for lun in self ._targets_luns [target ].keys ():
885+ single_target_param .update (self ._targets_luns [target ][lun ])
886+ single_target_param ["target" ] = target
887+ single_target_param ["iscsi_backend" ] = "fileio"
888+ self ._targets_mapping [target ] = IscsiLIO (single_target_param , root_dir )
889+ if lun not in ("default_lun" ,):
890+ self ._targets_mapping [target ].luns = lun
891+
892+ def query_targets (self , emulated_image = None , lun = None ):
893+ """
894+ Dynamically filter the targets from image name given and lun given.
895+
896+ :param emulated_image: the image name. If none, do NOT check emulated_image
897+ :type emulated_image: string
898+ :param lun: the lun. If none, do NOT check lun
899+ :type lun: string
900+
901+ :return: the targets in list or []
902+ :rtype: list
903+ """
904+ cmd = "targetcli ls /iscsi 1"
905+ target_info = process .run (cmd ).stdout_text
906+ targets = re .findall (r"iqn[\.]\S+:\S+" , target_info )
907+
908+ filtered_targets = []
909+ for target in targets :
910+ cmd = "targetcli ls /iscsi/%s/tpg1/luns" % target
911+ luns_info = process .run (cmd ).stdout_text
912+ if (
913+ (not emulated_image and not lun )
914+ or (emulated_image and not lun and emulated_image + ")" in luns_info )
915+ or (
916+ emulated_image
917+ and lun
918+ and emulated_image + ")" in luns_info
919+ and " " + lun + " " in luns_info
920+ )
921+ ):
922+ filtered_targets .append (target )
923+ return filtered_targets
924+
925+ def set_chap_auth_target (self , target = None ):
926+ """
927+ set up authentication information for every single initiator,
928+ which provides the capability to define common login information
929+ for all Endpoints in a TPG
930+
931+ :param target: the target.
932+ :type target: string
933+ """
934+ for key in self ._targets_mapping .keys ():
935+ if not target or key == target :
936+ self ._targets_mapping [key ].set_chap_auth_target ()
937+
938+ def export_target (self , target = None ):
939+ """
940+ Export target(s) in localhost for emulated iscsi.
941+
942+ :param target: the target.
943+ :type target: string
944+ """
945+ for key in self ._targets_mapping .keys ():
946+ if not target or key == target :
947+ self ._targets_mapping [key ].export_target ()
948+
949+ def delete_target (self , target = None ):
950+ """
951+ Delete target(s) from host.
952+
953+ :param target: the target.
954+ :type target: string
955+ """
956+ for key in self ._targets_mapping .keys ():
957+ if not target or key == target :
958+ self ._targets_mapping [key ].delete_target ()
959+
960+ def login (self , target = None ):
961+ """
962+ Login target.
963+
964+ :param target: the target.
965+ :type target: string
966+ """
967+ if target :
968+ self ._targets_mapping [target ].login ()
969+ else :
970+ LOG .error ("The target can't be None!" )
971+
972+ def cleanup (self , target = None , confirmed = False ):
973+ """
974+ Clean up env after iscsi used.
975+
976+ :param target: the target.
977+ :type target: string
978+ :param confirmed: switch for cleanup all iscsi config
979+ :type confirmed: bool
980+ """
981+ for key in self ._targets_mapping .keys ():
982+ if not target or key == target :
983+ self ._targets_mapping [key ].cleanup (confirmed )
984+
985+ def logout (self , target = None ):
986+ """
987+ Logout from target.
988+
989+ :param target: the target.
990+ :type target: string
991+ """
992+ if self ._targets_mapping [target ].logged_in ():
993+ iscsi_logout (self .target )
994+
995+ def logged_in (self , target = None ):
996+ """
997+ Check if the session is login or not.
998+
999+ :param target: the target.
1000+ :type target: string
1001+
1002+ :return: logged in or not
1003+ :rtype: bool
1004+ """
1005+ if target :
1006+ return self ._targets_mapping [target ].logged_in ()
1007+ else :
1008+ LOG .error ("The target can't be None!" )
0 commit comments