Skip to content

Commit c43cb44

Browse files
committed
update iscsi.py module
- Add a new class to supporting iscsi with the multi targets. - Update the create_iSCSI function. Signed-off-by: Houqi (Nick) Zuo <hzuo@redhat.com>
1 parent 978c026 commit c43cb44

1 file changed

Lines changed: 132 additions & 18 deletions

File tree

virttest/iscsi.py

Lines changed: 132 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from __future__ import division
1111

12+
import ast
1213
import logging
1314
import os
1415
import 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,22 +651,8 @@ def export_target(self):
651651
self.device,
652652
self.emulated_image,
653653
)
654-
try:
655-
output = process.run(device_cmd).stdout_text
656-
except process.CmdError as e:
657-
file_exists = re.match(
658-
r".*storage object.*exists.*",
659-
str(e),
660-
re.DOTALL | re.IGNORECASE,
661-
)
662-
if file_exists and self.allow_multipath:
663-
LOG.info(f"Allow Multipath, skipping error {e}")
664-
else:
665-
raise e
666-
if (
667-
not self.allow_multipath
668-
and "Created %s" % self.iscsi_backend not in output
669-
):
654+
output = process.run(device_cmd).stdout_text
655+
if "Created %s" % self.iscsi_backend not in output:
670656
raise exceptions.TestFail(
671657
"Failed to create %s %s. (%s)"
672658
% (self.iscsi_backend, self.device, output)
@@ -833,5 +819,133 @@ def create_iSCSI(params, root_dir=data_dir.get_tmp_dir()):
833819
)
834820
iscsi_instance = IscsiTGT(params, root_dir)
835821
else:
836-
iscsi_instance = IscsiLIO(params, root_dir)
822+
iscsi_instance = (
823+
MultiTargetsIscsiLIO(params, root_dir)
824+
if not params.get("target") and params.get("targets_luns")
825+
else IscsiLIO(params, root_dir)
826+
)
837827
return iscsi_instance
828+
829+
830+
class MultiTargetsIscsiLIO(IscsiLIO):
831+
"""
832+
Iscsi class supporting multi-targets for the LIO backend used in RHEL7.
833+
"""
834+
835+
def __init__(self, params, root_dir):
836+
"""
837+
Init the object based on the params and root_dir.
838+
Note: 'targets_luns' in params is introduced at this class.
839+
The structure of 'targets_luns':
840+
targets_luns =
841+
{
842+
${target01}: {
843+
${lun01} : {"emulated_image": ..., ...},
844+
${lun02} : {"emulated_image": ..., ...},
845+
},
846+
${target02}: {
847+
${lun01} : {"emulated_image": ..., ...},
848+
${lun02} : {"emulated_image": ..., ...},
849+
},
850+
...
851+
}
852+
If there's only one lun without any special assigned requests,
853+
lun should be set to "default_lun", for example:
854+
targets_luns = { ${target01}: { "default_lun": {...}}}
855+
856+
:param params: parameters dict for iSCSI
857+
:param root_dir: path for image
858+
"""
859+
self._targets_luns = ast.literal_eval(params.get("targets_luns"))
860+
# stores the iscsiLIO objects based on each targets
861+
self._targets_mapping = {}
862+
# param_in_lun = (
863+
# "emulated_image",
864+
# "image_size",
865+
# "iscsi_lun_attrs",
866+
# )
867+
for target in self._targets_luns.keys():
868+
single_target_param = params.copy()
869+
for lun in self._targets_luns[target].keys():
870+
single_target_param.update(self._targets_luns[target][lun])
871+
single_target_param["target"] = target
872+
single_target_param["iscsi_backend"] = "fileio"
873+
self._targets_mapping[target] = super().__init__(
874+
single_target_param, root_dir
875+
)
876+
if lun not in ("default_lun",):
877+
self._targets_mapping[target].luns = lun
878+
879+
def query_targets(self, emulated_image=None, lun=None):
880+
"""
881+
Dynamically filter the targets from image name given and lun given.
882+
883+
:param emulated_image: the image name. If none, do NOT check emulated_image
884+
:type emulated_image: string
885+
:param lun: the lun. If none, do NOT check lun
886+
:type lun: string
887+
888+
:return: the targets in list or []
889+
:rtype: list
890+
"""
891+
cmd = "targetcli ls /iscsi 1"
892+
target_info = process.run(cmd).stdout_text
893+
targets = re.findall(r"iqn[\.]\S+:\S+", target_info)
894+
895+
filtered_targets = []
896+
for target in targets:
897+
cmd = "targetcli ls /iscsi/%s/tpg1/luns" % target
898+
luns_info = process.run(cmd).stdout_text
899+
if (
900+
(not emulated_image and not lun)
901+
or (emulated_image and not lun and emulated_image + ")" in luns_info)
902+
or (
903+
emulated_image
904+
and lun
905+
and emulated_image + ")" in luns_info
906+
and " " + lun + " " in luns_info
907+
)
908+
):
909+
filtered_targets.append(target)
910+
return filtered_targets
911+
912+
def set_chap_auth_target(self, target=None):
913+
"""
914+
set up authentication information for every single initiator,
915+
which provides the capability to define common login information
916+
for all Endpoints in a TPG
917+
918+
:param target: the target.
919+
:type target: string
920+
"""
921+
if not target:
922+
for i in self._targets_mapping.keys():
923+
self._targets_mapping[i].set_chap_auth_target()
924+
else:
925+
self._targets_mapping[target].set_chap_auth_target()
926+
927+
def export_target(self, target=None):
928+
"""
929+
Export target(s) in localhost for emulated iscsi.
930+
931+
:param target: the target.
932+
:type target: string
933+
"""
934+
if not target:
935+
for i in self._targets_mapping.keys():
936+
self._targets_mapping[i].export_target()
937+
else:
938+
self._targets_mapping[target].export_target()
939+
940+
def delete_target(self, target=None):
941+
"""
942+
Delete target(s) from host.
943+
944+
:param target: the target.
945+
:type target: string
946+
"""
947+
if not target:
948+
for i in self._targets_mapping.keys():
949+
self._targets_mapping[i].delete_target()
950+
else:
951+
self._targets_mapping[target].delete_target()

0 commit comments

Comments
 (0)