diff --git a/.gitignore b/.gitignore index 593a6e1..126bf06 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /targetcli-1.99.2.gitb03ec79.tar.gz +/v2.0rc1.fb1 +/v2.0rc1.fb2 diff --git a/0001-Remove-ads-from-cli-welcome-msg.-Mention-help-is-ava.patch b/0001-Remove-ads-from-cli-welcome-msg.-Mention-help-is-ava.patch deleted file mode 100644 index ee0691b..0000000 --- a/0001-Remove-ads-from-cli-welcome-msg.-Mention-help-is-ava.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 786d5b84d653c019c391fa07e483947156a03e3d Mon Sep 17 00:00:00 2001 -From: Andy Grover -Date: Sat, 30 Jul 2011 16:02:43 -0700 -Subject: [PATCH 1/6] Remove ads from cli welcome msg. Mention help is available. - -Signed-off-by: Andy Grover ---- - scripts/targetcli | 4 ++-- - 1 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/scripts/targetcli b/scripts/targetcli -index 8af0613..738f02c 100755 ---- a/scripts/targetcli -+++ b/scripts/targetcli -@@ -58,9 +58,9 @@ def main(): - shell = TargetCLI('~/.targetcli') - shell.con.epy_write(''' - Welcome to the B{targetcli} shell:: -- Copyright (c) 2011 by RisingTide Systems LLC. -+ Copyright (c) 2011 by RisingTide Systems LLC.\n -+ For help on commands, type 'help'. - -- Visit us at U{http://www.risingtidesystems.com}. - ''') - shell.con.display('') - if not is_root: --- -1.7.1 - diff --git a/0002-bundle-lio-utils.patch b/0002-bundle-lio-utils.patch deleted file mode 100644 index 4e497b5..0000000 --- a/0002-bundle-lio-utils.patch +++ /dev/null @@ -1,3992 +0,0 @@ -From c55d9206e4f783d25ceb574ba07c40a83daf00a3 Mon Sep 17 00:00:00 2001 -From: Andy Grover -Date: Thu, 18 Aug 2011 11:19:35 -0700 -Subject: [PATCH 2/6] bundle lio-utils - -lio-utils is used just for saving state. It should be going away -shortly, so just bundle it for now. - -Signed-off-by: Andy Grover ---- - targetcli/lio_dump.py | 265 +++++++++ - targetcli/lio_node.py | 1349 ++++++++++++++++++++++++++++++++++++++++++++++ - targetcli/tcm_dump.py | 366 +++++++++++++ - targetcli/tcm_fabric.py | 532 ++++++++++++++++++ - targetcli/tcm_fileio.py | 83 +++ - targetcli/tcm_iblock.py | 86 +++ - targetcli/tcm_loop.py | 242 +++++++++ - targetcli/tcm_node.py | 737 +++++++++++++++++++++++++ - targetcli/tcm_pscsi.py | 184 +++++++ - targetcli/tcm_ramdisk.py | 53 ++ - 10 files changed, 3897 insertions(+), 0 deletions(-) - create mode 100644 targetcli/lio_dump.py - create mode 100644 targetcli/lio_node.py - create mode 100644 targetcli/tcm_dump.py - create mode 100644 targetcli/tcm_fabric.py - create mode 100644 targetcli/tcm_fileio.py - create mode 100644 targetcli/tcm_iblock.py - create mode 100644 targetcli/tcm_loop.py - create mode 100644 targetcli/tcm_node.py - create mode 100644 targetcli/tcm_pscsi.py - create mode 100644 targetcli/tcm_ramdisk.py - -diff --git a/targetcli/lio_dump.py b/targetcli/lio_dump.py -new file mode 100644 -index 0000000..81c5104 ---- /dev/null -+++ b/targetcli/lio_dump.py -@@ -0,0 +1,265 @@ -+import os, sys -+import subprocess as sub -+import string -+import re -+import datetime, time -+from optparse import OptionParser -+ -+lio_root = "/sys/kernel/config/target/iscsi" -+ -+def lio_target_configfs_dump(option, opt_str, value, parser): -+ -+ if not os.path.isdir(lio_root): -+ print "Unable to access lio_root: " + lio_root -+ sys.exit(1) -+ -+ iqn_root = os.listdir(lio_root) -+ -+ # This will load up iscsi_target_mod.ko -+ print "mkdir " + lio_root -+ -+ print "#### iSCSI Discovery authentication information" -+ auth_dir = lio_root + "/discovery_auth" -+ if os.path.isdir(auth_dir) == True: -+ for auth in os.listdir(auth_dir): -+ if auth == "authenticate_target": -+ continue -+ -+ auth_file = auth_dir + "/" + auth -+ p = os.open(auth_file, 0) -+ value = os.read(p, 256) -+ ret = value.isspace() -+ if ret: -+ os.close(p) -+ continue -+ print "echo -n " + value.rstrip() + " > " + auth_file -+ os.close(p) -+ -+ iqn_root = os.listdir(lio_root) -+ -+ # Loop through LIO-Target IQN list -+ for iqn in iqn_root: -+ if iqn == "lio_version": -+ continue -+ if iqn == "discovery_auth": -+ continue -+ -+ # Loop through LIO-Target IQN+TPGT list -+ tpg_root = os.listdir(lio_root + "/" + iqn); -+ for tpgt_tmp in tpg_root: -+ if tpgt_tmp == "fabric_statistics": -+ continue -+ -+ tpgt_tmp2 = tpgt_tmp.split('_') -+ tpgt = tpgt_tmp2[1] -+ -+ print "#### Network portals for iSCSI Target Portal Group" -+ np_root = os.listdir(lio_root + "/" + iqn + "/tpgt_" + tpgt + "/np") -+ for np in np_root: -+ print "mkdir -p " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/np/" + np -+ -+ print "#### iSCSI Target Ports" -+ lun_root = os.listdir(lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun") -+ for lun_tmp in lun_root: -+ lun_tmp2 = lun_tmp.split('_') -+ lun = lun_tmp2[1] -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ print "mkdir -p " + lun_dir -+ -+ port_root = os.listdir(lun_dir) -+ for port in port_root: -+ if port == "alua_tg_pt_gp": -+ continue -+ if port == "alua_tg_pt_offline": -+ continue -+ if port == "alua_tg_pt_status": -+ continue -+ if port == "alua_tg_pt_write_md": -+ continue -+ -+ if not os.path.islink(lun_dir + "/" + port): -+ continue -+ -+ port_link = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun + "/" + port -+ sourcelink = os.readlink(port_link) -+ sourcelink2 = os.path.join(os.path.dirname(port_link), sourcelink) -+ print "ln -s " + sourcelink2 + " " + port_link -+ -+ # Dump ALUA Target Port Group -+ tg_pt_gp_file = lun_dir + "/alua_tg_pt_gp" -+ p = os.open(tg_pt_gp_file, 0) -+ try: -+ value = os.read(p, 512) -+ except: -+ os.close(p) -+ continue -+ os.close(p) -+ if value: -+ tg_pt_gp_tmp = value.split('\n') -+ tg_pt_gp_out = tg_pt_gp_tmp[0] -+ off = tg_pt_gp_out.index('Alias: ') -+ off += 7 # Skip over "Alias: " -+ tg_pt_gp_name = tg_pt_gp_out[off:] -+ # Only need to dump if LIO-Target Port is NOT partof -+ # the 'default_tg_pt_gp' -+ if not re.search(tg_pt_gp_name, 'default_tg_pt_gp'): -+ print "#### ALUA Target Port Group" -+ print "echo " + tg_pt_gp_name + " > " + tg_pt_gp_file -+ -+ print "lio_node --aluasecmd " + iqn + " " + tpgt + " " + lun -+ -+ # Dump values of iscsi/iqn/tpgt/attrib/ -+ print "#### Attributes for iSCSI Target Portal Group" -+ attrib_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib/" -+ attrib_root = os.listdir(attrib_dir) -+ for attrib in attrib_root: -+ attrib_file = attrib_dir + attrib -+ p = os.open(attrib_file, 0) -+ value = os.read(p, 16) -+ print "echo " + value.rstrip() + " > " + attrib_file -+ os.close(p) -+ -+ # Dump values for iscsi/iqn/tpgt/param -+ print "#### Parameters for iSCSI Target Portal Group" -+ param_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/param/" -+ param_root = os.listdir(param_dir) -+ for param in param_root: -+ param_file = param_dir + param -+ p = os.open(param_file, 0) -+ value = os.read(p, 256) -+ print "echo \"" + value.rstrip() + "\" > " + param_file -+ os.close(p) -+ -+ # Dump iSCSI Initiator Node ACLs from iscsi/iqn/tpgt/acls -+ print "#### iSCSI Initiator ACLs for iSCSI Target Portal Group" -+ nacl_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" -+ nacl_root = os.listdir(nacl_dir) -+ for nacl in nacl_root: -+ print "mkdir -p " + nacl_dir + nacl -+ tcq_depth_file = nacl_dir + nacl + "/cmdsn_depth" -+ p = os.open(tcq_depth_file, 0) -+ value = os.read(p, 8) -+ print "echo " + value.rstrip() + " > " + tcq_depth_file -+ os.close(p) -+ -+ # Dump iSCSI Initiator ACL authentication info from iscsi/iqn/tpgt/acls/$INITIATOR/auth -+ print "#### iSCSI Initiator ACL authentication information" -+ auth_dir = nacl_dir + nacl + "/auth" -+ for auth in os.listdir(auth_dir): -+ if auth == "authenticate_target": -+ continue -+ auth_file = auth_dir + "/" + auth -+ p = os.open(auth_file, 0) -+ value = os.read(p, 256) -+ ret = value.isspace() -+ if ret: -+ os.close(p) -+ continue -+ print "echo -n " + value.rstrip() + " > " + auth_file -+ os.close(p) -+ -+ # Dump iSCSI Initiator ACL TPG attributes from iscsi/iqn/tpgt/acls/$INITIATOR/attrib -+ print "#### iSCSI Initiator ACL TPG attributes" -+ nacl_attrib_dir = nacl_dir + nacl + "/attrib" -+ for nacl_attrib in os.listdir(nacl_attrib_dir): -+ nacl_attrib_file = nacl_attrib_dir + "/" + nacl_attrib -+ p = os.open(nacl_attrib_file, 0) -+ value = os.read(p, 8) -+ print "echo " + value.rstrip() + " > " + nacl_attrib_file -+ os.close(p) -+ -+ # Dump iSCSI Initiator LUN ACLs from iscsi/iqn/tpgt/acls/$INITIATOR/lun -+ print "#### iSCSI Initiator LUN ACLs for iSCSI Target Portal Group" -+ lun_acl_dir = nacl_dir + nacl -+ for lun_acl in os.listdir(lun_acl_dir): -+ ret = re.search('lun_', lun_acl) -+ if not ret: -+ continue -+ lun_link_dir = nacl_dir + nacl + "/" + lun_acl -+ print "mkdir -p " + lun_link_dir -+ -+ for lun_acl_link in os.listdir(lun_link_dir): -+ if lun_acl_link == "write_protect": -+ p = os.open(lun_link_dir + "/write_protect", 0) -+ value = os.read(p, 4) -+ print "echo " + value.rstrip() + " > " + lun_link_dir + "/write_protect" -+ os.close(p) -+ continue -+ -+ if not os.path.islink(lun_link_dir + "/" + lun_acl_link): -+ continue -+ -+ sourcelink = os.readlink(lun_link_dir + "/" + lun_acl_link) -+ sourcelink2 = os.path.join(os.path.dirname(lun_link_dir + "/" + lun_acl_link), sourcelink) -+ print "ln -s " + sourcelink2 + " " + lun_link_dir + "/" + lun_acl_link -+ -+ # Dump value of iscsi/iqn/tpgt/enable -+ print "#### Trigger to enable iSCSI Target Portal Group" -+ enable_file = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/enable" -+ p = os.open(enable_file, 0) -+ value = os.read(p, 1) -+ print "echo " + value.rstrip() + " > " + enable_file -+ os.close(p) -+ -+# lio_target_del_iqn(None, None, iqn, None) -+ -+ return -+ -+def lio_backup_to_file(option, opt_str, value, parser): -+ now = str(value) -+ -+ if not os.path.isdir(lio_root): -+ print "Unable to access lio_root: " + lio_root -+ sys.exit(1) -+ -+ backup_dir = "/etc/target/backup" -+ if not os.path.isdir(backup_dir): -+ op = "mkdir " + backup_dir -+ ret = os.system(op) -+ if ret: -+ print "Unable to open backup_dir" -+ sys.exit(1) -+ -+ op = "lio_dump --stdout" -+ p = sub.Popen(op, shell=True, stdout=sub.PIPE).stdout -+ if not p: -+ print "Unable to dump LIO-Target/ConfigFS running state" -+ sys.exit(1) -+ -+ print "Making backup of LIO-Target/ConfigFS with timestamp: " + now -+ backup_file = backup_dir + "/lio_backup-" + now + ".sh" -+ if os.path.isfile(backup_file): -+ print "LIO-Target backup_file: " + backup_file + "already exists, exiting" -+ p.close() -+ sys.exit(1) -+ -+ back = open(backup_file, 'w') -+ -+ line = p.readline() -+ while line: -+ print >>back, line.rstrip() -+ line = p.readline() -+ -+ p.close() -+ back.close() -+ return backup_file -+ -+def main(): -+ -+ parser = OptionParser() -+ parser.add_option("--s","--stdout", action="callback", callback=lio_target_configfs_dump, nargs=0, -+ help="Dump running LIO-Target/ConfigFS syntax to STDOUT") -+ parser.add_option("--t", "--tofile", action="callback", callback=lio_backup_to_file, nargs=1, -+ type="string", dest="DATE_TIME", help="Backup running LIO-Target/ConfigFS syntax to /etc/target/backup/lio_backup-.sh") -+ -+ (options, args) = parser.parse_args() -+ if len(sys.argv) == 1: -+ parser.print_help() -+ sys.exit(0) -+ elif not re.search('--', sys.argv[1]): -+ print "Unknown CLI option: " + sys.argv[1] -+ sys.exit(1) -+ -+if __name__ == "__main__": -+ main() -diff --git a/targetcli/lio_node.py b/targetcli/lio_node.py -new file mode 100644 -index 0000000..de2c1e3 ---- /dev/null -+++ b/targetcli/lio_node.py -@@ -0,0 +1,1349 @@ -+import os, sys -+import subprocess as sub -+import string -+import re -+from optparse import OptionParser -+ -+tcm_root = "/sys/kernel/config/target/core" -+lio_root = "/sys/kernel/config/target/iscsi" -+alua_secondary_md_dir = "/var/target/alua/iSCSI/" -+ -+def lio_err(msg): -+ print msg -+ sys.exit(1) -+ -+def lio_alua_check_secondary_md(iqn, tpgt): -+ alua_sec_md_path = alua_secondary_md_dir + iqn + "+" + tpgt + "/" -+ if os.path.isdir(alua_sec_md_path) == False: -+ mkdir_op = "mkdir -p " + alua_sec_md_path -+ ret = os.system(mkdir_op) -+ if ret: -+ lio_err("Unable to create secondary ALUA MD directory: " + alua_sec_md_path) -+ -+ return -+ -+def lio_alua_delete_secondary_md(iqn, tpgt): -+ alua_sec_md_path = alua_secondary_md_dir + iqn + "+" + tpgt + "/" -+ if os.path.isdir(alua_sec_md_path) == False: -+ return -+ -+ rm_op = "rm -rf " + alua_sec_md_path -+ ret = os.system(rm_op) -+ if ret: -+ lio_err("Unable to remove secondary ALUA MD directory: " + alua_sec_md_path) -+ -+ return -+ -+def lio_alua_delete_secondary_md_port(iqn, tpgt, lun): -+ -+ alua_sec_md_file = alua_secondary_md_dir + iqn + "+" + tpgt + "/lun_" + lun -+ if os.path.isfile(alua_sec_md_file) == False: -+ return -+ -+ rm_op = "rm -rf "+ alua_sec_md_file -+ ret = os.system(rm_op) -+ if ret: -+ lio_err("Unable to delete ALUA secondary metadata file: " + alua_sec_md_file) -+ -+ return -+ -+def lio_alua_set_secondary_write_md(iqn, tpgt, lun): -+ alua_write_md_file = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun + "/alua_tg_pt_write_md" -+ if os.path.isfile(alua_write_md_file) == False: -+ return -+ -+ p = open(alua_write_md_file, 'w') -+ if not p: -+ lio_err("Unable to open: " + alua_write_md_file) -+ -+ ret = p.write("1") -+ if ret: -+ lio_err("Unable to enable writeable ALUA secondary metadata for " + alua_write_md_file) -+ -+ p.close() -+ return -+ -+def lio_alua_process_secondary_md(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ -+ alua_sec_md_file = alua_secondary_md_dir + iqn + "+" + tpgt + "/lun_" + lun -+ if os.path.isfile(alua_sec_md_file) == False: -+ # Use --aluasecmd as a chance to make sure the directory for this -+ # LIO-Target endpoint (iqn+tpgt) exists.. -+ lio_alua_check_secondary_md(iqn, tpgt) -+ lio_alua_set_secondary_write_md(iqn, tpgt, lun) -+ lio_err("Unable to locate ALUA secondary metadata file: " + alua_sec_md_file) -+ return -+ -+# print "Using alua_sec_md_file: " + alua_sec_md_file -+ alua_sec_cfs_path = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+# print "Using alua_sec_cfs_path: " + alua_sec_cfs_path -+ -+ p = open(alua_sec_md_file, 'rU') -+ if not p: -+ print "Unable to process ALUA secondary metadata for: " + alua_sec_md_file -+ -+ line = p.readline() -+ while line: -+ buf = line.rstrip() -+ -+ if re.search('alua_tg_pt_offline=', buf): -+ alua_tg_pt_offline = buf[19:] -+# print "Extracted alua_tg_pt_offline: " + alua_tg_pt_offline -+ cfs = open(alua_sec_cfs_path + "/alua_tg_pt_offline", 'w') -+ if not cfs: -+ p.close() -+ lio_err("Unable to open " + alua_sec_cfs_path + "/alua_tg_pt_offline") -+ -+ ret = cfs.write(alua_tg_pt_offline) -+ cfs.close() -+ if ret: -+ p.close() -+ lio_err("Unable to write " + alua_sec_cfs_path + "/alua_tg_pt_offline") -+ -+ elif re.search('alua_tg_pt_status=', buf): -+ alua_tg_pt_status = buf[18:] -+# print "Extracted alua_tg_pt_status: " + alua_tg_pt_status -+ cfs = open(alua_sec_cfs_path + "/alua_tg_pt_status", 'w') -+ if not cfs: -+ p.close() -+ lio_err("Unable to open " + alua_sec_cfs_path + "/alua_tg_pt_status") -+ -+ ret = cfs.write(alua_tg_pt_status) -+ cfs.close() -+ if ret: -+ p.close() -+ lio_err("Unable to write " + alua_sec_cfs_path + "/alua_tg_pt_status") -+ -+ line = p.readline() -+ -+ p.close() -+ # Now enable the alua_tg_pt_write_md bit to allow for new updates -+ # to ALUA secondary metadata in struct file for this port -+ lio_alua_set_secondary_write_md(iqn, tpgt, lun) -+ return -+ -+def __lio_target_del_iqn(option, opt_str, value, parser, delete_tpg_md): -+ iqn = str(value); -+ iqn = iqn.lower(); -+ -+# Loop through LIO-Target IQN+TPGT list -+ tpg_root = os.listdir(lio_root + "/" + iqn); -+ for tpgt_tmp in tpg_root: -+ if tpgt_tmp == "fabric_statistics": -+ continue -+ -+ tpgt_tmp2 = tpgt_tmp.split('_') -+ tpgt = tpgt_tmp2[1] -+ -+ tpg_val = [iqn,tpgt] -+ if delete_tpg_md == 1: -+ lio_target_del_tpg(None, None, tpg_val, None) -+ else: -+ __lio_target_del_tpg(None, None, tpg_val, None, 0) -+ -+ rmdir_op = "rmdir " + lio_root + "/" + iqn -+# print "rmdir_op: " + rmdir_op -+ ret = os.system(rmdir_op) -+ if not ret: -+ print "Successfully released iSCSI Target Endpoint IQN: " + iqn -+ else: -+ lio_err("Unable to release iSCSI Target Endpoint IQN: " + iqn) -+ -+ return -+ -+def lio_target_del_iqn(option, opt_str, value, parser): -+ iqn = str(value); -+ iqn = iqn.lower(); -+ -+ iqn_dir = lio_root + "/" + iqn -+ if os.path.isdir(iqn_dir) == False: -+ lio_err("Unable to locate iSCSI Target IQN: " + iqn_dir) -+ -+ # Passing 1 for delete_tpg_md here means lio_target_del_tpg() -+ # with lio_alua_delete_secondary_md() will get called to delete -+ # all of the secondary ALUA directories for the LIO-Target endpoint -+ # when an explict --deliqn is called. -+ __lio_target_del_iqn(option, opt_str, value, parser, 1) -+ -+ return -+ -+def __lio_target_del_tpg(option, opt_str, value, parser, delete_tpg_md): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ # This will set TPG Status to INACTIVE force all of the iSCSI sessions for this -+ # tiqn+tpgt tuple to be released. -+ disable_op = "echo 0 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/enable" -+ ret = os.system(disable_op) -+ if ret: -+ print "Unable to disable TPG: " + iqn + " TPGT: " + tpgt -+ -+ np_root = os.listdir(lio_root + "/" + iqn + "/tpgt_" + tpgt + "/np") -+ for np in np_root: -+ np_val = [iqn,tpgt,np] -+ -+ lio_target_del_np(None, None, np_val, None) -+ -+ nacl_root = os.listdir(lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls") -+ for nacl in nacl_root: -+ nacl_val = [iqn,tpgt,nacl] -+ -+ lio_target_del_nodeacl(None, None, nacl_val, None) -+ -+ lun_root = os.listdir(lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun") -+ for lun_tmp in lun_root: -+ lun_tmp2 = lun_tmp.split('_') -+ lun = lun_tmp2[1] -+ -+ lun_val = [iqn,tpgt,lun] -+ if delete_tpg_md == 1: -+ lio_target_del_port(None, None, lun_val, None) -+ else: -+ __lio_target_del_port(None, None, lun_val, None) -+ -+ -+ rmdir_op = "rmdir " + lio_root + "/" + iqn + "/tpgt_" + tpgt -+# print "rmdir_op: " + rmdir_op -+ ret = os.system(rmdir_op) -+ if not ret: -+ print "Successfully released iSCSI Target Portal Group: " + iqn + " TPGT: " + tpgt -+ else: -+ lio_err("Unable to release iSCSI Target Portal Group: " + iqn + " TPGT: " + tpgt) -+ -+ return -+ -+def lio_target_del_tpg(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ tpgt_file = lio_root + "/" + iqn + "/tpgt_" + tpgt -+ if os.path.isdir(tpgt_file) == False: -+ lio_err("iSCSI Target Port Group: " + tpgt_file + " does not exist") -+ -+ __lio_target_del_tpg(option, opt_str, value, parser, 1) -+ # Delete the ALUA secondary metadata directory on explict --deltpg or -+ # called from --deliqn -+ lio_alua_delete_secondary_md(iqn, tpgt) -+ return -+ -+def lio_target_add_np(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ np = str(value[2]); -+ -+ # Append default iSCSI Port is non is given. -+ if re.search(']', np)and not re.search(']:', np): -+ np = np + ":3260" -+ elif re.search(':\\Z', np): -+ np = np + "3260" -+ elif not re.search(':', np): -+ np = np + ":3260" -+ -+ # Extract the iSCSI port and make sure it is a valid u16 value -+ if re.search(']:', np): -+ off = np.index(']:') -+ off += 2 -+ port = int(np[off:]) -+ else: -+ off = np.index(':') -+ off += 1 -+ port = int(np[off:]) -+ -+ if port == 0 or port > 65535: -+ lio_err("Illegal port value: " + str(port) + " for iSCSI network portal") -+ -+ mkdir_op = "mkdir -p " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/np/" + np -+# print "mkdir_op: " + mkdir_op -+ ret = os.system(mkdir_op) -+ if not ret: -+ print "Successfully created network portal: " + np + " created " + iqn + " TPGT: " + tpgt -+ lio_alua_check_secondary_md(iqn, tpgt) -+ else: -+ lio_err("Unable to create network portal: " + np + " created " + iqn + " TPGT: " + tpgt) -+ -+ return -+ -+def lio_target_del_np(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ np = str(value[2]); -+ -+ rmdir_op = "rmdir " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/np/" + np -+# print "rmdir_op: " + rmdir_op -+ ret = os.system(rmdir_op) -+ if not ret: -+ print "Successfully released network portal: " + np + " created " + iqn + " TPGT: " + tpgt -+ else: -+ lio_err("Unable to release network portal: " + np + " created " + iqn + " TPGT: " + tpgt) -+ -+ return -+ -+def lio_target_add_port(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ port_name = str(value[3]); -+ tcm_obj = str(value[4]); -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ if os.path.isdir(lun_dir): -+ lio_err("iSCSI Target Logical Unit ConfigFS directory already exists") -+ -+ mkdir_op = "mkdir -p " + lun_dir -+# print "mkdir_op: " + mkdir_op -+ ret = os.system(mkdir_op) -+ if ret: -+ lio_err("Unable to create iSCSI Target Logical Unit ConfigFS directory") -+ -+ port_src = tcm_root + "/" + tcm_obj -+ port_dst = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun + "/" + port_name -+ link_op = "ln -s " + port_src + " " + port_dst -+# print "link_op: " + link_op -+ ret = os.system(link_op) -+ if not ret: -+ print "Successfully created iSCSI Target Logical Unit" -+ lio_alua_check_secondary_md(iqn, tpgt) -+ lio_alua_set_secondary_write_md(iqn, tpgt, lun) -+ else: -+ os.rmdir(lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun) -+ lio_err("Unable to create iSCSI Target Logical Unit symlink") -+ -+ return -+ -+def lio_target_add_tpg(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ tpg_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt -+ if os.path.isdir(tpg_dir): -+ lio_err("iSCSI Target Portal Group directory already exists") -+ -+ mkdir_op = "mkdir -p " + tpg_dir -+ ret = os.system(mkdir_op) -+ if ret: -+ lio_err("Unable to create iSCSI Target Portal Group ConfigFS directory") -+ else: -+ print "Successfully created iSCSI Target Portal Group" -+ lio_alua_check_secondary_md(iqn, tpgt) -+ -+ return -+ -+def __lio_target_del_port(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ port_root = os.listdir(lun_dir) -+ -+ for port in port_root: -+ if port == "alua_tg_pt_gp": -+ continue -+ if port == "alua_tg_pt_offline": -+ continue -+ if port == "alua_tg_pt_status": -+ continue -+ if port == "alua_tg_pt_write_md": -+ continue -+ -+ if not os.path.islink(lun_dir + "/" + port): -+ continue -+ -+ unlink_op = "unlink " + lun_dir + "/" + port -+# print "del_portunlink_op: " + unlink_op -+ ret = os.system(unlink_op) -+ if ret: -+ lio_err("Unable to unlink iSCSI Target Logical Unit") -+ -+ rmdir_op= "rmdir " + lun_dir -+# print "del_port rmdir_op: " + rmdir_op -+ ret = os.system(rmdir_op); -+ if not ret: -+ print "Successfully deleted iSCSI Target Logical Unit" -+ else: -+ lio_err("Unable to rmdir iSCSI Target Logical Unit configfs directory") -+ -+ return -+ -+def lio_target_del_port(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ if os.path.isdir(lun_dir) == False: -+ lio_err("LIO-Target Port/LUN directory: " + lun_dir + " does not exist") -+ -+ __lio_target_del_port(option, opt_str, value, parser) -+ # Delete the ALUA secondary metadata file for this Port/LUN -+ # during an explict --dellun -+ lio_alua_delete_secondary_md_port(iqn, tpgt, lun) -+ -+ return -+ -+def lio_target_tpg_disableauth(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ enable_op = "echo 0 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib/authentication" -+ ret = os.system(enable_op) -+ if ret: -+ lio_err("Unable to disable iSCSI Authentication on iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully disabled iSCSI Authentication on iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_tpg_demomode(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ enable_op = "echo 1 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib/generate_node_acls" -+ ret = os.system(enable_op) -+ if ret: -+ lio_err("Unable to disable Initiator ACL mode (Enable DemoMode) on iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully disabled Initiator ACL mode (Enabled DemoMode) on iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_disable_lunwp(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ mapped_lun = str(value[3]); -+ -+ disable_op = "echo 0 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/lun_" + mapped_lun + "/write_protect" -+ ret = os.system(disable_op) -+ if ret: -+ lio_err("Unable to disable WriteProtect for Mapped LUN: " + mapped_lun + " for " + initiator_iqn + " on iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully disabled WRITE PROTECT for Mapped LUN: " + mapped_lun + " for " + initiator_iqn + " on iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_enable_auth(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ enable_op = "echo 1 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib/authentication" -+ ret = os.system(enable_op) -+ if ret: -+ lio_err("Unable to enable iSCSI Authentication on iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully enabled iSCSI Authentication on iSCSI Target Portal Group: " + iqn + " " + tpgt -+ return -+ -+def lio_target_enable_lunwp(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ mapped_lun = str(value[3]); -+ -+ enable_op = "echo 1 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/lun_" + mapped_lun + "/write_protect" -+ ret = os.system(enable_op) -+ if ret: -+ lio_err("Unable to enable WriteProtect for Mapped LUN: " + mapped_lun + " for " + initiator_iqn + " on iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully enabled WRITE PROTECT for Mapped LUN: " + mapped_lun + " for " + initiator_iqn + " on iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_enable_tpg(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ enable_op = "echo 1 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/enable" -+ ret = os.system(enable_op) -+ if ret: -+ lio_err("Unable to enable iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully enabled iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_disable_tpg(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ disable_op = "echo 0 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/enable" -+ ret = os.system(disable_op) -+ if ret: -+ lio_err("Unable to disable iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully disabled iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_enableaclmode(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ enable_op = "echo 0 > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib/generate_node_acls" -+ ret = os.system(enable_op) -+ if ret: -+ lio_err("Unable to enable Initiator ACL mode (Disabled DemoMode) on iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully enabled Initiator ACL mode (Disabled DemoMode) on iSCSI Target Portal Group: " + iqn + " " + tpgt -+ return -+ -+ -+def lio_target_add_lunacl(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ tpg_lun = str(value[3]); -+ mapped_lun = str(value[4]); -+ -+ mkdir_op = "mkdir -p " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/lun_" + mapped_lun -+ ret = os.system(mkdir_op) -+ if ret: -+ lio_err("Unable to add iSCSI Initiator Mapped LUN: " + mapped_lun + " ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ addlunacl_op = "ln -s " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + tpg_lun + " " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/lun_" + mapped_lun + "/lio_lun" -+ -+ ret = os.system(addlunacl_op) -+ if ret: -+ lio_err("Unable to add iSCSI Initiator Mapped LUN: " + mapped_lun + " ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully added iSCSI Initiator Mapped LUN: " + mapped_lun + " ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt -+ lio_alua_check_secondary_md(iqn, tpgt) -+ -+ return -+ -+def lio_target_del_lunacl(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ mapped_lun = str(value[3]); -+ -+ lun_link_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/lun_" + mapped_lun -+ for lun_acl_link in os.listdir(lun_link_dir): -+ if lun_acl_link == "write_protect": -+ continue -+ -+ if not os.path.islink(lun_link_dir + "/" + lun_acl_link): -+ continue; -+ -+ unlink_op = "unlink " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/lun_" + mapped_lun + "/" + lun_acl_link -+# print "unlink_op: " + unlink_op -+ ret = os.system(unlink_op) -+ if ret: -+ lio_err("Unable to unlink iSCSI Initiator Mapped LUN: " + mapped_lun + " ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ dellunacl_op = "rmdir " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/lun_" + mapped_lun -+ ret = os.system(dellunacl_op) -+ if ret: -+ lio_err("Unable to delete iSCSI Initiator Mapped LUN: " + mapped_lun + " ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully deleted iSCSI Initiator Mapped LUN: " + mapped_lun + " ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_add_nodeacl(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ -+ addnodeacl_op = "mkdir -p " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn -+ ret = os.system(addnodeacl_op) -+ if ret: -+ lio_err("Unable to add iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully added iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt -+ lio_alua_check_secondary_md(iqn, tpgt) -+ -+ return -+ -+def lio_target_del_nodeacl(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ -+ nacl_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn -+ lun_acl_root = os.listdir(nacl_dir) -+ for lun_acl in lun_acl_root: -+ ret = re.search('lun_', lun_acl) -+ if not ret: -+ continue -+ lun_delacl_val = [iqn,tpgt,initiator_iqn,lun_acl[4:]] -+ lio_target_del_lunacl(None, None, lun_delacl_val, None) -+ -+ delnodeacl_op = "rmdir " + nacl_dir -+ ret = os.system(delnodeacl_op) -+ if ret: -+ lio_err("Unable to delete iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully deleted iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_set_chap_auth(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ user = str(value[3]); -+ password = str(value[4]); -+ -+ auth_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/auth/" -+ -+ if not os.path.isdir(auth_dir): -+ lio_err("iSCSI Initiator ACL " + initiator_iqn + " does not exist for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ setuser_op = "echo -n " + user + " > " + auth_dir + "/userid" -+ ret = os.system(setuser_op) -+ if ret: -+ lio_err("Unable to set CHAP username for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ setpassword_op = "echo -n " + password + " > " + auth_dir + "/password" -+ ret = os.system(setpassword_op) -+ if ret: -+ lio_err("Unable to set CHAP password for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully set CHAP authentication for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_set_chap_mutual_auth(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ user_mutual = str(value[3]); -+ password_mutual = str(value[4]); -+ -+ auth_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/auth/" -+ -+ if not os.path.isdir(auth_dir): -+ lio_err("iSCSI Initiator ACL " + initiator_iqn + " does not exist for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ setuser_op = "echo -n " + user_mutual + " > " + auth_dir + "/userid_mutual" -+ ret = os.system(setuser_op) -+ if ret: -+ lio_err("Unable to set mutual CHAP username for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ setpassword_op = "echo -n " + password_mutual + " > " + auth_dir + "/password_mutual" -+ ret = os.system(setpassword_op) -+ if ret: -+ lio_err("Unable to set mutual CHAP password for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully set mutual CHAP authentication for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_set_chap_discovery_auth(option, opt_str, value, parser): -+ user = str(value[0]); -+ password = str(value[1]); -+ -+ auth_dir = lio_root + "/discovery_auth" -+ if not os.path.isdir(auth_dir): -+ lio_err("iSCSI Discovery Authentication directory " + auth_dir + " does not exist") -+ -+ setuser_op = "echo -n " + user + " > " + auth_dir + "/userid" -+ ret = os.system(setuser_op) -+ if ret: -+ lio_err("Unable to set CHAP username for iSCSI Discovery Authentication") -+ -+ setpassword_op = "echo -n " + password + " > " + auth_dir + "/password" -+ ret = os.system(setpassword_op) -+ if ret: -+ lio_err("Unable to set CHAP password for iSCSI Discovery Authentication") -+ else: -+ print "Successfully set CHAP authentication for iSCSI Discovery Authentication" -+ -+ return -+ -+def lio_target_set_chap_mutual_discovery_auth(option, opt_str, value, parser): -+ user_mutual = str(value[0]); -+ password_mutual = str(value[1]); -+ -+ auth_dir = lio_root + "/discovery_auth" -+ if not os.path.isdir(auth_dir): -+ lio_err("iSCSI Discovery Authentication directory " + auth_dir + " does not exist") -+ -+ setuser_op = "echo -n " + user_mutual + " > " + auth_dir + "/userid_mutual" -+ ret = os.system(setuser_op) -+ if ret: -+ lio_err("Unable to set mutual CHAP username for iSCSI Discovery Authentication") -+ -+ setpassword_op = "echo -n " + password_mutual + " > " + auth_dir + "/password_mutual" -+ ret = os.system(setpassword_op) -+ if ret: -+ lio_err("Unable to set mutual CHAP password for iSCSI Discovery Authentication") -+ else: -+ print "Successfully set mutual CHAP authentication for iSCSI Discovery Authentication" -+ -+ return -+ -+def lio_target_set_enforce_discovery_auth(option, opt_str, value, parser): -+ value = str(value); -+ -+ da_attr = lio_root + "/discovery_auth/enforce_discovery_auth" -+ if not os.path.isfile(da_attr): -+ lio_err("iSCSI Discovery Authentication directory does not exist") -+ -+ da_op = "echo " + value + " > " + da_attr; -+ ret = os.system(da_op) -+ if ret: -+ lio_err("Unable to set da_attr: " + da_attr) -+ -+ if value == "1": -+ print "Successfully enabled iSCSI Discovery Authentication enforcement" -+ else: -+ print "Successfully disabled iSCSI Discovery Authentication enforcement" -+ -+ return -+ -+ -+def lio_target_set_node_tcq(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ depth = str(value[3]); -+ -+ setnodetcq_op = "echo " + depth + " > " + lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/cmdsn_depth" -+ ret = os.system(setnodetcq_op) -+ if ret: -+ lio_err("Unable to set TCQ: " + depth + " for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ else: -+ print "Successfully set TCQ: " + depth + " for iSCSI Initaitor ACL " + initiator_iqn + " for iSCSI Target Portal Group: " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_alua_set_tgptgp(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ tg_pt_gp_name = str(value[3]) -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ if not os.path.isdir(lun_dir): -+ lio_err("LIO-Target Port/LUN: " + lun + " does not exist on: " + iqn + " " + tpgt) -+ -+ set_tp_pt_gp_op = "echo " + tg_pt_gp_name + " > " + lun_dir + "/alua_tg_pt_gp" -+ ret = os.system(set_tp_pt_gp_op) -+ if ret: -+ lio_err("Unable to set ALUA Target Port Group: " + tg_pt_gp_name + " for LUN: " + lun + " on " + iqn + " " + tpgt) -+ else: -+ print "Successfully set ALUA Target Port Group: " + tg_pt_gp_name + " for LUN: " + lun + " on " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_alua_set_tgpt_offline(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ if not os.path.isdir(lun_dir): -+ lio_err("LIO-Target Port/LUN: " + lun + " does not exist on: " + iqn + " " + tpgt) -+ -+ set_tg_pt_gp_offline_op = "echo 1 > " + lun_dir + "/alua_tg_pt_offline" -+ ret = os.system(set_tg_pt_gp_offline_op) -+ if ret: -+ lio_err("Unable to set ALUA secondary state OFFLINE bit for LUN: " + lun + " on " + iqn + " " + tpgt) -+ else: -+ print "Successfully set ALUA secondary state OFFLINE for LUN: " + lun + " on " + iqn + " " + tpgt -+ -+ return -+ -+def lio_target_alua_clear_tgpt_offline(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ if not os.path.isdir(lun_dir): -+ lio_err("LIO-Target Port/LUN: " + lun + " does not exist on: " + iqn + " " + tpgt) -+ -+ set_tg_pt_gp_offline_op = "echo 0 > " + lun_dir + "/alua_tg_pt_offline" -+ ret = os.system(set_tg_pt_gp_offline_op) -+ if ret: -+ lio_err("Unable to clear ALUA secondary state OFFLINE for LUN: " + lun + " on " + iqn + " " + tpgt) -+ else: -+ print "Successfully cleared ALUA secondary state OFFLINE for LUN: " + lun + " on " + iqn + " " + tpgt -+ return -+ -+def lio_target_show_chap_auth(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ -+ auth_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/auth/" -+ -+ if not os.path.isdir(auth_dir): -+ lio_err("iSCSI Initiator ACL " + initiator_iqn + " does not exist for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ for auth in os.listdir(auth_dir): -+ p = os.open(auth_dir + "/" + auth, 0) -+ value = os.read(p, 256) -+ print auth + ": " + value.rstrip() -+ os.close(p) -+ -+ return -+ -+def lio_target_show_chap_discovery_auth(option, opt_str, value, parser): -+ -+ auth_dir = lio_root + "/discovery_auth" -+ if not os.path.isdir(auth_dir): -+ lio_err("iSCSI Discovery Authentication directory " + auth_dir + " does not exist") -+ -+ for auth in os.listdir(auth_dir): -+ p = os.open(auth_dir + "/" + auth, 0) -+ value = os.read(p, 256) -+ print auth + ": " + value.rstrip() -+ os.close(p) -+ -+ return -+ -+def lio_target_show_node_tcq(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]); -+ initiator_iqn = initiator_iqn.lower(); -+ -+ nacl = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn -+ if not os.path.isdir(nacl): -+ lio_err("iSCSI Initiator ACL: " + initiator_iqn + " does not exist for iSCSI Target Portal Group: " + iqn + " " + tpgt) -+ -+ tcq_depth_file = nacl + "/cmdsn_depth" -+ p = os.open(tcq_depth_file, 0) -+ value = os.read(p, 8) -+ print value.rstrip() -+ os.close(p) -+ -+ return -+ -+def lio_target_alua_show_tgptgp(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ lun = str(value[2]); -+ -+ lun_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ if not os.path.isdir(lun_dir): -+ lio_err("LIO-Target Port/LUN: " + lun + " does not exist on: " + iqn + " " + tpgt) -+ -+ show_tp_pt_gp_op = "cat " + lun_dir + "/alua_tg_pt_gp" -+ ret = os.system(show_tp_pt_gp_op) -+ if ret: -+ lio_err("Unable to show ALUA Target Port Group: " + tg_pt_gp_name + " for LUN: " + lun + " on " + iqn + " " + tpgt) -+ -+ return -+ -+def lio_target_list_endpoints(option, opt_str, value, parser): -+ -+ iqn_root = os.listdir(lio_root) -+ -+ for iqn in iqn_root: -+ if iqn == "lio_version": -+ continue -+ if iqn == "discovery_auth": -+ continue -+ -+ print "\------> " + iqn -+ -+ tpg_root = lio_root + "/" + iqn -+ for tpg in os.listdir(tpg_root): -+ if tpg == "fabric_statistics": -+ continue -+ -+ p = os.open(tpg_root + "/" + tpg + "/param/TargetAlias", 0) -+ value = os.read(p, 256) -+ print " \-------> " + tpg + " TargetAlias: " + value.rstrip() -+ os.close(p) -+ -+ print " TPG Status:", -+ p = os.open(tpg_root + "/" + tpg + "/enable", 0) -+ value = os.read(p, 8) -+ enable_bit = value.rstrip(); -+ if enable_bit == '1': -+ print "ENABLED" -+ else: -+ print "DISABLED" -+ os.close(p) -+ -+ print " TPG Network Portals:" -+ np_root = tpg_root + "/" + tpg + "/np" -+ for np in os.listdir(np_root): -+ print " \-------> " + np -+ -+ print " TPG Logical Units:" -+ lun_root = tpg_root + "/" + tpg + "/lun" -+ for lun in os.listdir(lun_root): -+ port_dir = lun_root + "/" + lun -+ for port in os.listdir(port_dir): -+ if port == "alua_tg_pt_gp": -+ continue -+ if port == "alua_tg_pt_offline": -+ continue -+ if port == "alua_tg_pt_status": -+ continue -+ if port == "alua_tg_pt_write_md": -+ continue -+ if port == "statistics": -+ continue -+ -+ port_link = port_dir + "/" + port -+ if not os.path.islink(port_link): -+ continue -+ -+ sourcelink = os.readlink(port_link) -+ # Skip over ../../../../../ in sourcelink" -+ print " \-------> " + lun + "/" + port + " -> " + sourcelink[18:] -+ -+ -+ return -+ -+def lio_target_list_lunacls(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ iqn_root = os.listdir(lio_root) -+ -+ nacl_root_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls" -+ nacl_root = os.listdir(nacl_root_dir) -+ for nacl in nacl_root: -+ print "\------> InitiatorName ACL: " + nacl -+ print " Logical Unit ACLs: " -+ lun_root_dir = nacl_root_dir + "/" + nacl -+ lun_root = os.listdir(lun_root_dir) -+ for lun in lun_root: -+ ret = re.search('lun_', lun) -+ if not ret: -+ continue -+ -+ wp_attrib = lun_root_dir + "/" + lun + "/write_protect" -+ wp_file = open(wp_attrib); -+ line = wp_file.readline() -+ wp_bit = line.rstrip() -+ if wp_bit == '1': -+ wp_info = "ENABLED" -+ else: -+ wp_info = "DISABLED" -+ -+ lun_link_dir = lun_root_dir + "/" + lun -+ for lun_link in os.listdir(lun_link_dir): -+ if lun_link == "write_protect": -+ continue -+ if lun_link == "statistics": -+ continue -+ -+ if not os.path.islink(lun_link_dir + "/" + lun_link): -+ continue -+ -+ sourcelink = os.readlink(lun_link_dir + "/" + lun_link) -+ # Skip over ../../../../../../ in sourcelink" -+ print " \-------> " + lun + " -> " + sourcelink[21:] -+ print " \-------> Write Protect for " + lun + ": " + wp_info -+ -+ return -+ -+def lio_target_list_nodeacls(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ iqn_root = os.listdir(lio_root) -+ -+ nacl_root_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls" -+ nacl_root = os.listdir(nacl_root_dir) -+ for nacl in nacl_root: -+ print "\------> InitiatorName: " + nacl -+ info_attrib = nacl_root_dir + "/" + nacl + "/info" -+ file = open(info_attrib, "r") -+ line = file.readline() -+ ret = re.search('No active iSCSI Session for Initiator Endpoint', line) -+ if ret: -+ print " No active iSCSI Session for Initiator Endpoint" -+ else: -+ line = file.readline() -+ while line: -+ print " " + line.rstrip() -+ line = file.readline() -+ -+ file.close() -+ -+ return -+ -+def lio_target_list_nps(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ np_root = os.listdir(lio_root + "/" + iqn + "/tpgt_" + tpgt + "/np") -+ for np in np_root: -+ print np -+ -+ return -+ -+def lio_target_list_targetnames(option, opt_str, value, parser): -+ -+ iqn_root = os.listdir(lio_root) -+ -+ # Loop through LIO-Target IQN list -+ for iqn in iqn_root: -+ if iqn == "lio_version": -+ continue -+ if iqn == "discovery_auth": -+ continue -+ -+ print iqn -+ -+ return -+ -+def lio_target_list_node_attr(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]) -+ -+ attr_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/attrib/" -+ if os.path.isdir(attr_dir) == False: -+ lio_err("Unable to locate node attr_dir: " + attr_dir) -+ -+ for attr in os.listdir(attr_dir): -+ p = open(attr_dir + "/" + attr, 'rU') -+ if not p: -+ lio_err("Unable to open attr: " + attr_dir + "/" + attr) -+ -+ val = p.read() -+ p.close() -+ -+ print attr + "=" + val.rstrip() -+ -+ return -+ -+def lio_target_set_node_attr(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]) -+ attr = str(value[3]) -+ val = str(value[4]) -+ -+ attr_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/attrib/" -+ if os.path.isdir(attr_dir) == False: -+ lio_err("Unable to locate node attr_dir: " + attr_dir) -+ -+ p = open(attr_dir + "/" + attr, 'w') -+ if not p: -+ lio_err("Unable to open node attr: " + attr_dir + "/" + attr) -+ -+ ret = p.write(val) -+ if ret: -+ lio_err("Unable to set node attr: " + attr_dir + "/" + attr) -+ -+ p.close() -+ print "Successfully set Initiator Node attribute: " + attr + " to: " + val -+ -+ return -+ -+def lio_target_list_node_param(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ initiator_iqn = str(value[2]) -+ -+ param_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" + initiator_iqn + "/param" -+ if os.path.isdir(param_dir) == False: -+ lio_err("Unable to locate node param_dir: " + param_dir) -+ -+ for param in os.listdir(param_dir): -+ p = open(param_dir + "/" + param, 'rU') -+ if not p: -+ lio_err("Unable to open attr: " + param_dir + "/" + param) -+ -+ val = p.read() -+ p.close() -+ -+ print param + "=" + val.rstrip() -+ -+ return -+ -+ -+def lio_target_list_tpg_attr(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ attr_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib" -+ if os.path.isdir(attr_dir) == False: -+ lio_err("Unable to locate tpg attr_dir: " + attr_dir) -+ -+ for attr in os.listdir(attr_dir): -+ p = open(attr_dir + "/" + attr, 'rU') -+ if not p: -+ lio_err("Unable to open attr: " + attr_dir + "/" + attr) -+ -+ val = p.read() -+ p.close() -+ -+ print attr + "=" + val.rstrip() -+ -+ return -+ -+def lio_target_set_tpg_attr(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ attr = str(value[2]); -+ val = str(value[3]); -+ -+ attr_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib" -+ if os.path.isdir(attr_dir) == False: -+ lio_err("Unable to locate tpg attr_dir: " + attr_dir) -+ -+ p = open(attr_dir + "/" + attr, 'w') -+ if not p: -+ lio_err("Unable to open tpg attr: " + attr_dir + "/" + attr) -+ -+ ret = p.write(val) -+ if ret: -+ lio_err("Unable to set tpg attr: " + attr_dir + "/" + attr) -+ -+ p.close() -+ print "Successfully set TPG attribute: " + attr + " to: " + val -+ -+ return -+ -+def lio_target_list_tpg_param(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ -+ param_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/param" -+ if os.path.isdir(param_dir) == False: -+ lio_err("Unable to locate tpg param dir: " + param_dir) -+ -+ for param in os.listdir(param_dir): -+ p = open(param_dir + "/" + param, 'rU') -+ if not p: -+ lio_err("Unable to open param: " + param_dir + "/" + param) -+ -+ val = p.read() -+ p.close() -+ -+ print param + "=" + val.rstrip() -+ -+ return -+ -+def lio_target_set_tpg_param(option, opt_str, value, parser): -+ iqn = str(value[0]); -+ iqn = iqn.lower(); -+ tpgt = str(value[1]); -+ param = str(value[2]); -+ val = str(value[3]); -+ -+ param_dir = lio_root + "/" + iqn + "/tpgt_" + tpgt + "/param" -+ if os.path.isdir(param_dir) == False: -+ lio_err("Unable to locate tpg param dir: " + param_dir) -+ -+ p = open(param_dir + "/" + param, 'w') -+ if not p: -+ lio_err("Unable to open tpg attr: " + param_dir + "/" + param) -+ -+ val = val + " " -+ ret = p.write(val) -+ if ret: -+ lio_err("Unable to write tpg attr: " + param_dir + "/" + param) -+ -+ p.close() -+ print "Successfully set TPG parameter: " + param + " to: " + val -+ -+ return -+ -+def lio_target_unload(option, opt_str, value, parser): -+ -+ if not os.path.isdir(lio_root): -+ lio_err("Unable to access lio_root: " + lio_root) -+ -+ iqn_root = os.listdir(lio_root) -+ -+ # Loop through LIO-Target IQN list -+ for iqn in iqn_root: -+ if iqn == "lio_version": -+ continue -+ if iqn == "discovery_auth": -+ continue -+ -+ # Loop through LIO-Target IQN+TPGT list -+ tpg_root = os.listdir(lio_root + "/" + iqn); -+ for tpgt_tmp in tpg_root: -+ if tpgt_tmp == "fabric_statistics": -+ continue -+ -+ tpgt_tmp2 = tpgt_tmp.split('_') -+ tpgt = tpgt_tmp2[1] -+ -+ tpg_val = [iqn,tpgt] -+ __lio_target_del_tpg(None, None, tpg_val, None, 0) -+ -+ __lio_target_del_iqn(None, None, iqn, None, 0) -+ -+ rmdir_op = "rmdir " + lio_root -+ ret = os.system(rmdir_op) -+ if ret: -+ print "Unable to release lio_root: " + lio_root -+ -+ rmmod_op = "rmmod iscsi_target_mod" -+ ret = os.system(rmmod_op) -+ if ret: -+ print "Unable to unload iscsi_target_mod" -+ -+ return -+ -+def lio_target_version(option, opt_str, value, parser): -+ -+ os.system("cat /sys/kernel/config/target/iscsi/lio_version") -+ return -+ -+def main(): -+ -+ parser = OptionParser() -+ parser.add_option("--addlunacl", action="callback", callback=lio_target_add_lunacl, nargs=5, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN TPG_LUN MAPPED_LUN", help="Add iSCSI Initiator LUN ACL to LIO-Target Portal Group LUN") -+ parser.add_option("--addnodeacl", action="callback", callback=lio_target_add_nodeacl, nargs=3, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN", help="Add iSCSI Initiator ACL to LIO-Target Portal Group") -+ parser.add_option("--addnp", action="callback", callback=lio_target_add_np, nargs=3, -+ type="string", dest="TARGET_IQN TPGT IP:PORT", help="Add LIO-Target IPv6 or IPv4 network portal") -+ parser.add_option("--addlun", action="callback", callback=lio_target_add_port, nargs=5, -+ type="string", dest="TARGET_IQN TPGT LUN PORT_ALIAS TCM_HBA/DEV ", help="Create LIO-Target Logical Unit") -+ parser.add_option("--addtpg", action="callback", callback=lio_target_add_tpg, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Create LIO-Target portal group") -+ parser.add_option("--aluasecmd", action="callback", callback=lio_alua_process_secondary_md, nargs=3, -+ type="string", dest="TARGET_IQN TPGT LUN", help="Process ALUA secondary metadata for Port/LUN"); -+ parser.add_option("--cleartgptoff","--clearaluaoff", action="callback", callback=lio_target_alua_clear_tgpt_offline, nargs=3, -+ type="string", dest="TARGET_IQN TPGT LUN", help="Clear ALUA Target Port Secondary State OFFLINE") -+ parser.add_option("--dellunacl", action="callback", callback=lio_target_del_lunacl, nargs=4, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN MAPPED_LUN", help="Delete iSCSI Initiator LUN ACL from LIO-Target Portal Group LUN") -+ parser.add_option("--delnodeacl", action="callback", callback=lio_target_del_nodeacl, nargs=3, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN", help="Delete iSCSI Initiator ACL from LIO-Target Portal Group") -+ parser.add_option("--delnp", action="callback", callback=lio_target_del_np, nargs=3, -+ type="string", dest="TARGET_IQN TPGT IP:PORT", help="Delete LIO-Target IPv6 or IPv4 network portal") -+ parser.add_option("--deliqn", action="callback", callback=lio_target_del_iqn, nargs=1, -+ type="string", dest="TARGET_IQN", help="Delete LIO-Target IQN Endpoint") -+ parser.add_option("--dellun", action="callback", callback=lio_target_del_port, nargs=3, -+ type="string", dest="TARGET_IQN TPGT LUN", help="Delete LIO-Target Logical Unit") -+ parser.add_option("--deltpg", action="callback", callback=lio_target_del_tpg, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Delete LIO-Target Portal Group") -+ parser.add_option("--demomode", "--permissive", action="callback", callback=lio_target_tpg_demomode, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Disable all iSCSI Initiator ACL requirements (enable DemoMode) for LIO-Target Portal Group (Disabled by default)") -+ parser.add_option("--disableauth", action="callback", callback=lio_target_tpg_disableauth, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Disable iSCSI Authentication for LIO-Target Portal Group (Enabled by default)") -+ parser.add_option("--disablelunwp", action="callback", callback=lio_target_disable_lunwp, nargs=4, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN MAPPED_LUN", help="Clear Write Protect bit for iSCSI Initiator LUN ACL") -+ parser.add_option("--disabletpg", action="callback", callback=lio_target_disable_tpg, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Disable LIO-Target Portal Group") -+ parser.add_option("--enableaclmode", action="callback", callback=lio_target_enableaclmode, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Enable iSCSI Initiator ACL requirement mode for LIO-Target Portal Group (Enabled by default)") -+ parser.add_option("--enableauth", action="callback", callback=lio_target_enable_auth, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Enable iSCSI Authentication for LIO-Target Portal Group (Enabled by default)") -+ parser.add_option("--enablelunwp", action="callback", callback=lio_target_enable_lunwp, nargs=4, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN MAPPED_LUN", help="Set Write Protect bit for iSCSI Initiator LUN ACL") -+ parser.add_option("--enabletpg", action="callback", callback=lio_target_enable_tpg, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="Enable LIO-Target Portal Group") -+ parser.add_option("--listendpoints", action="callback", callback=lio_target_list_endpoints, nargs=0, -+ help="List iSCSI Target Endpoints") -+ parser.add_option("--listlunacls", action="callback", callback=lio_target_list_lunacls, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="List iSCSI Initiator LUN ACLs for LIO-Target Portal Group") -+ parser.add_option("--listnodeacls", action="callback", callback=lio_target_list_nodeacls, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="List iSCSI Initiator ACLs for LIO-Target Portal Group") -+ parser.add_option("--listnodeattr", action="callback", callback=lio_target_list_node_attr, nargs=3, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN", help="List iSCSI Initiator ACL attributes for LIO-Target Portal Group") -+ parser.add_option("--listnodeparam", action="callback", callback=lio_target_list_node_param, nargs=3, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN", help="List iSCSI Initiator ACL RFC-3720 parameters for LIO-Target Portal Group") -+ parser.add_option("--listnps", action="callback", callback=lio_target_list_nps, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="List LIO-Target Portal Group Network Portals") -+ parser.add_option("--listtargetnames", action="callback", callback=lio_target_list_targetnames, nargs=0, -+ help="List iSCSI Target Names") -+ parser.add_option("--listtpgattr", action="callback", callback=lio_target_list_tpg_attr, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="List LIO-Target Portal Group attributes") -+ parser.add_option("--listtpgparam", action="callback", callback=lio_target_list_tpg_param, nargs=2, -+ type="string", dest="TARGET_IQN TPGT", help="List LIO-Target Portal Group RFC-3720 parameters") -+ parser.add_option("--setchapauth", action="callback", callback=lio_target_set_chap_auth, nargs=5, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN USER PASS", help="Set CHAP authentication information for iSCSI Initiator Node ACL"); -+ parser.add_option("--setchapmutualauth", action="callback", callback=lio_target_set_chap_mutual_auth, nargs=5, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN USER_IN PASS_IN", help="Set CHAP mutual authentication information for iSCSI Initiator Node ACL"); -+ parser.add_option("--setchapdiscenforce", action="callback", callback=lio_target_set_enforce_discovery_auth, nargs=1, -+ type="string", dest="Enforce=1, NoEnforcement=0", help="Set CHAP authentication enforcement for iSCSI Discovery Sessions"); -+ parser.add_option("--setchapdiscauth", action="callback", callback=lio_target_set_chap_discovery_auth, nargs=2, -+ type="string", dest="USER PASS", help="Set CHAP authentication information for iSCSI Discovery Authentication") -+ parser.add_option("--setchapdiscmutualauth", action="callback", callback=lio_target_set_chap_mutual_discovery_auth, nargs=2, -+ type="string", dest="USER PASS", help="Set CHAP mutual authentication information for iSCSI Discovery Authentication") -+ parser.add_option("--setnodeattr", action="callback", callback=lio_target_set_node_attr, nargs=5, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN ", help="Set iSCSI Initiator ACL Attribute") -+ parser.add_option("--setnodetcq", action="callback", callback=lio_target_set_node_tcq, nargs=4, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN DEPTH", help="Set iSCSI Initiator ACL TCQ Depth for LIO-Target Portal Group") -+ parser.add_option("--settpgattr", action="callback", callback=lio_target_set_tpg_attr, nargs=4, -+ type="string", dest="TARGET_IQN TPGT ", help="Set LIO-Target Port Group Attribute") -+ parser.add_option("--settpgparam", action="callback", callback=lio_target_set_tpg_param, nargs=4, -+ type="string", dest="TARGET_IQN TPGT ", help="Set LIO-Target Port Group RFC-3720 parameter") -+ parser.add_option("--settgptgp","--setaluatpg", action="callback", callback=lio_target_alua_set_tgptgp, nargs=4, -+ type="string", dest="TARGET_IQN TPGT LUN TG_PT_GP_NAME", help="Set ALUA Target Port Group for LIO-Target Port/LUN") -+ parser.add_option("--settgptoff","--setaluaoff", action="callback", callback=lio_target_alua_set_tgpt_offline, nargs=3, -+ type="string", dest="TARGET_IQN TPGT LUN", help="Set ALUA Target Port Secondary State OFFLINE") -+ parser.add_option("--showchapauth", action="callback", callback=lio_target_show_chap_auth, nargs=3, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN", help="Show CHAP authentication information for iSCSI Initiator Node ACL"); -+ parser.add_option("--showchapdiscauth", action="callback", callback=lio_target_show_chap_discovery_auth, nargs=0, -+ help="Show CHAP authentication information for iSCSI Discovery portal"); -+ parser.add_option("--shownodetcq", action="callback", callback=lio_target_show_node_tcq, nargs=3, -+ type="string", dest="TARGET_IQN TPGT INITIATOR_IQN", help="Show iSCSI Initiator ACL TCQ Depth for LIO-Target Portal Group") -+ parser.add_option("--showtgptgp", action="callback", callback=lio_target_alua_show_tgptgp, nargs=3, -+ type="string", dest="TARGET_IQN TPGT LUN", help="Show ALUA Target Port Group for LIO-Target Port/LUN") -+ parser.add_option("--unload", action="callback", callback=lio_target_unload, nargs=0, -+ help="Unload LIO-Target") -+ parser.add_option("--version", action="callback", callback=lio_target_version, nargs=0, -+ help="Display LIO-Target version information") -+ -+ (options, args) = parser.parse_args() -+ if len(sys.argv) == 1: -+ parser.print_help() -+ sys.exit(0) -+ elif not re.search('--', sys.argv[1]): -+ lio_err("Unknown CLI option: " + sys.argv[1]) -+ -+if __name__ == "__main__": -+ main() -diff --git a/targetcli/tcm_dump.py b/targetcli/tcm_dump.py -new file mode 100644 -index 0000000..bf80632 ---- /dev/null -+++ b/targetcli/tcm_dump.py -@@ -0,0 +1,366 @@ -+import os, sys, shutil -+import subprocess as sub -+from subprocess import Popen, PIPE -+import string -+import re -+import datetime, time -+from optparse import OptionParser -+ -+import tcm_node -+import tcm_pscsi -+import tcm_iblock -+import tcm_ramdisk -+import tcm_fileio -+ -+import lio_dump -+import tcm_fabric -+ -+tcm_root = "/sys/kernel/config/target/core" -+ -+def tcm_dump_hba_devices(): -+ pass -+ -+def tcm_dump_configfs(option, opt_str, value, parser): -+ -+ if not os.path.isdir(tcm_root): -+ print "Unable to access tcm_root: " + tcm_root -+ sys.exit(1) -+ -+ print "modprobe target_core_mod" -+ -+ # Loop through ALUA Logical Unit Groups -+ # Note that the 'default_lu_gp' is automatically created when -+ # target_core_mod is loaded. -+ print "#### ALUA Logical Unit Groups" -+ for lu_gp in os.listdir(tcm_root + "/alua/lu_gps"): -+ if lu_gp == "default_lu_gp": -+ continue -+ -+ print "mkdir -p " + tcm_root + "/alua/lu_gps/" + lu_gp -+ lu_gp_id_file = tcm_root + "/alua/lu_gps/" + lu_gp + "/lu_gp_id" -+ p = os.open(lu_gp_id_file, 0) -+ value = os.read(p, 8) -+ os.close(p) -+ if not value: -+ continue -+ print "echo " + value.rstrip() + " > " + lu_gp_id_file -+ -+ # Loop through HBA list -+ for f in os.listdir(tcm_root): -+ if f == "alua": -+ continue; -+ -+# print "mkdir -p " + tcm_root + "/" + f -+ -+ dev_root = tcm_root + "/" + f + "/" -+ for g in os.listdir(dev_root): -+ if g == "hba_info" or g == "hba_mode": -+ continue; -+ -+ # Dump device aka storage object -+ print "#### Parameters for TCM subsystem plugin storage object reference" -+ -+ # Generate subsystem dependent configfs ops for association to -+ # an target_core_mod storage object. -+ result = re.search('pscsi_', f) -+ if result: -+ dev = dev_root + g -+ params = tcm_pscsi.pscsi_get_params(dev) -+ if not params: -+ continue -+ print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ result = re.search('iblock_', f) -+ if result: -+ dev = dev_root + g -+ params = tcm_iblock.iblock_get_params(dev) -+ if not params: -+ continue -+ print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ result = re.search('rd_dr_', f) -+ if result: -+ dev = dev_root + g -+ params = tcm_ramdisk.rd_get_params(dev) -+ if not params: -+ continue -+ print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ result = re.search('rd_mcp_', f) -+ if result: -+ dev = dev_root + g -+ params = tcm_ramdisk.rd_get_params(dev) -+ if not params: -+ continue -+ print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ result = re.search('fileio_', f) -+ if result: -+ dev = dev_root + g -+ params = tcm_fileio.fd_get_params(dev) -+ if not params: -+ continue -+ print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ -+ # Dump T10 VP Unit Serial for all non Target_Core_Mod/pSCSI objects -+ result = re.search('pscsi_', f) -+ if not result: -+ unit_serial_file = dev_root + g + "/wwn/vpd_unit_serial" -+ p = os.open(unit_serial_file, 0) -+ value = os.read(p, 512) -+ off = value.index('Number: ') -+ off += 8 # Skip over "Number: " -+ unit_serial = value[off:] -+ # Note that this will handle read, parse and set any PR APTPL metadata -+ print "tcm_node --setunitserialwithmd " + f + "/" + g + " " + unit_serial.rstrip() -+ os.close(p) -+ -+ # Dump device object alias -+ alias_file = dev_root + g + "/alias" -+ p = open(alias_file, 'r') -+ value = p.read(512) -+ value = value.rstrip() -+ p.close() -+ if value: -+ print "echo -n \"" + value + "\" > " + dev_root + g + "/alias" -+ -+ # Dump ALUA Logical Unit Group -+ lu_gp_file = dev_root + g + "/alua_lu_gp" -+ p = os.open(lu_gp_file, 0) -+ value = os.read(p, 512) -+ os.close(p) -+ if value: -+ lu_gp_tmp = value.split('\n') -+ lu_gp_out = lu_gp_tmp[0] -+ off = lu_gp_out.index('Alias: ') -+ off += 7 # Skip over "Alias: " -+ lu_gp_name = lu_gp_out[off:] -+ # Only need to dump if storage object is NOT part of -+ # the 'default_lu_gp' -+ if not re.search(lu_gp_name, 'default_lu_gp'): -+ print "echo " + lu_gp_name + " > " + lu_gp_file -+ -+ # Loop through ALUA Target Port Groups -+ if os.path.isdir(dev_root + g + "/alua/") == True: -+ print "#### ALUA Target Port Groups" -+ for tg_pt_gp in os.listdir(dev_root + g + "/alua/"): -+ tg_pt_gp_id_file = dev_root + g + "/alua/" + tg_pt_gp + "/tg_pt_gp_id" -+ p = os.open(tg_pt_gp_id_file, 0) -+ value = os.read(p, 8) -+ os.close(p) -+ if not value: -+ continue -+ print "tcm_node --addaluatpgwithmd " + f + "/" + g + " " + tg_pt_gp + " " + value.rstrip() -+ # Dump the ALUA types -+ tg_pt_gp_type_file = dev_root + g + "/alua/" + tg_pt_gp + "/alua_access_type" -+ p = os.open(tg_pt_gp_type_file, 0) -+ value = os.read(p, 32) -+ os.close(p) -+ if value: -+ value = value.rstrip() -+ alua_type = 0 -+ -+ if re.search('Implict and Explict', value): -+ alua_type = 3 -+ elif re.search('Explict', value): -+ alua_type = 2 -+ elif re.search('Implict', value): -+ alua_type = 1 -+ -+ print "echo " + str(alua_type) + " > " + tg_pt_gp_type_file -+ -+ # Dump the preferred bit -+ tg_pt_gp_pref_file = dev_root + g + "/alua/" + tg_pt_gp + "/preferred" -+ p = os.open(tg_pt_gp_pref_file, 0) -+ value = os.read(p, 8) -+ os.close(p) -+ if value: -+ print "echo " + value.rstrip() + " > " + tg_pt_gp_pref_file -+ # Dump the Active/NonOptimized Delay -+ tg_pt_gp_nonop_delay_file = dev_root + g + "/alua/" + tg_pt_gp + "/nonop_delay_msecs" -+ p = os.open(tg_pt_gp_nonop_delay_file, 0) -+ value = os.read(p, 8) -+ os.close(p) -+ if value: -+ print "echo " + value.rstrip() + " > " + tg_pt_gp_nonop_delay_file -+ # Dump the Transition Delay -+ tg_pt_gp_trans_delay_file = dev_root + g + "/alua/" + tg_pt_gp + "/trans_delay_msecs" -+ p = os.open(tg_pt_gp_trans_delay_file, 0) -+ value = os.read(p, 8) -+ os.close(p) -+ if value: -+ print "echo " + value.rstrip() + " > " + tg_pt_gp_trans_delay_file -+ -+ # Dump device attributes -+ print "#### Attributes for " + dev_root + g -+ dev_attrib_root = dev_root + g + "/attrib/" -+ for h in os.listdir(dev_attrib_root): -+ # The hw_* prefixed attributes are RO -+ if h == "hw_queue_depth": -+ continue -+ if h == "hw_max_sectors": -+ continue -+ if h == "hw_block_size": -+ continue -+ # Do not change block-size for target_core_mod/pSCSI -+ if h == "block_size": -+ result = re.search('pscsi_', f) -+ if result: -+ continue -+ -+ attrib_file = dev_attrib_root + h -+ p = os.open(attrib_file, 0) -+ value = os.read(p, 8) -+ print "echo " + value.rstrip() + " > " + attrib_file -+ os.close(p) -+ -+ # Dump snapshot attributes -+ snap_attrib_root = dev_root + g + "/snap/" -+ if (os.path.isdir(snap_attrib_root) == False): -+ continue -+ -+ snap_enabled = 0 -+ enabled_attr_file = snap_attrib_root + "enabled" -+ p = open(enabled_attr_file, 'rU') -+ if not p: -+ continue -+ value = p.read() -+ enabled = value.rstrip() -+ p.close() -+ if enabled != "1": -+ continue -+ -+ snap_enabled = 1 -+ print "#### Snapshot Attributes for " + dev_root + g -+ for s in os.listdir(snap_attrib_root): -+ if s == "pid": -+ continue -+ if s == "usage": -+ continue -+ if s == "enabled": -+ continue -+ -+ attrib_file = snap_attrib_root + s -+ p = open(attrib_file, 'rU') -+ value = p.read() -+ p.close() -+ attr_val = value.rstrip() -+ print "echo " + attr_val + " > " + attrib_file -+ -+ if snap_enabled == 1: -+ print "tcm_node --lvsnapstart " + f + "/" + g -+ -+def tcm_backup_to_file(option, opt_str, value, parser): -+ datetime = str(value) -+ -+ if not os.path.isdir(tcm_root): -+ print "Unable to access tcm_root: " + tcm_root -+ sys.exit(1) -+ -+ backup_dir = "/etc/target/backup" -+ if not os.path.isdir(backup_dir): -+ op = "mkdir " + backup_dir -+ ret = os.system(op) -+ if ret: -+ print "Unable to open backup_dir" -+ sys.exit(1) -+ -+ op = "tcm_dump --stdout" -+ p = sub.Popen(op, shell=True, stdout=sub.PIPE).stdout -+ if not p: -+ print "Unable to dump Target_Core_Mod/ConfigFS running state" -+ sys.exit(0) -+ -+ print "Making backup of Target_Core_Mod/ConfigFS with timestamp: " + datetime -+ backup_file = backup_dir + "/tcm_backup-" + datetime + ".sh" -+ if os.path.isfile(backup_file): -+ print "Target_Core_Mod backup_file: " + backup_file + "already exists, exiting" -+ p.close() -+ sys.exit(1) -+ -+ back = open(backup_file, 'w') -+ -+ line = p.readline() -+ while line: -+ print >>back, line.rstrip() -+ line = p.readline() -+ -+ p.close() -+ back.close() -+ return backup_file -+ -+def tcm_full_backup(option, opt_str, value, parser): -+ overwrite = str(value) -+ -+ now = datetime.datetime.now() -+ tmp = str(now) -+ tmp2 = tmp.split(' ') -+ timestamp = tmp2[0] + "_" + tmp2[1] -+ -+ tcm_file = "/etc/target/tcm_start.sh" -+ lio_file = "/etc/target/lio_start.sh" -+ lio_active = 0 -+ -+ ret = tcm_fabric.fabric_backup_to_file_all(timestamp) -+ if ret: -+ print "Unable to backup tcm_fabric.modules" -+ -+ if os.path.isdir("/sys/kernel/config/target/iscsi"): -+ lio_file_new = lio_dump.lio_backup_to_file(None, None, timestamp, None) -+ if not lio_file_new: -+ sys.exit(1) -+ lio_active = 1 -+ print "Generated LIO-Target config: " + lio_file_new -+ -+ -+ tcm_file_new = tcm_backup_to_file(None, None, timestamp, None) -+ if not tcm_file_new: -+ sys.exit(1) -+ -+ print "Generated Target_Core_Mod config: " + tcm_file_new -+ -+ if overwrite != "1": -+ print "Not updating default config" -+ return -+ -+ if lio_active: -+ ret = shutil.copyfile(lio_file_new, lio_file) -+ if ret: -+ print "Unable to copy " + lio_file_new -+ sys.exit(1) -+ print "Successfully updated default config " + lio_file -+ -+ ret = shutil.copyfile(tcm_file_new, tcm_file) -+ if ret: -+ print "Unable to copy " + tcm_file_new -+ sys.exit(1) -+ -+ print "Successfully updated default config " + tcm_file -+ -+def tcm_overwrite_default(option, opt_str, value, parser): -+ -+ input = raw_input("Are you sure you want to overwrite the default configuration? Type 'yes': ") -+ if input != "yes": -+ sys.exit(0) -+ -+ val = "1" -+ tcm_full_backup(None, None, val, None) -+ -+def main(): -+ -+ parser = OptionParser() -+ parser.add_option("--b","--backup", action="callback", callback=tcm_full_backup, nargs=1, -+ type="string", dest="OVERWRITE", help="Do backup of TCM and storage fabric modules, and optionally overwrite default config data") -+ parser.add_option("--o","--overwrite", action="callback", callback=tcm_overwrite_default, nargs=0, -+ help="Overwrite default config data of TCM and storage fabric modules") -+ parser.add_option("--s","--stdout", action="callback", callback=tcm_dump_configfs, nargs=0, -+ help="Dump running Target_Core_Mod/ConfigFS syntax to STDOUT") -+ parser.add_option("--t", "--tofile", action="callback", callback=tcm_backup_to_file, nargs=1, -+ type="string", dest="DATE_TIME", help="Backup running Target_Core_Mod/ConfigFS syntax to /etc/target/backup/tcm_backup-.sh") -+ -+ (options, args) = parser.parse_args() -+ if len(sys.argv) == 1: -+ parser.print_help() -+ sys.exit(0) -+ elif not re.search('--', sys.argv[1]): -+ print "Unknown CLI option: " + sys.argv[1] -+ sys.exit(1) -+ -+if __name__ == "__main__": -+ main() -diff --git a/targetcli/tcm_fabric.py b/targetcli/tcm_fabric.py -new file mode 100644 -index 0000000..8a843d4 ---- /dev/null -+++ b/targetcli/tcm_fabric.py -@@ -0,0 +1,532 @@ -+import os, sys, shutil -+import subprocess as sub -+import string -+import re -+import datetime, time -+import optparse -+ -+target_root = "/sys/kernel/config/target/" -+spec_root = "/var/target/fabric/" -+ -+def fabric_configfs_dump(fabric_name, fabric_root, module_name): -+ -+ if not os.path.isdir(fabric_root): -+ print "Unable to access fabric_root: " + fabric_root -+ sys.exit(1) -+ -+ iqn_root = os.listdir(fabric_root) -+ -+ # This will load up the fabric module -+ print "modprobe " + module_name -+ print "mkdir " + fabric_root -+ -+# print "#### " + fabric_name + " Discovery authentication information" -+ auth_dir = fabric_root + "/discovery_auth" -+ if os.path.isdir(auth_dir) == True: -+ for auth in os.listdir(auth_dir): -+ if auth == "authenticate_target": -+ continue -+ -+ auth_file = auth_dir + "/" + auth -+ p = os.open(auth_file, 0) -+ value = os.read(p, 256) -+ ret = value.isspace() -+ if ret: -+ os.close(p) -+ continue -+ print "echo -n " + value.rstrip() + " > " + auth_file -+ os.close(p) -+ -+ iqn_root = os.listdir(fabric_root) -+ -+ # Loop through LIO-Target IQN list -+ for iqn in iqn_root: -+ if not os.path.isdir(fabric_root + "/" + iqn): -+ continue -+ if iqn == "lio_version": -+ continue -+ if iqn == "discovery_auth": -+ continue -+ -+ # Loop through LIO-Target IQN+TPGT list -+ tpg_root = os.listdir(fabric_root + "/" + iqn); -+ for tpgt_tmp in tpg_root: -+ if tpgt_tmp == "fabric_statistics": -+ continue -+ -+ tpgt_tmp2 = tpgt_tmp.split('_') -+ tpgt = tpgt_tmp2[1] -+ -+# print "#### Network portals for iSCSI Target Portal Group" -+# np_root = os.listdir(fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/np") -+# for np in np_root: -+# print "mkdir -p " + fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/np/" + np -+ -+ -+ # Dump Nexus attribute (when available) -+ nexus_file = fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/nexus" -+ if os.path.isfile(nexus_file): -+ print "mkdir -p " + fabric_root + "/" + iqn + "/tpgt_" + tpgt -+ p = os.open(nexus_file, 0) -+ value = os.read(p, 256) -+ print "echo " + value.rstrip() + " > " + nexus_file -+ os.close(p) -+ -+ print "#### " + fabric_name + " Target Ports" -+ lun_root = os.listdir(fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/lun") -+ for lun_tmp in lun_root: -+ lun_tmp2 = lun_tmp.split('_') -+ lun = lun_tmp2[1] -+ -+ lun_dir = fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun -+ print "mkdir -p " + lun_dir -+ -+ port_root = os.listdir(lun_dir) -+ for port in port_root: -+ if port == "alua_tg_pt_gp": -+ continue -+ if port == "alua_tg_pt_offline": -+ continue -+ if port == "alua_tg_pt_status": -+ continue -+ if port == "alua_tg_pt_write_md": -+ continue -+ -+ if not os.path.islink(lun_dir + "/" + port): -+ continue -+ -+ port_link = fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/lun/lun_" + lun + "/" + port -+ sourcelink = os.readlink(port_link) -+ sourcelink2 = os.path.join(os.path.dirname(port_link), sourcelink) -+ print "ln -s " + sourcelink2 + " " + port_link -+ -+ # Dump ALUA Target Port Group -+ tg_pt_gp_file = lun_dir + "/alua_tg_pt_gp" -+ p = os.open(tg_pt_gp_file, 0) -+ try: -+ value = os.read(p, 512) -+ except: -+ os.close(p) -+ continue -+ os.close(p) -+ if value: -+ tg_pt_gp_tmp = value.split('\n') -+ tg_pt_gp_out = tg_pt_gp_tmp[0] -+ off = tg_pt_gp_out.index('Alias: ') -+ off += 7 # Skip over "Alias: " -+ tg_pt_gp_name = tg_pt_gp_out[off:] -+ # Only need to dump if LIO-Target Port is NOT partof -+ # the 'default_tg_pt_gp' -+ if not re.search(tg_pt_gp_name, 'default_tg_pt_gp'): -+ print "#### ALUA Target Port Group" -+ print "echo " + tg_pt_gp_name + " > " + tg_pt_gp_file -+ -+#FIXME: --aluasecmd support -+# print "lio_node --aluasecmd " + iqn + " " + tpgt + " " + lun -+ -+ # Dump values of iscsi/iqn/tpgt/attrib/ -+ print "#### Attributes for " + fabric_name + " Target Portal Group" -+ attrib_dir = fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/attrib/" -+ attrib_root = os.listdir(attrib_dir) -+ for attrib in attrib_root: -+ attrib_file = attrib_dir + attrib -+ p = os.open(attrib_file, 0) -+ value = os.read(p, 16) -+ print "echo " + value.rstrip() + " > " + attrib_file -+ os.close(p) -+ -+ # Dump values for iscsi/iqn/tpgt/param -+ print "#### Parameters for " + fabric_name + " Target Portal Group" -+ param_dir = fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/param/" -+ param_root = os.listdir(param_dir) -+ for param in param_root: -+ param_file = param_dir + param -+ p = os.open(param_file, 0) -+ value = os.read(p, 256) -+ print "echo \"" + value.rstrip() + "\" > " + param_file -+ os.close(p) -+ -+ if os.path.isfile(nexus_file): -+ continue -+ -+ # Dump fabric Initiator Node ACLs from fabric_root/$WWN/tpgt_$TPGT/acls/ -+ print "#### " + fabric_name + " Initiator ACLs for " + fabric_name + " Target Portal Group" -+ nacl_dir = fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/acls/" -+ nacl_root = os.listdir(nacl_dir) -+ for nacl in nacl_root: -+ print "mkdir -p " + nacl_dir + nacl -+ -+ # Dump fabric Initiator ACL authentication info from fabric_root/$WWN/tpgt_$TPGT/acls//$INITIATOR/auth -+ print "#### " + fabric_name + " Initiator ACL authentication information" -+ auth_dir = nacl_dir + nacl + "/auth" -+ for auth in os.listdir(auth_dir): -+ if auth == "authenticate_target": -+ continue -+ auth_file = auth_dir + "/" + auth -+ p = os.open(auth_file, 0) -+ value = os.read(p, 256) -+ ret = value.isspace() -+ if ret: -+ os.close(p) -+ continue -+ print "echo -n " + value.rstrip() + " > " + auth_file -+ os.close(p) -+ -+ # Dump fabric Initiator ACL TPG attributes from fabric_root/$WWN/tpgt_$TPGT/acls/$INITIATOR/attrib -+ print "#### " + fabric_name + " Initiator ACL TPG attributes" -+ nacl_attrib_dir = nacl_dir + nacl + "/attrib" -+ for nacl_attrib in os.listdir(nacl_attrib_dir): -+ nacl_attrib_file = nacl_attrib_dir + "/" + nacl_attrib -+ p = os.open(nacl_attrib_file, 0) -+ value = os.read(p, 8) -+ print "echo " + value.rstrip() + " > " + nacl_attrib_file -+ os.close(p) -+ -+ # Dump fabric Initiator LUN ACLs from fabric_root/$WWN/tpgt_$TPGT//acls/$INITIATOR/lun -+ print "#### " + fabric_name + " Initiator LUN ACLs for iSCSI Target Portal Group" -+ lun_acl_dir = nacl_dir + nacl -+ for lun_acl in os.listdir(lun_acl_dir): -+ ret = re.search('lun_', lun_acl) -+ if not ret: -+ continue -+ lun_link_dir = nacl_dir + nacl + "/" + lun_acl -+ print "mkdir -p " + lun_link_dir -+ -+ for lun_acl_link in os.listdir(lun_link_dir): -+ if lun_acl_link == "write_protect": -+ p = os.open(lun_link_dir + "/write_protect", 0) -+ value = os.read(p, 4) -+ print "echo " + value.rstrip() + " > " + lun_link_dir + "/write_protect" -+ os.close(p) -+ continue -+ -+ if not os.path.islink(lun_link_dir + "/" + lun_acl_link): -+ continue -+ -+ sourcelink = os.readlink(lun_link_dir + "/" + lun_acl_link) -+ sourcelink2 = os.path.join(os.path.dirname(lun_link_dir + "/" + lun_acl_link), sourcelink) -+ print "ln -s " + sourcelink2 + " " + lun_link_dir + "/" + lun_acl_link -+ -+ # Dump value of fabric_root/$WWN/tpgt_$TPGT//enable -+ print "#### Trigger to enable " + fabric_name + " Target Portal Group" -+ enable_file = fabric_root + "/" + iqn + "/tpgt_" + tpgt + "/enable" -+ if os.path.isfile(enable_file): -+ p = os.open(enable_file, 0) -+ value = os.read(p, 1) -+ print "echo " + value.rstrip() + " > " + enable_file -+ os.close(p) -+ -+ -+ return -+ -+def fabric_configfs_dump_all(): -+ -+ for fabric_name in os.listdir(target_root): -+ if fabric_name == "version": -+ continue -+ if fabric_name == "core": -+ continue -+ # FIXME: currently using lio_dump --stdout -+ if fabric_name == "iscsi": -+ continue -+ -+ fabric_root = target_root + fabric_name -+# print "Using fabric_configfs_dump_all: " + fabric_name + ", " + fabric_root -+ module_name = fabric_get_module_name(fabric_name) -+# print "module_name: "+ module_name -+ -+ fabric_configfs_dump(fabric_name, fabric_root, module_name); -+ -+ return -+ -+def fabric_backup_to_file(date_time, fabric_name, fabric_root, module_name): -+ now = date_time -+ -+ if not os.path.isdir(fabric_root): -+ print "Unable to access fabric_root: " + fabric_root -+ sys.exit(1) -+ -+ current_dir = "/etc/target" -+ backup_dir = "/etc/target/backup" -+ if not os.path.isdir(backup_dir): -+ op = "mkdir " + backup_dir -+ ret = os.system(op) -+ if ret: -+ print "Unable to open backup_dir" -+ sys.exit(1) -+ -+ op = "tcm_fabric --stdout --fabric-name=" + fabric_name + " --fabric-root=" + fabric_root + " --module-name=" + module_name -+# print "Using op: " + op -+ p = sub.Popen(op, shell=True, stdout=sub.PIPE).stdout -+ if not p: -+ print "Unable to dump " + fabric_name + "/ConfigFS running state" -+ sys.exit(1) -+ -+ orig_file = current_dir + "/" + fabric_name + "_start.sh" -+ -+ print "Making backup of " + fabric_name + "/ConfigFS with timestamp: " + now -+ backup_file = backup_dir + "/" + fabric_name + "_backup-" + now + ".sh" -+ if os.path.isfile(backup_file): -+ print "" + fabric_name + " backup_file: " + backup_file + "already exists, exiting" -+ p.close() -+ sys.exit(1) -+ -+ back = open(backup_file, 'w') -+ -+ line = p.readline() -+ while line: -+ print >>back, line.rstrip() -+ line = p.readline() -+ -+ p.close() -+ back.close() -+ -+ ret = shutil.copyfile(backup_file, orig_file) -+ if ret: -+ print "Unable to copy " + back_file -+ sys.exit(1) -+ -+ print "Successfully updated default config " + orig_file -+ -+ return backup_file -+ -+def fabric_backup_to_file_all(date_time): -+ -+ if not os.path.isdir(target_root): -+ print "Unable to open target_root: " + target_root -+ sys.exit(1) -+ -+ for fabric_name in os.listdir(target_root): -+ if fabric_name == "version": -+ continue -+ if fabric_name == "core": -+ continue -+ # FIXME: currently using lio_dump -+ if fabric_name == "iscsi": -+ continue -+ -+ fabric_root = target_root + fabric_name -+# print "Using fabric_backup_to_file: " + date_time + ", " + fabric_name + ", " + fabric_root -+ module_name = fabric_get_module_name(fabric_name) -+# print "Using module_name: "+ module_name -+ -+ fabric_backup_to_file(date_time, fabric_name, fabric_root, module_name) -+ -+ -+ return -+ -+def fabric_unload(fabric_name, fabric_root, module_name): -+ -+ if not os.path.isdir(fabric_root): -+ print "Unable to access fabric_root: " + fabric_root -+ sys.exit(1) -+ -+ wwn_root = os.listdir(fabric_root) -+ for wwn in wwn_root: -+ if not os.path.isdir(fabric_root + "/" + wwn): -+ continue -+ if wwn == "discovery_auth": -+ continue -+ -+ tpg_root = fabric_root + "/" + wwn -+ for tpgt_tmp in os.listdir(tpg_root): -+ if tpgt_tmp == "fabric_statistics": -+ continue -+ -+ tpgt_tmp2 = tpgt_tmp.split('_') -+ tpgt = tpgt_tmp2[1] -+ -+ if os.path.isfile(fabric_root + "/" + wwn + "/tpgt_" + tpgt + "/enable"): -+ disable_op = "echo 0 > " + fabric_root + "/" + wwn + "/tpgt_" + tpgt + "/enable" -+ ret = os.system(disable_op) -+ if ret: -+ print "Unable to disable TPG: " + wwn + " TPGT: " + tpgt -+ -+ nacl_root = fabric_root + "/" + wwn + "/tpgt_" + tpgt + "/acls" -+ for nacl in os.listdir(nacl_root): -+ lun_acl_root = nacl_root + "/" + nacl + "/" -+ for lun_acl in os.listdir(lun_acl_root): -+ ret = re.search('lun_', lun_acl) -+ if not ret: -+ continue -+ mapped_lun = lun_acl[4:] -+ -+ lun_link_dir = lun_acl_root + "/" + lun_acl + "/" -+ for lun_acl_link in os.listdir(lun_link_dir): -+ if lun_acl_link == "write_protect": -+ continue -+ -+ if os.path.islink(lun_link_dir + "/" + lun_acl_link): -+ unlink_op = "unlink " + lun_link_dir + "/" + lun_acl_link -+ ret = os.system(unlink_op) -+ if ret: -+ print "Unable to unlink MappedLUN: " + lun_link_dir + "/" + lun_acl_link -+ -+ dellunacl_op = "rmdir " + lun_link_dir -+ ret = os.system(dellunacl_op) -+ if ret: -+ print "Unable to rmdir fabric mapped_lun" -+ -+ delnodeacl_op = "rmdir " + nacl_root + "/" + nacl + "/" -+ ret = os.system(delnodeacl_op) -+ if ret: -+ print "Unable to remove NodeACL: " + nacl_root + "/" + nacl + "/" -+ -+ lun_root = fabric_root + "/" + wwn + "/tpgt_" + tpgt + "/lun" -+ for lun_tmp in os.listdir(lun_root): -+ lun_tmp2 = lun_tmp.split('_') -+ lun = lun_tmp2[1] -+ -+ lun_dir = lun_root + "/lun_" + lun -+ for port in os.listdir(lun_dir): -+ if not os.path.islink(lun_dir + "/" + port): -+ continue -+ -+ unlink_op = "unlink " + lun_dir + "/" + port -+ ret = os.system(unlink_op) -+ if ret: -+ print "Unable to unlink fabric port/lun" -+ -+ rmdir_op= "rmdir " + lun_dir -+ ret = os.system(rmdir_op); -+ if ret: -+ print "Unable to rmdir fabric port/lun: " + lun_dir -+ -+ -+ rmdir_op = "rmdir " + fabric_root + "/" + wwn + "/tpgt_" + tpgt + "/" -+ ret = os.system(rmdir_op) -+ if ret: -+ print "Unable to rmdir fabric tpg: " + fabric_root + "/" + wwn + "/tpgt_" + tpgt + "/" -+ -+ rmdir_op = "rmdir " + fabric_root + "/" + wwn + "/" -+ ret = os.system(rmdir_op) -+ if ret: -+ print "Unable to rmdir fabric wwn: " + fabric_root + "/" + wwn + "/" -+ -+ -+ -+ rmdir_op = "rmdir " + fabric_root -+ ret = os.system(rmdir_op) -+ if ret: -+ print "Unable to release fabric_root: " + fabric_root -+ -+ rmmod_op = "rmmod " + module_name -+ ret = os.system(rmmod_op) -+ if ret: -+ print "Unable to unload " + module_name -+ -+ print "Successfully released fabric: " + fabric_root -+ return -+ -+def fabric_get_module_name(fabric_name): -+ kernel_module = "" -+ -+ for specs in os.listdir(spec_root): -+ if specs == "README": -+ continue -+# print "specs: " + specs + ", fabric_name: " + fabric_name -+ -+ if not re.search(fabric_name + ".spec", specs) and not re.search("tcm_" + fabric_name + ".spec", specs) and not re.search(fabric_name, specs): -+ continue -+ -+ op = "cat " + spec_root + specs -+ p = sub.Popen(op, shell=True, stdout=sub.PIPE).stdout -+ if not p: -+ print "Unable to dump " + fabric_name + "/ConfigFS running state" -+ sys.exit(1) -+ -+ line = p.readline() -+ while line: -+ tmp = line.rstrip() -+ # Check for 'kernel_module' line in $FABRIC.spec -+ if re.search('kernel_module', tmp): -+ tmp_list = tmp.split('= ') -+ p.close() -+ return tmp_list[1] -+ -+ line = p.readline() -+ -+ p.close() -+ -+ return kernel_module -+ -+def fabric_unloadall(): -+ -+ module_name = "" -+ -+ for fabric_name in os.listdir(target_root): -+ if fabric_name == "version": -+ continue -+ if fabric_name == "core": -+ continue -+ # FIXME: currently using lio_node --unload -+ if fabric_name == "iscsi": -+ continue -+ -+ fabric_root = target_root + fabric_name -+ module_name = fabric_get_module_name(fabric_name) -+# print "fabric_get_module_name() using: " + module_name -+ -+ if module_name == "": -+ continue -+ -+ fabric_unload(fabric_name, fabric_root, module_name) -+ -+ -+def do_work(stdout_enable, stdout_enable_all, date_time, unload, unloadall, fabric_name, fabric_root, module_name): -+ -+ if not stdout_enable == "None": -+ fabric_configfs_dump(fabric_name, fabric_root, module_name) -+ elif not stdout_enable_all == "None": -+ fabric_configfs_dump_all() -+ elif not date_time == "None": -+ fabric_backup_to_file(date_time, fabric_name, fabric_root, module_name) -+ elif not unload == "None": -+ fabric_unload(fabric_name, fabric_root, module_name) -+ elif not unloadall == "None": -+ fabric_unloadall() -+ -+ return 0 -+ -+def main(): -+ -+ parser_fabric = optparse.OptionParser() -+ parser_fabric.add_option("--s","--stdout", dest='stdout_enable', action='store', nargs=0, -+ help="Dump running Fabric/ConfigFS syntax to STDOUT", type='string') -+ parser_fabric.add_option("--z","--stdoutall", dest='stdout_enable_all', action='store', nargs=0, -+ help="Dump all running Fabric/ConfigFS syntax to STDOUT", type='string') -+ parser_fabric.add_option("--t", "--tofile", dest="date_time", action='store', nargs=1, -+ help="Backup running Fabric/ConfigFS syntax to /etc/target/backup/fabricname_backup-.sh", -+ type='string') -+ parser_fabric.add_option("--u", "--unload", dest="unload", action='store', nargs=0, -+ help="Unload running Fabric/ConfigFS", type='string') -+ parser_fabric.add_option("--a", "--unloadall", dest="unloadall", action='store', nargs=0, -+ help="Unload all running Fabric/ConfigFS", type='string') -+ parser_fabric.add_option("--f", "--fabric-name", dest='fabric_name', action='store', nargs=1, -+ help="Target fabric name", type='string') -+ parser_fabric.add_option("--r", "--fabric-root", dest='fabric_root', action='store', nargs=1, -+ help="Target fabric configfs root", type='string') -+ parser_fabric.add_option("--m", "--module-name", dest='module_name', action='store', nargs=1, -+ help="Target fabric module name ", type='string') -+ -+ (opts_fabric, args_fabric) = parser_fabric.parse_args() -+ -+ mandatories = ['fabric_name', 'fabric_root', 'module_name'] -+ for m in mandatories: -+ if not opts_fabric.__dict__[m]: -+ unloadall = str(opts_fabric.__dict__['unloadall']) -+ stdout_enable = str(opts_fabric.__dict__['stdout_enable']) -+ stdout_enable_all = str(opts_fabric.__dict__['stdout_enable_all']) -+ date_time = str(opts_fabric.__dict__['date_time']) -+ if unloadall == "None" and stdout_enable == "None" and stdout_enable_all == "None" and date_time == "None": -+ print "mandatory option is missing\n" -+ parser_fabric.print_help() -+ exit(-1) -+ -+ do_work(str(opts_fabric.stdout_enable), str(opts_fabric.stdout_enable_all), -+ str(opts_fabric.date_time), str(opts_fabric.unload), str(opts_fabric.unloadall), -+ str(opts_fabric.fabric_name), str(opts_fabric.fabric_root), -+ str(opts_fabric.module_name)) -+ -+if __name__ == "__main__": -+ main() -diff --git a/targetcli/tcm_fileio.py b/targetcli/tcm_fileio.py -new file mode 100644 -index 0000000..839d91a ---- /dev/null -+++ b/targetcli/tcm_fileio.py -@@ -0,0 +1,83 @@ -+import os -+import subprocess as sub -+import string, re -+from optparse import OptionParser -+ -+tcm_root = "/sys/kernel/config/target/core" -+ -+def createvirtdev(path, params): -+ -+# print "Calling fileio createvirtdev: path " + path -+ cfs_path = tcm_root + "/" + path + "/" -+# print "Calling fileio createvirtdev: params " + str(params) -+ fd_params = str(params) -+ -+ # Extract the udev_dev path from fd_dev_name= -+ try: -+ off = fd_params.index('fd_dev_name=') -+ off += 12 -+ file_tmp = fd_params[off:] -+ file = file_tmp.split(',') -+ except IOError, msg: -+ print "Unable to locate fd_dev_name= parameter key" -+ return -1 -+ -+ # Set UDEV path if struct file is pointing to an underlying struct block_device -+ if re.search('/dev/', file[0]): -+ udev_path = file[0] -+ set_udev_path_op = "echo -n " + udev_path + " > " + cfs_path + "udev_path" -+ ret = os.system(set_udev_path_op) -+ if ret: -+ print "pSCSI: Unable to set udev_path in " + cfs_path + " for: " + udev_path -+ return -1 -+ -+ control_opt = "echo -n " + params[0] + " > " + cfs_path + "control" -+# print "control_opt: " + control_opt -+ ret = os.system(control_opt) -+ if ret: -+ print "FILEIO: createvirtdev failed for control_opt with " + params[0] -+ return -1 -+ -+ enable_opt = "echo 1 > " + cfs_path + "enable" -+# print "Calling enable_opt " + enable_opt -+ ret = os.system(enable_opt) -+ if ret: -+ print "FILEIO: createvirtdev failed for enable_opt with " + params[0] -+ return -1 -+ -+def fd_freevirtdev(): -+ pass -+ -+def fd_get_params(path): -+ # Reference by udev_path if available -+ udev_path_file = path + "/udev_path" -+ p = os.open(udev_path_file, 0) -+ value = os.read(p, 1024) -+ if re.search('/dev/', value): -+ os.close(p) -+ # Append a FILEIO size of ' 0', as struct block_device sector count is autodetected by TCM -+ return "fd_dev_name=" + value.rstrip() + ",fd_dev_size=0" -+ -+ os.close(p) -+ -+ info_file = path + "/info" -+ p = open(info_file, 'rU') -+ try: -+ value = p.read(1024) -+ except IOError, msg: -+ p.close() -+ return -+ p.close() -+ -+ off = value.index('File: ') -+ off += 6 -+ fd_dev_name_tmp = value[off:] -+ fd_dev_name = fd_dev_name_tmp.split(' ') -+ off = value.index(' Size: ') -+ off += 7 -+ fd_dev_size_tmp = value[off:] -+ fd_dev_size = fd_dev_size_tmp.split(' ') -+ params = "fd_dev_name=" + fd_dev_name[0] + ",fd_dev_size=" + fd_dev_size[0] -+ -+ # fd_dev_name= and fd_dev_size= parameters for tcm_node --createdev -+ return params -diff --git a/targetcli/tcm_iblock.py b/targetcli/tcm_iblock.py -new file mode 100644 -index 0000000..f522dd2 ---- /dev/null -+++ b/targetcli/tcm_iblock.py -@@ -0,0 +1,86 @@ -+import os, tempfile -+import subprocess as sub -+import string, re -+from optparse import OptionParser -+ -+tcm_root = "/sys/kernel/config/target/core" -+ -+def createvirtdev(path, params): -+# print "Calling iblock createvirtdev: path " + path -+ cfs_path = tcm_root + "/" + path + "/" -+# print "Calling iblock createvirtdev: params " + str(params) -+ path = params[0] -+ if not re.search('/dev/', path): -+ print "IBLOCK: Please reference a valid /dev/ block_device" -+ return -1 -+ -+ udev_path = path.rstrip() -+ # Resolve symbolic links to get major/minor -+ udev_op = "/bin/ls -laL " + udev_path -+ p = sub.Popen(udev_op, shell=True, stdout=sub.PIPE).stdout -+ line = p.readline() -+ out = line.split(' '); -+ major = out[4] -+ minor = out[5] -+ p.close() -+ -+ if major == "11,": -+ print "Unable to export Linux/SCSI TYPE_CDROM from IBLOCK, please use pSCSI export" -+ return -1 -+ if major == "22,": -+ print "Unable to export IDE CDROM from IBLOCK" -+ return -1 -+ -+ set_udev_path_op = "echo -n " + udev_path + " > " + cfs_path + "udev_path" -+ ret = os.system(set_udev_path_op) -+ if ret: -+ print "IBLOCK: Unable to set udev_path in " + cfs_path + " for: " + udev_path -+ return -1 -+ -+ control_opt = "echo -n udev_path=" + udev_path + " > " + cfs_path + "control" -+ ret = os.system(control_opt) -+ if ret: -+ print "IBLOCK: createvirtdev failed for control_opt with " + control_opt -+ return -1 -+ -+ enable_opt = "echo 1 > " + cfs_path + "enable" -+ ret = os.system(enable_opt) -+ if ret: -+ print "IBLOCK: createvirtdev failed for enable_opt with " + enable_opt -+ return -1 -+ -+def iblock_freevirtdev(): -+ pass -+ -+def iblock_get_params(path): -+ # Reference by udev_path if available -+ udev_path_file = path + "/udev_path" -+ p = os.open(udev_path_file, 0) -+ value = os.read(p, 1024) -+ if re.search('/dev/', value): -+ os.close(p) -+ return value.rstrip() -+ -+ os.close(p) -+ -+ info_file = path + "/info" -+ p = open(info_file, 'rU') -+ try: -+ value = p.read(1024) -+ except IOError, msg: -+ p.close() -+ return -+ p.close() -+ -+ of = value.index('Major: ') -+ off += 7 -+ major_tmp = value[off:] -+ major = major_tmp.split(' ') -+ off = value.index('Minor: ') -+ off += 7 -+ minor_tmp = value[off:] -+ minor = minor_tmp.split(' ') -+ params = "major=" + major[0] + ",minor=" + minor[0] -+ os.close(p) -+ -+ return params -diff --git a/targetcli/tcm_loop.py b/targetcli/tcm_loop.py -new file mode 100644 -index 0000000..aeb211a ---- /dev/null -+++ b/targetcli/tcm_loop.py -@@ -0,0 +1,242 @@ -+import os, sys -+import subprocess as sub -+import string -+import re -+from optparse import OptionParser -+ -+tcm_loop_root = "/sys/kernel/config/target/loopback/" -+tcm_root = "/sys/kernel/config/target/core" -+ -+def tcm_generate_naa_sas_address(): -+ # Use NAA IEEE Registered Designator prefix, and append WWN UUID below -+ sas_address = "naa.6001405" -+ -+ uuidgen_op = 'uuidgen' -+ p = sub.Popen(uuidgen_op, shell=True, stdout=sub.PIPE).stdout -+ uuid = p.readline() -+ p.close() -+ -+ if not uuid: -+ print "Unable to generate UUID using uuidgen, continuing anyway" -+ sys.exit(1) -+ -+ val = uuid.rstrip(); -+ sas_address += val[:10] -+ sas_address = sas_address.replace('-','') -+ -+ return sas_address -+ -+def tcm_loop_add_target_www(option, opt_str, value, parser): -+ sas_target_address = tcm_generate_naa_sas_address(); -+ sas_target_tpgt = str(value) -+ -+def tcm_loop_del_target_wwn(option, opt_str, value, parser): -+ sas_target_address = str(value[0]) -+ sas_target_tpgt = str(value[1]) -+ -+ tpgt_dir = tcm_loop_root + sas_target_address + "/tpgt_" + sas_target_tpgt -+ delete_op = "rmdir " + tpgt_dir -+ ret = os.system(delete_op) -+ if ret: -+ print "Unable to remove configfs group: " + tpgt_dir -+ -+ naa_dir = tcm_loop_root + sas_target_address -+ delete_op = "rmdir " + naa_dir -+ ret = os.system(delete_op) -+ if ret: -+ print "Unable to remove configfs group: " + naa_dir -+ else: -+ print "Successfully removed NAA based SAS Target Address: " + naa_dir + "/" + tpgt_dir -+ -+def tcm_loop_create_nexus(option, opt_str, value, parser): -+ sas_target_address = tcm_generate_naa_sas_address(); -+ sas_target_tpgt = str(value) -+ sas_initiator_address = tcm_generate_naa_sas_address(); -+ -+ tpgt_dir = tcm_loop_root + sas_target_address + "/tpgt_" + sas_target_tpgt -+ create_op = "mkdir -p " + tpgt_dir -+ ret = os.system(create_op) -+ if ret: -+ print "Unable to create virtual Target Port: " + create_op -+ sys.exit(1) -+ -+ # In TCM_Loop 4.x code, there is an nexus configfs attribute instead of -+ # nexus configfs group -+ nexus_dir = tpgt_dir + "/nexus" -+ if os.path.isfile(nexus_dir): -+ create_op = "echo " + sas_initiator_address + " > " + nexus_dir -+ else: -+ create_op = "mkdir -p " + nexus_dir + "/" + sas_initiator_address -+ -+ ret = os.system(create_op) -+ if ret: -+ print "Unable to create virtual SAS I_T Nexus: " + create_op -+ sys.exit(1) -+ else: -+ print "Successfully created virtual SCSI I_T Nexus between TCM and Linux/SCSI HBA" -+ print " SAS Target Address: " + sas_target_address -+ print " SAS Initiator Address " + sas_initiator_address -+ -+def tcm_loop_delete_nexus(option, opt_str, value, parser): -+ sas_target_address = str(value[0]) -+ sas_target_tpgt = str(value[1]) -+ sas_initiator_address = ""; -+ -+ nexus_dir = tcm_loop_root + sas_target_address + "/tpgt_" + sas_target_tpgt + "/nexus" -+ -+ if os.path.isfile(nexus_dir): -+ delete_op = "echo NULL > " + nexus_dir -+ -+ ret = os.system(delete_op) -+ if ret: -+ print "Unable to delete virtual SCSI I_T Nexus between TCM and Linux/SCSI HBA" -+ sys.exit(1) -+ -+ print "Successfully deleted virtual SCSI I_T Nexus between TCM and Linux/SCSI HBA" -+ return -+ -+ for nexus in os.listdir(nexus_dir): -+ delete_op = "rmdir " + nexus_dir + "/" + nexus -+ -+ ret = os.system(delete_op) -+ if ret: -+ print "Unable to delete virtual SCSI I_T Nexus between TCM and Linux/SCSI HBA" -+ sys.exit(1) -+ -+ print "Successfully deleted virtual SCSI I_T Nexus between TCM and Linux/SCSI HBA" -+ return -+ -+def tcm_loop_addlun(option, opt_str, value, parser): -+ sas_target_address = str(value[0]) -+ sas_target_tpgt = str(value[1]) -+ sas_target_lun = str(value[2]) -+ -+ mkdir_op = "mkdir -p " + tcm_loop_root + sas_target_address + "/tpgt_" + sas_target_tpgt + "/lun/lun_" + sas_target_lun -+ ret = os.system(mkdir_op) -+ if ret: -+ print "Unable to create SAS Target Port LUN configfs group: " + mkdir_op -+ sys.exit(1) -+ -+ tcm_obj = str(value[3]); -+ port_src = tcm_root + "/" + tcm_obj -+ port_dst = tcm_loop_root + sas_target_address + "/tpgt_" + sas_target_tpgt + "/lun/lun_" + sas_target_lun + "/virtual_scsi_port" -+ -+ link_op = "ln -s " + port_src + " " + port_dst -+ ret = os.system(link_op) -+ if not ret: -+ print "Successfully created SAS Target Port to local virtual SCSI Logical Unit" -+ # FIXME Add tcm_loop_alua_check_secondary_md() -+ # FIXME Add tcm_loop_alua_set_secondary_write_md() -+ else: -+ print "Unable to create SAS Target Port to local virtual SCSI Logical Unit" -+ sys.exit(1) -+ -+def tcm_loop_dellun(option, opt_str, value, parser): -+ sas_target_address = str(value[0]) -+ sas_target_tpgt = str(value[1]) -+ sas_target_lun = str(value[2]) -+ -+ port_link = "" -+ -+ lun_dir = tcm_loop_root + sas_target_address + "/tpgt_" + sas_target_tpgt + "/lun/lun_" + sas_target_lun -+ if not os.path.isdir(lun_dir): -+ print "TCM_Loop lun_dir: " + lun_dir + " does not exist" -+ sys.exit(1) -+ -+ # Locate the port symlink, skipping over the per TCM port alua_* attributes -+ for port in os.listdir(lun_dir): -+ port_link_tmp = lun_dir + "/" + port -+ if not os.path.islink(port_link_tmp): -+ continue -+ -+ port_link = port_link_tmp -+ break -+ -+ if port_link == "": -+ print "Active TCM_Loop port link does not exist!" -+ sys.exit(1) -+ -+ unlink_op = "unlink " + port_link -+ ret = os.system(unlink_op) -+ if ret: -+ print "Unable to unlink port for virtual SCSI Logical Unit: " + port -+ sys.exit(1) -+ -+ rmdir_op = "rmdir " + tcm_loop_root + sas_target_address + "/tpgt_" + sas_target_tpgt + "/lun/lun_" + sas_target_lun -+ ret = os.system(rmdir_op) -+ if ret: -+ print "Unable to rmdir configfs group for virtual SCSI Logical Unit: " + port -+ sys.exit(1) -+ else: -+ print "Succesfully deleted local virtual SCSI Logical Unit from SAS Target Port" -+ -+def tcm_loop_unload(option, opt_str, value, parser): -+ -+ for sas_target_naa in os.listdir(tcm_loop_root): -+ print "sas_target_naa: " + sas_target_naa -+ -+ if os.path.isfile(tcm_loop_root + sas_target_naa) == True: -+ continue -+ -+ tpgt_dir = tcm_loop_root + sas_target_naa + "/" -+ for sas_target_tpgt in os.listdir(tpgt_dir): -+ if sas_target_tpgt == "fabric_statistics": -+ continue -+ -+ print "sas_target_tpgt: " + sas_target_tpgt -+ -+ lun_dir = tpgt_dir + "/" + sas_target_tpgt + "/lun/" -+ for sas_target_lun in os.listdir(lun_dir): -+ -+ print "sas_target_lun: " + sas_target_lun -+ tpgt = sas_target_tpgt[5:] -+ lun = sas_target_lun[4:] -+ vals = [sas_target_naa, tpgt, lun] -+ tcm_loop_dellun(None, None, vals, None) -+ -+ tpgt = sas_target_tpgt[5:] -+ vals = [sas_target_naa, tpgt] -+ -+ tcm_loop_delete_nexus(None, None, vals, None) -+ -+ tcm_loop_del_target_wwn(None, None, vals, None) -+ -+ rmdir_op = "rmdir " + tcm_loop_root -+ ret = os.system(rmdir_op) -+ if ret: -+ print "Unable to remove tcm_loop_root configfs group: " + tcm_loop_root -+ sys.exit(1) -+ -+ rmmod_op = "rmmod tcm_loop" -+ ret = os.system(rmmod_op) -+ if ret: -+ print "Unable to remove tcm_loop kernel module" -+ sys.exit(1) -+ -+ print "Successfully removed tcm_loop kernel module" -+ -+def main(): -+ -+ parser = OptionParser() -+ parser.add_option("--delwwn", action="callback", callback=tcm_loop_del_target_wwn, nargs=2, -+ type="string", dest="NAA_TARGET_WWN TPGT", help="Delete a SAS Virtual HBA by WWN+TPGT") -+ parser.add_option("--createnexus", action="callback", callback=tcm_loop_create_nexus, nargs=1, -+ type="string", dest="TPGT", help="Create a virtual SAS I_T Nexus using generated NAA WWN for SAS Address. This will create a new Linux/SCSI Host Bus Adapter for the I_T Nexus"); -+ parser.add_option("--delnexus", action="callback", callback=tcm_loop_delete_nexus, nargs=2, -+ type="string", dest="NAA_TARGET_WWN TPGT", help="Delete a virtual SAS I_T Nexus"); -+ parser.add_option("--addlun", action="callback", callback=tcm_loop_addlun, nargs=4, -+ type="string", dest="NAA_TARGET_WWN TPGT LUN HBA/DEV", help="Add virtual SCSI Linux to NAA Target/Initiator Sas Addresses") -+ parser.add_option("--dellun", action="callback", callback=tcm_loop_dellun, nargs=3, -+ type="string", dest="NAA_TARGET_WWN TPGT LUN", help="Delete Target SAS Port to virtual SCSI Logical unit mapping") -+ parser.add_option("--unload", action="callback", callback=tcm_loop_unload, nargs=0, -+ help="Shutdown all virtual SCSI LUNs and unload tcm_loop") -+ -+ (options, args) = parser.parse_args() -+ if len(sys.argv) == 1: -+ parser.print_help() -+ sys.exit(0) -+ elif not re.search('--', sys.argv[1]): -+ lio_err("Unknown CLI option: " + sys.argv[1]) -+ -+if __name__ == "__main__": -+ main() -diff --git a/targetcli/tcm_node.py b/targetcli/tcm_node.py -new file mode 100644 -index 0000000..9df6f40 ---- /dev/null -+++ b/targetcli/tcm_node.py -@@ -0,0 +1,737 @@ -+from __future__ import with_statement -+ -+import os, sys, signal -+import subprocess as sub -+import string -+import re -+import errno -+import uuid -+import shutil -+from optparse import OptionParser -+ -+import tcm_pscsi -+import tcm_iblock -+import tcm_ramdisk -+import tcm_fileio -+ -+tcm_root = "/sys/kernel/config/target/core" -+ -+def tcm_err(msg): -+ print >> sys.stderr, msg -+ sys.exit(1) -+ -+def tcm_read(filename): -+ with open(filename) as f: -+ return f.read() -+ -+def tcm_write(filename, value, newline=True): -+ with open(filename, "w") as f: -+ f.write(value) -+ if newline: -+ f.write("\n") -+ -+def tcm_full_path(arg): -+ return tcm_root + "/" + arg -+ -+def tcm_check_dev_exists(dev_path): -+ full_path = tcm_full_path(dev_path) -+ if not os.path.isdir(full_path): -+ tcm_err("TCM/ConfigFS storage object does not exist: " + full_path) -+ -+def tcm_add_alua_lugp(gp_name): -+ os.makedirs(tcm_root + "/alua/lu_gps/" + gp_name) -+ -+ try: -+ tcm_write(tcm_root + "/alua/lu_gps/%s/lu_gp_id" % lu_gp_name, lu_gp_name) -+ except: -+ os.rmdir(tcm_root + "/alua/lu_gps/" + lu_gp_name) -+ raise -+ -+def tcm_add_alua_tgptgp(dev_path, gp_name): -+ tcm_check_dev_exists(dev_path) -+ -+ alua_cfs_path = tcm_full_path(dev_path) + "alua/" + gp_name + "/" -+ -+ os.makedirs(alua_cfs_path) -+ -+ try: -+ tcm_write(alua_cfs_path + "tg_pt_gp_id", "0") -+ except: -+ os.rmdir(alua_cfs_path) -+ raise -+ -+def tcm_alua_check_metadata_dir(dev_path): -+ alua_path = "/var/target/alua/tpgs_" + tcm_get_unit_serial(dev_path) + "/" -+ if os.path.isdir(alua_path): -+ return -+ -+ # Create the ALUA metadata directory for the passed storage object -+ # if it does not already exist. -+ os.makedirs(alua_path) -+ -+def tcm_alua_delete_metadata_dir(unit_serial): -+ try: -+ os.rmdir("/var/target/alua/tpgs_" + unit_serial + "/") -+ except OSError: -+ pass -+ -+def tcm_alua_process_metadata(dev_path, gp_name, gp_id): -+ alua_gp_path = tcm_full_path(dev_path) + "/alua/" + gp_name -+ alua_md_path = "/var/target/alua/tpgs_" + tcm_get_unit_serial(dev_path) \ -+ + "/" + gp_name -+ -+ if not os.path.isfile(alua_md_path): -+ # If not pre-existing ALUA metadata exists, go ahead and -+ # allow new ALUA state changes to create and update the -+ # struct file metadata -+ tcm_write(alua_gp_path + "/alua_write_metadata", "1") -+ return -+ -+ with open(alua_md_path, 'rU') as p: -+ d = dict() -+ for line in p.readlines(): -+ name, value = line.split("=") -+ d[name.strip()] = value.strip() -+ -+ if "tg_pt_gp_id" in d and int(d["tg_pt_gp_id"]) != int(gp_id): -+ raise IOError("Passed tg_pt_gp_id: %s does not match extracted: %s" % \ -+ (gp_id, d["tg_pt_gp_id"])) -+ -+ if "alua_access_state" in d: -+ tcm_write(alua_gp_path + "/alua_access_state", d["alua_access_state"]) -+ -+ if "alua_access_status" in d: -+ tcm_write(alua_gp_path + "/alua_access_status", d["alua_access_status"]) -+ -+ # Now allow changes to ALUA target port group update the struct file metadata -+ # in /var/target/alua/tpgs_$T10_UNIT_SERIAL/$TG_PT_GP_NAME -+ tcm_write(alua_gp_path + "/alua_write_metadata", "1") -+ -+def tcm_add_alua_tgptgp_with_md(dev_path, gp_name, gp_id): -+ alua_gp_path = tcm_full_path(dev_path) + "/alua/" + gp_name -+ -+ tcm_check_dev_exists(dev_path) -+ -+ # If the default_tg_pt_gp is passed, we skip the creation (as it already exists) -+ # and just process ALUA metadata -+ if gp_name == 'default_tg_pt_gp' and gp_id == '0': -+ tcm_alua_process_metadata(dev_path, gp_name, gp_id) -+ return -+ -+ os.makedirs(alua_gp_path) -+ -+ try: -+ tcm_write(alua_gp_path + "/tg_pt_gp_id", gp_id) -+ except: -+ os.rmdir(alua_gp_path) -+ raise -+ -+ # Now process the ALUA metadata for this group -+ tcm_alua_process_metadata(dev_path, gp_name, gp_id) -+ -+def tcm_delhba(hba_name): -+ hba_path = tcm_full_path(hba_name) -+ -+ for g in os.listdir(hba_path): -+ if g == "hba_info" or g == "hba_mode": -+ continue -+ -+ __tcm_freevirtdev(hba_name + "/" + g) -+ -+ os.rmdir(hba_path) -+ -+def tcm_del_alua_lugp(lu_gp_name): -+ if not os.path.isdir(tcm_root + "/alua/lu_gps/" + lu_gp_name): -+ tcm_err("ALUA Logical Unit Group: " + lu_gp_name + " does not exist!") -+ -+ os.rmdir(tcm_root + "/alua/lu_gps/" + lu_gp_name) -+ -+def __tcm_del_alua_tgptgp(dev_path, gp_name): -+ tcm_check_dev_exists(dev_path) -+ -+ full_path = tcm_full_path(dev_path) -+ -+ if not os.path.isdir(full_path + "/alua/" + gp_name): -+ tcm_err("ALUA Target Port Group: " + gp_name + " does not exist!") -+ -+ os.rmdir(full_path + "/alua/" + gp_name) -+ -+# deletes configfs entry for alua *and* metadata dir. -+def tcm_del_alua_tgptgp(dev_path, gp_name): -+ tcm_check_dev_exists(dev_path) -+ -+ alua_md_path = "/var/target/alua/tpgs_" + tcm_get_unit_serial(dev_path) \ -+ + "/" + gp_name -+ -+ __tcm_del_alua_tgptgp(dev_path, gp_name) -+ -+ if not os.path.isfile(alua_md_path): -+ return -+ -+ shutil.rmtree(alua_md_path) -+ -+def tcm_generate_uuid_for_unit_serial(dev_path): -+ # Generate random uuid -+ tcm_set_wwn_unit_serial(dev_path, str(uuid.uuid4())) -+ -+tcm_types = ( \ -+ dict(name="pscsi", module=tcm_pscsi, gen_uuid=False), -+ dict(name="stgt", module=None, gen_uuid=True), -+ dict(name="iblock", module=tcm_iblock, gen_uuid=True), -+ dict(name="rd_dr", module=tcm_ramdisk, gen_uuid=True), -+ dict(name="rd_mcp", module=tcm_ramdisk, gen_uuid=True), -+ dict(name="fileio", module=tcm_fileio, gen_uuid=True), -+) -+ -+def tcm_createvirtdev(dev_path, plugin_params, establishdev=False): -+ hba_path = dev_path.split('/')[0] -+ -+ # create hba if it doesn't exist -+ hba_full_path = tcm_full_path(hba_path) -+ if not os.path.isdir(hba_full_path): -+ os.mkdir(hba_full_path) -+ -+ # create dev if it doesn't exist -+ full_path = tcm_full_path(dev_path) -+ if os.path.isdir(full_path): -+ tcm_err("TCM/ConfigFS storage object already exists: " + full_path) -+ else: -+ os.mkdir(full_path) -+ -+ # Determine if --establishdev is being called and we want to skip -+ # the T10 Unit Serial Number generation -+ gen_uuid = True -+ if establishdev: -+ gen_uuid = False -+ -+ # Calls into submodules depending on target_core_mod subsystem plugin -+ for tcm in tcm_types: -+ if hba_path.startswith(tcm["name"] + "_"): -+ try: -+ if tcm["module"]: -+ # modules expect plugin_params to be a list, for now. -+ tcm["module"].createvirtdev(dev_path, [plugin_params]) -+ else: -+ tcm_err("no module for %s" % tcm["name"]) -+ except: -+ os.rmdir(full_path) -+ print "Unable to register TCM/ConfigFS storage object: " \ -+ + full_path -+ raise -+ -+ print tcm_read(full_path + "/info") -+ -+ if tcm["gen_uuid"] and gen_uuid: -+ tcm_generate_uuid_for_unit_serial(dev_path) -+ tcm_alua_check_metadata_dir(dev_path) -+ break -+ -+def tcm_get_unit_serial(dev_path): -+ string = tcm_read(tcm_full_path(dev_path) + "/wwn/vpd_unit_serial") -+ return string.split(":")[1].strip() -+ -+def tcm_show_aptpl_metadata(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ aptpl_file = "/var/target/pr/aptpl_" + tcm_get_unit_serial(dev_path) -+ if not os.path.isfile(aptpl_file): -+ tcm_err("Unable to dump PR APTPL metadata file: " + aptpl_file) -+ -+ print tcm_read(aptpl_file) -+ -+def tcm_delete_aptpl_metadata(unit_serial): -+ aptpl_file = "/var/target/pr/aptpl_" + unit_serial -+ if not os.path.isfile(aptpl_file): -+ return -+ -+ shutil.rmtree(aptpl_file) -+ -+def tcm_process_aptpl_metadata(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ full_path = tcm_full_path(dev_path) -+ -+ aptpl_file = "/var/target/pr/aptpl_" + tcm_get_unit_serial(dev_path) -+ if not os.path.isfile(aptpl_file): -+ return -+ -+ # read PR info from file -+ lines = tcm_read(aptpl_file).split() -+ -+ if not lines[0].startswith("PR_REG_START:"): -+ return -+ -+ reservations = [] -+ for line in lines: -+ if line.startswith("PR_REG_START:"): -+ res_list = [] -+ elif line.startswith("PR_REG_END:"): -+ reservations.append(res_list) -+ else: -+ res_list.append(line.strip()) -+ -+ # write info into configfs -+ for res in reservations: -+ tcm_write(full_path + "/pr/res_aptpl_metadata", ",".join(res)) -+ -+def tcm_establishvirtdev(dev_path, plugin_params): -+ tcm_createvirtdev(dev_path, plugin_params, True) -+ -+def tcm_create_pscsi(dev_path, ctl): -+ # convert passed 3-tuple to format pscsi expects -+ # "1:3:5" -> "scsi_channel_id=1,scsi_target_id=3..." -+ # -+ param_names = ("scsi_channel_id", "scsi_target_id", "scsi_lun_id") -+ -+ pscsi_params = zip(param_names, ctl.split(":")) -+ pscsi_params_str = ",".join([x + "=" + y for x, y in pscsi_params]) -+ -+ tcm_createvirtdev(dev_path, pscsi_params_str) -+ -+def tcm_create_pscsibyudev(dev_path, udev_path): -+ tcm_createvirtdev(cfs_dev, udev_path) -+ -+def tcm_create_iblock(dev_path, udev_path): -+ tcm_createvirtdev(dev_path, udev_path) -+ -+def tcm_create_fileio(dev_path, filename, size): -+ fileio_params = "fd_dev_name=" + filename + ",fd_dev_size=" + size -+ tcm_createvirtdev(dev_path, fileio_params) -+ -+def tcm_create_ramdisk(dev_path, pages): -+ tcm_createvirtdev(dev_path, pages) -+ -+def __tcm_freevirtdev(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ full_path = tcm_full_path(dev_path) -+ -+ for tg_pt_gp in os.listdir(full_path + "/alua/"): -+ if tg_pt_gp == "default_tg_pt_gp": -+ continue -+ __tcm_del_alua_tgptgp(dev_path, tg_pt_gp) -+ -+ os.rmdir(full_path) -+ -+def tcm_freevirtdev(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ unit_serial = tcm_get_unit_serial(dev_path) -+ -+ __tcm_freevirtdev(dev_path) -+ # For explict tcm_node --freedev, delete any remaining -+ # PR APTPL and ALUA metadata -+ tcm_delete_aptpl_metadata(unit_serial) -+ tcm_alua_delete_metadata_dir(unit_serial) -+ -+def tcm_list_dev_attribs(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ full_path = tcm_full_path(dev_path) -+ -+ print "TCM Storage Object Attributes for " + full_path -+ for attrib in os.listdir(full_path + "/attrib/"): -+ print " %s: %s" % \ -+ (attrib, tcm_read(full_path + "/attrib/" + attrib).strip()) -+ -+def tcm_list_hbas(): -+ for hba in os.listdir(tcm_root): -+ if hba == "alua": -+ continue -+ -+ print "\------> " + hba -+ dev_root = tcm_root + "/" + hba -+ print "\t" + tcm_read(dev_root+"/hba_info").strip() -+ -+ for dev in os.listdir(dev_root): -+ if dev in ("hba_info", "hba_mode"): -+ continue -+ -+ try: -+ value = tcm_read(dev_root + "/" + dev + "/info") -+ except IOError, msg: -+ print " \-------> " + dev -+ print " No TCM object association active, skipping" -+ continue -+ -+ udev_path = tcm_read(dev_root + "/" + dev + "/udev_path") -+ if udev_path: -+ udev_str = "udev_path: " + udev_path.rstrip() -+ else: -+ udev_str = "udev_path: N/A" -+ -+ print " \-------> " + dev -+ print " " + value.rstrip() -+ print " " + udev_str -+ -+def tcm_list_alua_lugps(): -+ for lu_gp in os.listdir(tcm_root + "/alua/lu_gps"): -+ group_path = tcm_root + "/alua/lu_gps/" + lu_gp -+ lu_gp_id = tcm_read(group_path + "/lu_gp_id").strip() -+ print "\------> " + lu_gp + " LUN Group ID: " + lu_gp_id -+ -+ lu_gp_members = tcm_read(group_path + "/members").strip().split() -+ -+ if not lu_gp_members: -+ print " No Logical Unit Group Members" -+ continue -+ -+ for member in lu_gp_members: -+ print " " + member -+ -+def tcm_dump_alua_state(alua_state_no): -+ if alua_state_no == "0": -+ return "Active/Optimized" -+ elif alua_state_no == "1": -+ return "Active/NonOptimized" -+ elif alua_state_no == "2": -+ return "Standby" -+ elif alua_state_no == "3": -+ return "Unavailable" -+ elif alua_state_no == "15": -+ return "Transition" -+ else: -+ return "Unknown" -+ -+def tcm_list_alua_tgptgp(dev_path, gp_name): -+ tcm_check_dev_exists(dev_path) -+ -+ gp_path = tcm_full_path(dev_path) + "/alua/" + gp_name -+ -+ gp_id = tcm_read(gp_path + "/tg_pt_gp_id").strip() -+ print "\------> " + tg_pt_gp + " Target Port Group ID: " + tg_pt_gp_id -+ -+ alua_type = tcm_read(gp_path + "/alua_access_type").strip() -+ print " Active ALUA Access Type(s): " + alua_type -+ -+ alua_state = tcm_read(gp_path + "/alua_access_state").strip() -+ print " Primary Access State: " + tcm_dump_alua_state(alua_state) -+ -+ try: -+ access_status = tcm_read(gp_path + "/alua_access_status").strip() -+ print " Primary Access Status: " + access_status -+ except IOError: -+ pass -+ -+ preferred = tcm_read(gp_path + "/preferred").strip() -+ print " Preferred Bit: " + preferred -+ -+ nonop_delay = tcm_read(gp_path + "/nonop_delay_msecs").strip() -+ print " Active/NonOptimized Delay in milliseconds: " + nonop_delay -+ -+ trans_delay = tcm_read(gp_path + "/trans_delay_msecs").strip() -+ print " Transition Delay in milliseconds: " + trans_delay -+ -+ gp_members = tcm_read(gp_path + "/members").strip().split() -+ -+ print " \------> TG Port Group Members" -+ if not gp_members: -+ print " No Target Port Group Members" -+ else: -+ for member in gp_members: -+ print " " + member -+ -+def tcm_list_alua_tgptgps(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ for tg_pt_gp in os.listdir(tcm_full_path(dev_path) + "/alua/"): -+ tcm_list_alua_tgptgp(dev_path, tg_pt_gp) -+ -+def tcm_show_persistent_reserve_info(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ full_path = tcm_full_path(dev_path) -+ -+ for f in os.listdir(full_path + "/pr/"): -+ info = tcm_read(full_path + "/pr/" + f).strip() -+ if info: -+ print info -+ -+def tcm_set_alua_state(dev_path, gp_name, access_state): -+ tcm_check_dev_exists(dev_path) -+ -+ new_alua_state_str = str(access_state).lower() -+ -+ if new_alua_state_str == "o": -+ alua_state = 0 # Active/Optimized -+ elif new_alua_state_str == "a": -+ alua_state = 1 # Active/NonOptimized -+ elif new_alua_state_str == "s": -+ alua_state = 2 # Standby -+ elif new_alua_state_str == "u": -+ alua_state = 3 # Unavailable -+ else: -+ tcm_err("Unknown ALUA access state: " + new_alua_state_str) -+ -+ alua_path = tcm_full_path(dev_path) + "/alua/" + gp_name + "/alua_access_state" -+ tcm_write(alua_path, str(alua_state)) -+ -+def tcm_set_alua_type(dev_path, gp_name, access_type): -+ tcm_check_dev_exists(dev_path) -+ -+ new_alua_type_str = str(access_type).lower() -+ -+ if new_alua_type_str == "both": -+ alua_type = 3 -+ elif new_alua_type_str == "explict": -+ alua_type = 2 -+ elif new_alua_type_str == "implict": -+ alua_type = 1 -+ elif new_alua_type_str == "none": -+ alua_type = 0 -+ else: -+ tcm_err("Unknown ALUA access type: " + new_alua_type_str) -+ -+ alua_path = tcm_full_path(dev_path) + "/alua/" + gp_name + "/alua_access_type" -+ tcm_write(alua_path, str(alua_type)) -+ -+def tcm_set_alua_nonop_delay(dev_path, gp_name, msec_delay): -+ tcm_check_dev_exists(dev_path) -+ -+ if not os.path.isdir(tcm_full_path(dev_path) + "/alua/" + gp_name): -+ tcm_err("Unable to locate TG Pt Group: " + gp_name) -+ -+ alua_path = tcm_full_path(dev_path) + "/alua/" + gp_name + "/nonop_delay_msecs" -+ tcm_write(alua_path, str(msec_delay)) -+ -+def tcm_set_alua_trans_delay(dev_path, gp_name, msec_delay): -+ tcm_check_dev_exists(dev_path) -+ -+ if not os.path.isdir(tcm_full_path(dev_path) + "/alua/" + gp_name): -+ tcm_err("Unable to locate TG Pt Group: " + gp_name) -+ -+ alua_path = tcm_full_path(dev_path) + "/alua/" + gp_name + "/trans_delay_msecs" -+ tcm_write(alua_path, str(msec_delay)) -+ -+def tcm_clear_alua_tgpt_pref(dev_path, gp_name): -+ tcm_check_dev_exists(dev_path) -+ -+ if not os.path.isdir(tcm_full_path(dev_path) + "/alua/" + gp_name): -+ tcm_err("Unable to locate TG Pt Group: " + gp_name) -+ -+ alua_path = tcm_full_path(dev_path) + "/alua/" + gp_name + "/preferred" -+ tcm_write(alua_path, "0") -+ -+def tcm_set_alua_tgpt_pref(dev_path, gp_name): -+ tcm_check_dev_exists(dev_path) -+ -+ if not os.path.isdir(tcm_full_path(dev_path) + "/alua/" + gp_name): -+ tcm_err("Unable to locate TG Pt Group: " + gp_name) -+ -+ alua_path = tcm_full_path(dev_path) + "/alua/" + gp_name + "/preferred" -+ tcm_write(alua_path, "1") -+ -+def tcm_set_alua_lugp(dev_path, gp_name): -+ tcm_check_dev_exists(dev_path) -+ -+ if not os.path.isdir(tcm_full_path(dev_path) + "/alua/lu_gps/" + gp_name): -+ tcm_err("Unable to locate ALUA Logical Unit Group: " + gp_name) -+ -+ alua_path = tcm_full_path(dev_path) + "/alua/lu_gps/" + gp_name + "/alua_lu_gp" -+ tcm_write(alua_path, gp_name) -+ -+def tcm_set_dev_attrib(dev_path, attrib, value): -+ tcm_check_dev_exists(dev_path) -+ -+ tcm_write(tcm_full_path(dev_path) + "/attrib/" + attrib, value) -+ -+def tcm_set_udev_path(dev_path, udev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ tcm_write(tcm_full_path(dev_path) + "/udev_path", udev_path, newline=False) -+ -+def tcm_set_wwn_unit_serial(dev_path, unit_serial): -+ tcm_check_dev_exists(dev_path) -+ -+ tcm_write(tcm_full_path(dev_path) + "/wwn/vpd_unit_serial", unit_serial) -+ -+def tcm_set_wwn_unit_serial_with_md(dev_path, unit_serial): -+ tcm_check_dev_exists(dev_path) -+ -+ tcm_set_wwn_unit_serial(dev_path, unit_serial) -+ # Process PR APTPL metadata -+ tcm_process_aptpl_metadata(dev_path) -+ # Make sure the ALUA metadata directory exists for this storage object -+ tcm_alua_check_metadata_dir(dev_path) -+ -+def tcm_show_udev_path(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ print tcm_read(tcm_full_path(dev_path) + "/udev_path") -+ -+def tcm_show_wwn_info(dev_path): -+ tcm_check_dev_exists(dev_path) -+ -+ full_path = tcm_full_path(dev_path) + "/wwn/" -+ -+ for f in os.listdir(full_path): -+ info = tcm_read(full_path + f).strip() -+ if info: -+ print info -+ -+def tcm_unload(): -+ if not os.path.isdir(tcm_root): -+ tcm_err("Unable to access tcm_root: " + tcm_root) -+ -+ hba_root = os.listdir(tcm_root) -+ -+ for f in hba_root: -+ if f == "alua": -+ continue -+ -+ tcm_delhba(f) -+ -+ for lu_gp in os.listdir(tcm_root + "/alua/lu_gps"): -+ if lu_gp == "default_lu_gp": -+ continue -+ -+ tcm_del_alua_lugp(lu_gp) -+ -+ # Unload TCM subsystem plugin modules -+ for module in ("iblock", "file", "pscsi", "stgt"): -+ os.system("rmmod target_core_%s" % module) -+ -+ # Unload TCM Core -+ rmmod_op = "rmmod target_core_mod" -+ ret = os.system(rmmod_op) -+ if ret: -+ tcm_err("Unable to rmmod target_core_mod") -+ -+def tcm_version(): -+ return tcm_read("/sys/kernel/config/target/version").strip() -+ -+cmdline_options = ( \ -+ dict(opt_str="--addlungp", callback=tcm_add_alua_lugp, nargs=1, -+ dest="lu_gp_name", help="Add ALUA Logical Unit Group"), -+ dict(opt_str=("--addtgptgp","--addaluatpg"), -+ callback=tcm_add_alua_tgptgp, nargs=2, -+ dest="HBA/DEV ", -+ help="Add ALUA Target Port Group to Storage Object"), -+ dict(opt_str=("--addtgptgpwithmd","--addaluatpgwithmd"), action="callback", -+ callback=tcm_add_alua_tgptgp_with_md, nargs=3, -+ dest="HBA/DEV ", -+ help="Add ALUA Target Port Group to Storage Object with ID and process ALUA metadata"), -+ dict(opt_str=("--block","--iblock"), callback=tcm_create_iblock, nargs=2, -+ dest="HBA/DEV ", -+ help="Associate TCM/IBLOCK object with Linux/BLOCK device"), -+ dict(opt_str="--clearaluapref", callback=tcm_clear_alua_tgpt_pref, -+ nargs=2, dest="HBA/DEV ", -+ help="Clear ALUA Target Port Group Preferred Bit"), -+ dict(opt_str="--delhba", callback=tcm_delhba, nargs=1, -+ dest="HBA", help="Delete TCM Host Bus Adapter (HBA)"), -+ dict(opt_str="--dellungp", callback=tcm_del_alua_lugp, nargs=1, -+ dest="lu_gp_name", help="Delete ALUA Logical Unit Group"), -+ dict(opt_str=("--deltgptgp","--delaluatpg"), callback=tcm_del_alua_tgptgp, nargs=2, -+ dest="HBA/DEV TG_PT_GP_NAME", -+ help="Delete ALUA Target Port Group from Storage Object"), -+ dict(opt_str="--createdev", callback=tcm_createvirtdev, nargs=2, -+ dest="HBA/DEV ", -+ help="Create TCM Storage Object using subsystem dependent parameters," -+ " and generate new T10 Unit Serial for IBLOCK,FILEIO,RAMDISK"), -+ dict(opt_str="--establishdev", callback=tcm_establishvirtdev, nargs=2, -+ dest="HBA/DEV ", -+ help="Create TCM Storage Object using subsystem dependent parameters, do" -+ "not generate new T10 Unit Serial"), -+ dict(opt_str="--fileio", callback=tcm_create_fileio, nargs=3, -+ dest="HBA/DEV ", -+ help="Associate TCM/FILEIO object with Linux/VFS file or underlying" -+ " device for buffered FILEIO"), -+ dict(opt_str="--freedev", callback=tcm_freevirtdev, nargs=1, -+ dest="HBA/DEV", help="Free TCM Storage Object"), -+ dict(opt_str="--listdevattr", callback=tcm_list_dev_attribs, nargs=1, -+ dest="HBA/DEV", help="List TCM storage object device attributes"), -+ dict(opt_str="--listhbas", callback=tcm_list_hbas, nargs=0, -+ help="List TCM Host Bus Adapters (HBAs)"), -+ dict(opt_str="--listlugps", callback=tcm_list_alua_lugps, nargs=0, -+ help="List ALUA Logical Unit Groups"), -+ dict(opt_str=("--listtgptgp","--listaluatpg"), callback=tcm_list_alua_tgptgp, nargs=2, -+ dest="HBA/DEV ", -+ help="List specific ALUA Target Port Group for Storage Object"), -+ dict(opt_str=("--listtgptgps","--listaluatpgs"), callback=tcm_list_alua_tgptgps, nargs=1, -+ dest="HBA/DEV", help="List all ALUA Target Port Groups for Storage Object"), -+ dict(opt_str="--pr", callback=tcm_show_persistent_reserve_info, nargs=1, -+ dest="HBA/DEV", help="Show Persistent Reservation info"), -+ dict(opt_str="--praptpl", callback=tcm_process_aptpl_metadata, nargs=1, -+ dest="HBA/DEV", help="Process PR APTPL metadata from file"), -+ dict(opt_str="--prshowmd", callback=tcm_show_aptpl_metadata, nargs=1, -+ dest="HBA/DEV", help="Show APTPL metadata file"), -+ dict(opt_str="--ramdisk", callback=tcm_create_ramdisk, nargs=2, -+ dest="HBA/DEV ", help="Create and associate TCM/RAMDISK object"), -+ dict(opt_str=("--scsi","--pscsi"), callback=tcm_create_pscsi, nargs=2, -+ dest="HBA/DEV ", -+ help="Associate TCM/pSCSI object with Linux/SCSI device by bus location"), -+ dict(opt_str=("--scsibyudev", "--pscsibyudev"), callback=tcm_create_pscsibyudev, nargs=2, -+ dest="HBA/DEV ", -+ help="Associate TCM/pSCSI object with Linux/SCSI device by UDEV Path"), -+ dict(opt_str="--setaluadelay", callback=tcm_set_alua_nonop_delay, nargs=3, -+ dest="HBA/DEV ", -+ help="Set ALUA Target Port Group delay for Active/NonOptimized in milliseconds"), -+ dict(opt_str="--setaluapref", callback=tcm_set_alua_tgpt_pref, nargs=2, -+ dest="HBA/DEV ", help="Set ALUA Target Port Group Preferred Bit"), -+ dict(opt_str="--setaluastate", callback=tcm_set_alua_state, nargs=3, -+ dest="HBA/DEV ", -+ help="Set ALUA access state for TG_PT_GP_NAME on Storage Object. The value access" -+ " states are \"o\" = active/optimized, \"a\" = active/nonoptimized, \"s\" = standby," -+ " \"u\" = unavailable"), -+ dict(opt_str="--setaluatransdelay", callback=tcm_set_alua_trans_delay, nargs=3, -+ dest="HBA/DEV ", -+ help="Set ALUA Target Port Group Transition delay"), -+ dict(opt_str="--setaluatype", callback=tcm_set_alua_type, nargs=3, -+ dest="HBA/DEV ", -+ help="Set ALUA access type for TG_PT_GP_NAME on Storage Object. The value type" -+ " states are \"both\" = implict/explict, \"explict\", \"implict\", or \"none\""), -+ dict(opt_str="--setdevattr", callback=tcm_set_dev_attrib, nargs=3, -+ dest="HBA/DEV ", -+ help="Set new value for TCM storage object device attribute"), -+ dict(opt_str="--setlugp", callback=tcm_set_alua_lugp, nargs=2, -+ dest="HBA/DEV LU_GP_NAME", help="Set ALUA Logical Unit Group"), -+ dict(opt_str="--setudevpath", callback=tcm_set_udev_path, nargs=2, -+ dest="HBA/DEV ", -+ help="Set UDEV Path Information, only used when --createdev did not contain" -+ " as parameter"), -+ dict(opt_str="--setunitserial", callback=tcm_set_wwn_unit_serial, nargs=2, -+ dest="HBA/DEV ", help="Set T10 EVPD Unit Serial Information"), -+ dict(opt_str="--setunitserialwithmd", callback=tcm_set_wwn_unit_serial_with_md, nargs=2, -+ dest="HBA/DEV ", -+ help="Set T10 EVPD Unit Serial Information and process PR APTPL metadata"), -+ dict(opt_str="--udevpath", callback=tcm_show_udev_path, nargs=1, -+ dest="HBA/DEV", help="Show UDEV Path Information for TCM storage object"), -+ dict(opt_str="--unload", callback=tcm_unload, nargs=0, -+ help="Unload target_core_mod"), -+ dict(opt_str="--wwn", callback=tcm_show_wwn_info, nargs=1, -+ dest="HBA/DEV", help="Show WWN info"), -+) -+ -+def dispatcher(option, opt_str, value, parser, orig_callback): -+ if option.nargs == 1: -+ value = (value,) -+ value = [str(x).strip() for x in value] -+ orig_callback(*value) -+ -+def main(): -+ -+ parser = OptionParser(version=tcm_version()) -+ -+ for opt in cmdline_options: -+ # cmd_aliases can be string or tuple of strings. -+ # we're unpacking below, so convert strings to 1 item tuples -+ cmd_aliases = opt["opt_str"] -+ if isinstance(cmd_aliases, basestring): -+ cmd_aliases = (cmd_aliases,) -+ del opt["opt_str"] -+ # common params for all options -+ opt["action"] = "callback" -+ opt["type"] = "string" -+ opt["callback_kwargs"] = dict(orig_callback=opt["callback"]) -+ opt["callback"] = dispatcher -+ parser.add_option(*cmd_aliases, **opt) -+ -+ (options, args) = parser.parse_args() -+ if len(sys.argv) == 1: -+ parser.print_help() -+ sys.exit(0) -+ elif not re.search('--', sys.argv[1]): -+ tcm_err("Unknown CLI option: " + sys.argv[1]) -+ -+if __name__ == "__main__": -+ main() -diff --git a/targetcli/tcm_pscsi.py b/targetcli/tcm_pscsi.py -new file mode 100644 -index 0000000..f849279 ---- /dev/null -+++ b/targetcli/tcm_pscsi.py -@@ -0,0 +1,184 @@ -+import os -+import subprocess as sub -+import string, re -+from optparse import OptionParser -+ -+tcm_root = "/sys/kernel/config/target/core" -+ -+def print_lsscsi(option, opt_str, value, parser): -+ command = "lsscsi" -+ -+ p = sub.Popen(command,shell=True, stdout=sub.PIPE).stdout -+ while 1: -+ line = p.readline() -+ if not line: break -+ print line, -+ -+def pscsi_get_hba_prefix(arg): -+ path = "/sys/kernel/config/target/core/pscsi_" + arg -+ return path -+ -+def pscsi_scan_lsscsi(option, opt_str, value, parser): -+ command = "lsscsi -H" -+ p = sub.Popen(command,shell=True, stdout=sub.PIPE).stdout -+ while 1: -+ line = p.readline() -+ if not line: break -+ line.split() -+ host_id = line[1] -+ print "SCSI Host ID: " + host_id -+ -+ cfs_path = pscsi_get_hba_prefix(host_id) -+ if (os.path.isdir(cfs_path)): -+ print "pSCSI HBA already registered, skipping" -+ continue -+ -+ print cfs_path -+ ret = os.mkdir(cfs_path) -+ print "os.path.mkdir ret: " + str(ret) -+ if not ret: -+ print "Successfully added ConfigFS path " + cfs_path -+ -+def createvirtdev(path, params): -+ -+# print "Calling pscsi createvirtdev: path " + path -+ cfs_path = tcm_root + "/" + path + "/" -+ -+# print "Calling pscsi createvirtdev: params " + str(params) -+ pscsi_params = params[0] -+# print pscsi_params -+ -+ # Exract HCTL from sysfs and set udev_path -+ if re.search('/dev/', pscsi_params): -+ udev_path = pscsi_params.rstrip() -+ if re.search('/dev/disk/', udev_path): -+ udev_op = "/bin/ls -l " + udev_path -+ p = sub.Popen(udev_op, shell=True, stdout=sub.PIPE).stdout -+ if not p: -+ print "pSCSI: Unable to locate scsi_device from udev_path: " + udev_path -+ return -1 -+ -+ line = p.readline() -+ out = line.split(' ../../'); -+ p.close() -+ if not out: -+ print "pSCSI: Unable to locate scsi_device from udev_path: " + udev_path -+ return -1 -+ -+ scsi_dev = out[1].rstrip() -+ elif re.search('/dev/s', udev_path): -+ out = udev_path.split('/dev/') -+ scsi_dev = out[1] -+ else: -+ print "pSCSI: Unable to locate scsi_device from udev_path: " + udev_path -+ return -1 -+ -+ # Convert scdX to sr0 for TYPE_ROM in /sys/block/ -+ if re.search('scd', scsi_dev): -+ scsi_dev = scsi_dev.replace('scd', 'sr'); -+ -+ if not os.path.isdir("/sys/block/" + scsi_dev + "/device/"): -+ print "pSCSI: Unable to locate scsi_device from udev_path: " + udev_path -+ return -1 -+ -+ scsi_dev_sysfs = "/sys/block/" + scsi_dev + "/device" -+ udev_op = "/bin/ls -l " + scsi_dev_sysfs -+ p = sub.Popen(udev_op, shell=True, stdout=sub.PIPE).stdout -+ if not p: -+ print "pSCSI: Unable to locate scsi_device from udev_path: " + udev_path -+ return -1 -+ -+ line = p.readline() -+ out = line.split('/') -+ p.close() -+ -+ scsi_hctl_tmp = out[len(out)-1] -+ scsi_hctl = scsi_hctl_tmp.split(':') -+ scsi_host_id = scsi_hctl[0] -+ scsi_channel_id = scsi_hctl[1] -+ scsi_target_id = scsi_hctl[2] -+ scsi_lun_id = scsi_hctl[3] -+ print "pSCSI: Referencing HCTL " + out[1].rstrip() + " for udev_path: " + udev_path -+ -+ set_udev_path_op = "echo -n " + udev_path + " > " + cfs_path + "udev_path" -+ ret = os.system(set_udev_path_op) -+ if ret: -+ print "pSCSI: Unable to set udev_path in " + cfs_path + " for: " + udev_path -+ return -1 -+ -+ pscsi_params = "scsi_host_id=" + scsi_host_id + ",scsi_channel_id=" + scsi_channel_id + ",scsi_target_id=" + scsi_target_id + ",scsi_lun_id=" + scsi_lun_id.rstrip() -+ -+ -+ control_opt = "echo -n " + pscsi_params + " > " + cfs_path + "control" -+# print "Calling control_opt " + control_opt -+ ret = os.system(control_opt) -+ if ret: -+ print "pSCSI: createvirtdev failed for control_opt with " + pscsi_params -+ return -1 -+ -+ enable_opt = "echo 1 > " + cfs_path + "enable" -+# print "Calling enable_opt " + enable_opt -+ ret = os.system(enable_opt) -+ if ret: -+ print "pSCSI: createvirtdev failed for enable_opt with " + pscsi_params -+ return -1 -+ -+def pscsi_freevirtdev(): -+ pass -+ -+def pscsi_get_params(path): -+ # Reference by udev_path if available -+ udev_path_file = path + "/udev_path" -+ p = os.open(udev_path_file, 0) -+ value = os.read(p, 1024) -+ if re.search('/dev/', value): -+ os.close(p) -+ return value.rstrip() -+ -+ os.close(p) -+ -+ info_file = path + "/info" -+ p = open(info_file, 'rU') -+ try: -+ value = p.read(1024) -+ except IOError, msg: -+ p.close() -+ return -+ p.close() -+ -+ off = value.index('Channel ID: ') -+ off += 12 -+ channel_id_tmp = value[off:] -+ channel_id = channel_id_tmp.split(' ') -+ off = value.index('Target ID: ') -+ off += 11 -+ target_id_tmp = value[off:] -+ target_id = target_id_tmp.split(' ') -+ off = value.index('LUN: ') -+ off += 5 -+ lun_id_tmp = value[off:] -+ lun_id = lun_id_tmp.split(' ') -+ params = "" -+ -+ try: -+ off = value.index('Host ID: ') -+ except ValueError: -+ params = "" -+ else: -+ off += 9 -+ host_id_tmp = value[off:] -+ host_id = host_id_tmp.split(' ') -+ host_id = host_id[0].rstrip() -+ if host_id != "PHBA": -+ params += "scsi_host_id=" + host_id[0] + "," -+ -+ params += "scsi_channel_id=" + channel_id[0] + ",scsi_target_id=" + target_id[0] + ",scsi_lun_id=" + lun_id[0].rstrip() -+ -+ # scsi_channel_id=, scsi_target_id= and scsi_lun_id= reference for tcm_node --createdev -+ return params -+ -+#parser = OptionParser() -+#parser.add_option("-s", "--scan", action="callback", callback=pscsi_scan_lsscsi, -+# default=False, help="Scan and register pSCSI HBAs with TCM/ConfigFS") -+#parser.parse_args() -+# -diff --git a/targetcli/tcm_ramdisk.py b/targetcli/tcm_ramdisk.py -new file mode 100644 -index 0000000..10b4a5f ---- /dev/null -+++ b/targetcli/tcm_ramdisk.py -@@ -0,0 +1,53 @@ -+import os -+import subprocess as sub -+import string, re -+from optparse import OptionParser -+ -+tcm_root = "/sys/kernel/config/target/core" -+ -+def createvirtdev(path, params): -+ -+# print "Calling ramdisk createvirtdev: path " + path -+ cfs_path = tcm_root + "/" + path + "/" -+# print "Calling ramdisk createvirtdev: params " + str(params) -+ rd_pages = params[0] -+ -+ rd_params = "rd_pages=" + rd_pages -+# print "rd_params: " + rd_params -+ -+ control_opt = "echo -n " + rd_params.rstrip() + " > " + cfs_path + "/control" -+# print "control_opt: " + control_opt -+ ret = os.system(control_opt) -+ if ret: -+ print "RAMDISK: createvirtdev failed for control_opt with " + rd_params -+ return -1 -+ -+ enable_opt = "echo 1 > " + cfs_path + "enable" -+# print "Calling enable_opt " + enable_opt -+ ret = os.system(enable_opt) -+ if ret: -+ print "RAMDISK: createvirtdev failed for enable_opt with " + rd_params -+ return -1 -+ -+def rd_freevirtdev(): -+ pass -+ -+def rd_get_params(path): -+ -+ info_file = path + "/info" -+ p = open(info_file, 'rU') -+ try: -+ value = p.read(1024) -+ except IOError, msg: -+ p.close() -+ return -+ p.close() -+ -+ off = value.index('PAGE_SIZE: ') -+ off += 11 # Skip over "PAGE_SIZE: " -+ rd_pages_tmp = value[off:] -+ rd_pages = rd_pages_tmp.split('*') -+ params = "rd_pages=" + rd_pages[0] -+ -+ # rd_pages= parameter for tcm_node --createdev -+ return rd_pages[0] --- -1.7.1 - diff --git a/0003-Hack.-dump-scripts-aren-t-in-PATH-anymore-so-call-th.patch b/0003-Hack.-dump-scripts-aren-t-in-PATH-anymore-so-call-th.patch deleted file mode 100644 index 39dc87e..0000000 --- a/0003-Hack.-dump-scripts-aren-t-in-PATH-anymore-so-call-th.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 7b4dce12237dc9b79dbe4f2ac9dbbb125d314b2c Mon Sep 17 00:00:00 2001 -From: Andy Grover -Date: Sat, 30 Jul 2011 18:31:45 -0700 -Subject: [PATCH 3/6] Hack. dump scripts aren't in PATH anymore, so call them explicitly. - -Signed-off-by: Andy Grover ---- - targetcli/lio_dump.py | 3 ++- - targetcli/tcm_dump.py | 22 +++++++++++++--------- - targetcli/tcm_fabric.py | 4 ++-- - 3 files changed, 17 insertions(+), 12 deletions(-) - -diff --git a/targetcli/lio_dump.py b/targetcli/lio_dump.py -index 81c5104..6ce217a 100644 ---- a/targetcli/lio_dump.py -+++ b/targetcli/lio_dump.py -@@ -221,7 +221,8 @@ def lio_backup_to_file(option, opt_str, value, parser): - print "Unable to open backup_dir" - sys.exit(1) - -- op = "lio_dump --stdout" -+ prefix = "python /usr/lib/python2.6/site-packages/rtsadmin/" -+ op = prefix + "lio_dump.py --stdout" - p = sub.Popen(op, shell=True, stdout=sub.PIPE).stdout - if not p: - print "Unable to dump LIO-Target/ConfigFS running state" -diff --git a/targetcli/tcm_dump.py b/targetcli/tcm_dump.py -index bf80632..1b76b62 100644 ---- a/targetcli/tcm_dump.py -+++ b/targetcli/tcm_dump.py -@@ -20,6 +20,10 @@ tcm_root = "/sys/kernel/config/target/core" - def tcm_dump_hba_devices(): - pass - -+path_prefix = "python /usr/lib/python2.6/site-packages/rtsadmin/" -+tcm_node_path = path_prefix + "tcm_node.py" -+tcm_dump_path = path_prefix + "tcm_dump.py" -+ - def tcm_dump_configfs(option, opt_str, value, parser): - - if not os.path.isdir(tcm_root): -@@ -68,35 +72,35 @@ def tcm_dump_configfs(option, opt_str, value, parser): - params = tcm_pscsi.pscsi_get_params(dev) - if not params: - continue -- print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ print tcm_node_path + " --establishdev " + f + "/" + g + " " + str(params) - result = re.search('iblock_', f) - if result: - dev = dev_root + g - params = tcm_iblock.iblock_get_params(dev) - if not params: - continue -- print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ print tcm_node_path + " --establishdev " + f + "/" + g + " " + str(params) - result = re.search('rd_dr_', f) - if result: - dev = dev_root + g - params = tcm_ramdisk.rd_get_params(dev) - if not params: - continue -- print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ print tcm_node_path + " --establishdev " + f + "/" + g + " " + str(params) - result = re.search('rd_mcp_', f) - if result: - dev = dev_root + g - params = tcm_ramdisk.rd_get_params(dev) - if not params: - continue -- print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ print tcm_node_path + " --establishdev " + f + "/" + g + " " + str(params) - result = re.search('fileio_', f) - if result: - dev = dev_root + g - params = tcm_fileio.fd_get_params(dev) - if not params: - continue -- print "tcm_node --establishdev " + f + "/" + g + " " + str(params) -+ print tcm_node_path + " --establishdev " + f + "/" + g + " " + str(params) - - # Dump T10 VP Unit Serial for all non Target_Core_Mod/pSCSI objects - result = re.search('pscsi_', f) -@@ -108,7 +112,7 @@ def tcm_dump_configfs(option, opt_str, value, parser): - off += 8 # Skip over "Number: " - unit_serial = value[off:] - # Note that this will handle read, parse and set any PR APTPL metadata -- print "tcm_node --setunitserialwithmd " + f + "/" + g + " " + unit_serial.rstrip() -+ print tcm_node_path + " --setunitserialwithmd " + f + "/" + g + " " + unit_serial.rstrip() - os.close(p) - - # Dump device object alias -@@ -146,7 +150,7 @@ def tcm_dump_configfs(option, opt_str, value, parser): - os.close(p) - if not value: - continue -- print "tcm_node --addaluatpgwithmd " + f + "/" + g + " " + tg_pt_gp + " " + value.rstrip() -+ print tcm_node_path + " --addaluatpgwithmd " + f + "/" + g + " " + tg_pt_gp + " " + value.rstrip() - # Dump the ALUA types - tg_pt_gp_type_file = dev_root + g + "/alua/" + tg_pt_gp + "/alua_access_type" - p = os.open(tg_pt_gp_type_file, 0) -@@ -244,7 +248,7 @@ def tcm_dump_configfs(option, opt_str, value, parser): - print "echo " + attr_val + " > " + attrib_file - - if snap_enabled == 1: -- print "tcm_node --lvsnapstart " + f + "/" + g -+ print tcm_node_path + " --lvsnapstart " + f + "/" + g - - def tcm_backup_to_file(option, opt_str, value, parser): - datetime = str(value) -@@ -261,7 +265,7 @@ def tcm_backup_to_file(option, opt_str, value, parser): - print "Unable to open backup_dir" - sys.exit(1) - -- op = "tcm_dump --stdout" -+ op = tcm_dump_path + " --stdout" - p = sub.Popen(op, shell=True, stdout=sub.PIPE).stdout - if not p: - print "Unable to dump Target_Core_Mod/ConfigFS running state" -diff --git a/targetcli/tcm_fabric.py b/targetcli/tcm_fabric.py -index 8a843d4..03f5570 100644 ---- a/targetcli/tcm_fabric.py -+++ b/targetcli/tcm_fabric.py -@@ -254,8 +254,8 @@ def fabric_backup_to_file(date_time, fabric_name, fabric_root, module_name): - if ret: - print "Unable to open backup_dir" - sys.exit(1) -- -- op = "tcm_fabric --stdout --fabric-name=" + fabric_name + " --fabric-root=" + fabric_root + " --module-name=" + module_name -+ prefix = "python /usr/lib/python2.6/site-packages/rtsadmin/" -+ op = prefix + "tcm_fabric.py --stdout --fabric-name=" + fabric_name + " --fabric-root=" + fabric_root + " --module-name=" + module_name - # print "Using op: " + op - p = sub.Popen(op, shell=True, stdout=sub.PIPE).stdout - if not p: --- -1.7.1 - diff --git a/0004-ignore-errors-from-failure-to-set-device-attributes.patch b/0004-ignore-errors-from-failure-to-set-device-attributes.patch deleted file mode 100644 index 5a409ee..0000000 --- a/0004-ignore-errors-from-failure-to-set-device-attributes.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 8f6fb804f7bf68bafa4799fb821882bd97e777c8 Mon Sep 17 00:00:00 2001 -From: Andy Grover -Date: Mon, 1 Aug 2011 14:40:12 -0700 -Subject: [PATCH 4/6] ignore errors from failure to set device attributes - -Signed-off-by: Andy Grover ---- - targetcli/tcm_dump.py | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/targetcli/tcm_dump.py b/targetcli/tcm_dump.py -index 1b76b62..abfd592 100644 ---- a/targetcli/tcm_dump.py -+++ b/targetcli/tcm_dump.py -@@ -211,7 +211,7 @@ def tcm_dump_configfs(option, opt_str, value, parser): - attrib_file = dev_attrib_root + h - p = os.open(attrib_file, 0) - value = os.read(p, 8) -- print "echo " + value.rstrip() + " > " + attrib_file -+ print "echo " + value.rstrip() + " > " + attrib_file + " 2>/dev/null" - os.close(p) - - # Dump snapshot attributes --- -1.7.1 - diff --git a/0005-fix-spec_root-path.patch b/0005-fix-spec_root-path.patch deleted file mode 100644 index 0ae75fa..0000000 --- a/0005-fix-spec_root-path.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 8f91eb2b471f8db02888e80d37f90b1c6c42605a Mon Sep 17 00:00:00 2001 -From: Andy Grover -Date: Thu, 25 Aug 2011 14:41:29 -0700 -Subject: [PATCH 5/6] fix spec_root path - -We moved the specs from /var/target/fabric to /var/lib/target/fabric, so -this needs to be updated so saveconfig will work. - -Signed-off-by: Andy Grover ---- - targetcli/tcm_fabric.py | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/targetcli/tcm_fabric.py b/targetcli/tcm_fabric.py -index 03f5570..2c4c6dc 100644 ---- a/targetcli/tcm_fabric.py -+++ b/targetcli/tcm_fabric.py -@@ -6,7 +6,7 @@ import datetime, time - import optparse - - target_root = "/sys/kernel/config/target/" --spec_root = "/var/target/fabric/" -+spec_root = "/var/lib/target/fabric/" - - def fabric_configfs_dump(fabric_name, fabric_root, module_name): - --- -1.7.1 - diff --git a/0006-add-docs.patch b/0006-add-docs.patch deleted file mode 100644 index ae89cbc..0000000 --- a/0006-add-docs.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 163c6d070b1b5f53327bf760b54b75c18d5c19cc Mon Sep 17 00:00:00 2001 -From: Andy Grover -Date: Mon, 21 Nov 2011 14:54:41 -0800 -Subject: [PATCH 6/8] add docs - -add a man page. - -Signed-off-by: Andy Grover ---- - targetcli.8 | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 151 insertions(+), 0 deletions(-) - create mode 100644 targetcli.8 - -diff --git a/targetcli.8 b/targetcli.8 -new file mode 100644 -index 0000000..54e26f4 ---- /dev/null -+++ b/targetcli.8 -@@ -0,0 +1,151 @@ -+.TH targetcli 8 -+.SH NAME -+.B targetcli -+.SH DESCRIPTION -+.B targetcli -+is a shell for viewing, editing, and saving the configuration of -+the kernel's target subsystem, also known as TCM/LIO. It enables the -+administrator to assign local storage resources backed by either files, -+volumes, or local SCSI devices, and export them to remote systems via -+network fabrics, such as iSCSI, FCoE, or others. -+.P -+The configuration layout is tree-based, similar to a filesystem, and -+navigated in a similar manner. -+.SH USAGE -+Invoke -+.B targetcli -+as root to enter the configuration shell. Use -+.B ls -+to list nodes below the current path. Configuration changes are made -+immediately. To retain changes on reboot, use -+.BR saveconfig . -+Moving -+around the tree is accomplished by the -+.B cd -+command, or by entering -+the new location directly. Use -+.B "help " -+for additional usage -+information. Tab-completion is enabled for commands and command -+arguments. -+.SH EXAMPLES -+To export a storage resource, 1) define a storage object using -+backstore, then 2) export the object via a network fabric, such as -+iSCSI or FCoE. -+.SS DEFINING A STORAGE OBJECT WITH BACKSTORE -+.B backstores/fileio0 create disk1 /disks/disk1.img 140M -+.br -+Creates a storage object named -+.I disk1 -+with the given path and size. -+.B targetcli -+supports common size abbreviations like 'M', 'G', and 'T'. -+.P -+In addition to the -+.I fileio -+backstore for file-backed volumes, other backstore types include -+.I iblock -+for block-device-backed volumes, and -+.I pscsi -+for volumes backed by local SCSI devices. See the built-in help -+for more details on required parameters. -+.SS EXPORTING A STORAGE OBJECT VIA FCOE -+.B tcm_fc/ create 20:00:00:19:99:a8:34:bc -+.br -+Create an FCoE target with the given WWN. -+.B targetcli -+can tab-complete the WWN based on registered FCoE interfaces. If none -+are found, verify that they are properly configured and are shown in -+the output of -+.BR "fcoeadm -i" . -+.P -+.B tcm_fc/20:00:00:19:99:a8:34:bc/ -+.br -+If -+.B auto_cd_after_create -+is set to false, change to the configuration node for the given -+target, equivalent to giving the command prefixed by -+.BR cd . -+.P -+.B luns/ create /backstores/fileio/disk1 -+.br -+Create a new LUN for the interface, attached to a previously defined -+storage object. The storage object now shows up under the /backstores -+configuration node as -+.BR activated . -+.P -+.B acls/ create 00:99:88:77:66:55:44:33 -+.br -+Create an ACL (access control list), for defining the resources each -+initiator may access. The default behavior is to auto-map existing -+LUNs to the ACL; see help for more information. -+.P -+The LUN should now be accessible via FCoE. -+.SS EXPORTING A STORAGE OBJECT VIA ISCSI -+.B iscsi/ create -+.br -+Creates an iSCSI target with a default WWN. It will also create an -+initial target portal group called -+.IR tpgt1 . -+.P -+.B iqn.2003-01.org.linux-iscsi.test2.x8664:sn123456789012/tpgt1/ -+.br -+An example of changing to the configuration node for the given -+target's first target portal group (TPG). This is equivalent to giving -+the command prefixed by "cd". (Although more can be useful for certain -+setups, most configurations have a single TPG per target. In this -+case, configuring the TPG is equivalent to configuring the overall -+target.) -+.P -+.B portals/ create -+.br -+Add a portal, i.e. an address and TCP port via which the target can be -+contacted by initiators. Sane defaults are used if these are not -+specified. -+.P -+.B luns/ create /backstores/fileio0/disk1 -+.br -+Create a new LUN in the TPG, attached to the storage object that has -+previously been defined. The storage object now shows up under the -+/backstores configuration node as activated. -+.P -+.B acls/ create iqn.1994-05.com.redhat:4321576890 -+.br -+Creates an ACL (access control list) for the given iSCSI initiator. -+.P -+.B acls/iqn.1994-05.com.redhat:4321576890 create 2 0 -+.br -+Gives the initiator access to the first exported LUN (lun0), which the -+initiator will see as lun2. The default is to give the initiator -+read/write access; if read-only access was desired, an additional "1" -+argument would be added to enable write-protect. -+.SS OTHER COMMANDS -+.B saveconfig -+.br -+Save the current configuration settings to a file, from which -+settings will be restored if the system is rebooted. -+.P -+This command must be executed from the configuration root node. -+.P -+.B exit -+.br -+Leave the configuration shell. -+.SS SETTINGS -+.B set attribute authentication=0 -+.br -+Disable CHAP authentication. -+.P -+.B set global auto_cd_after_create=false -+.br -+Do not change into the configuration node of a newly created -+object. The default is 'true'. -+.SH FILES -+.B /etc/target/* -+.br -+.B /var/lib/target/* -+.SH AUTHOR -+Written by Jerome Martin . -+.br -+Man page written by Andy Grover . -+.SH REPORTING BUGS -+Report bugs to --- -1.7.1 - diff --git a/0007-all-start.patch b/0007-all-start.patch deleted file mode 100644 index 477572a..0000000 --- a/0007-all-start.patch +++ /dev/null @@ -1,35 +0,0 @@ -commit 1af9a2ce6f1ebb15a43439c7c438b59d69568fd5 -Author: Andy Grover -Date: Wed Nov 2 14:46:39 2011 -0700 - - append all start scripts into /etc/target/all_start.sh - - This should make systemd packaging a little easier. - - Signed-off-by: Andy Grover - -diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py -index 2048544..b3f78c4 100644 ---- a/targetcli/ui_root.py -+++ b/targetcli/ui_root.py -@@ -89,6 +89,20 @@ class UIRoot(UINode): - else: - self.shell.log.warning("Aborted, configuration left untouched.") - -+ # append all into single script -+ from glob import iglob -+ import os -+ import shutil -+ sources = iglob(os.path.join("/etc/target", '*_start.sh')) -+ # ensure tcm_start is appended first -+ sources = [x for x in sources if not 'tcm_' in x] -+ sources = [x for x in sources if not 'all_' in x] -+ sources.insert(0, '/etc/target/tcm_start.sh') -+ dest = open('/etc/target/all_start.sh', 'wb') -+ for filename in sources: -+ shutil.copyfileobj(open(filename, 'rb'), dest) -+ dest.close() -+ - def ui_command_version(self): - ''' - Displays the targetcli and support libraries versions. diff --git a/sources b/sources index 049663c..56d1fc2 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -d90375b632ffb27700fa006b0e39e3f6 targetcli-1.99.2.gitb03ec79.tar.gz +a000250bd42fbafaa641b9cd0e7c1663 v2.0rc1.fb2 diff --git a/targetcli-git-version.patch b/targetcli-git-version.patch deleted file mode 100644 index 66ed45d..0000000 --- a/targetcli-git-version.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/rtsadmin/__init__.py b/rtsadmin/__init__.py -index 90150a8..c8a8f07 100644 ---- a/targetcli/__init__.py -+++ b/targetcli/__init__.py -@@ -17,7 +17,7 @@ along with this program. If not, see . - - from ui_root import UIRoot - --__version__ = 'GIT_VERSION' -+__version__ = 'b03ec79' - __author__ = "Jerome Martin " - __url__ = "http://www.risingtidesystems.com" - __description__ = "An administration shell for RTS storage targets." diff --git a/targetcli.spec b/targetcli.spec index 58c747b..a34b8f7 100644 --- a/targetcli.spec +++ b/targetcli.spec @@ -1,30 +1,19 @@ +%global oname targetcli-fb + Name: targetcli License: AGPLv3 Group: System Environment/Libraries Summary: An administration shell for storage targets -Version: 1.99.2.gitb03ec79 -Release: 4%{?dist} -# placeholder URL and source entries -# archive created using: -# git clone git://risingtidesystems.com/targetcli.git -# cd targetcli -# git archive b03ec79 --prefix targetcli-%{version}/ | gzip > targetcli-%{version}.tar.gz -URL: http://www.risingtidesystems.com/git/ -Source: %{name}-%{version}.tar.gz +Version: 2.0rc1.fb2 +Release: 1%{?dist} +URL: https://github.com/agrover/targetcli-fb +Source: https://github.com/agrover/%{oname}/tarball/v%{version} Source1: targetcli.service -Patch1: targetcli-git-version.patch -Patch2: 0001-Remove-ads-from-cli-welcome-msg.-Mention-help-is-ava.patch -Patch3: 0002-bundle-lio-utils.patch -Patch4: 0003-Hack.-dump-scripts-aren-t-in-PATH-anymore-so-call-th.patch -Patch5: 0004-ignore-errors-from-failure-to-set-device-attributes.patch -Patch6: 0005-fix-spec_root-path.patch -Patch7: 0006-add-docs.patch -Patch8: 0007-all-start.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildArch: noarch BuildRequires: python-devel python-rtslib python-configshell epydoc BuildRequires: systemd-units -Requires: python-rtslib python-configshell +Requires: python-rtslib >= 2.1.fb1, python-configshell Requires(post): systemd-units @@ -35,15 +24,7 @@ users will also need to install and use fcoe-utils. %prep -%setup -q -n %{name}-%{version} -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 +%setup -q -n agrover-%{oname}-091a9a2 %build %{__python} setup.py build @@ -77,6 +58,18 @@ fi %{_mandir}/man8/targetcli.8.gz %changelog +* Tue Dec 6 2011 Andy Grover - 2.0rc1.fb2-1 +- New upstream source and release +- Remove patches: + * targetcli-git-version.patch + * 0001-Remove-ads-from-cli-welcome-msg.-Mention-help-is-ava.patch + * 0002-bundle-lio-utils.patch + * 0003-Hack.-dump-scripts-aren-t-in-PATH-anymore-so-call-th.patch + * 0004-ignore-errors-from-failure-to-set-device-attributes.patch + * 0005-fix-spec_root-path.patch + * 0006-add-docs.patch + * 0007-all-start.patch + * Mon Nov 21 2011 Andy Grover - 1.99.2.gitb03ec79-4 - Update doc patch to include iscsi tutorial