ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/IscsiClientLib.ycp

{
module "IscsiClientLib";
textdomain "iscsi-client";

import "Service";
import "Popup";
import "Hostname";
import "Stage";
import "ModuleLoading";
import "Mode";
import "String";
import "Arch";

global list <string> sessions = [];
global list <string> discovered = [];
global list <string> targets = [];
global list<string> currentRecord = [];

// status of rcopen-iscsi service
boolean serviceStatus = false;
// main configuration file (/etc/iscsi/iscsid.conf)
map<string, any> config = $[];
// iBFT (iSCSI Boot Firmware Table)
map<string, any> ibft = nil;
// InitiatorName file (/etc/iscsi/initiatorname.iscsi)
global string initiatorname = "";
// map used for autoYaST
global map ay_settings=nil;



global map<string, any> hidePassword(map<string, any> orig){
 map<string, any> hidden=$[];
 foreach(string key, any value, orig, {
  if (issubstring(key, "PASS")) value="*****";
  hidden[key]=value;
 });
 return hidden;
}


/**
 * get iBFT (available only on some special hardware)
 */
global map<string, any> getiBFT(){
 if (ibft==nil){
  if (!Arch::i386() && !Arch::x86_64()){
	y2milestone("Because architecture %1 is is different from x86, not using iBFT", Arch::arch_short());
	 return $[];
 }
  ibft=$[];
  y2milestone("check and modprobe iscsi_ibft : %1", SCR::Execute(.target.bash_output, "lsmod |grep -q iscsi_ibft || modprobe iscsi_ibft"));
  string from_bios = ((map<string, any>)SCR::Execute(.target.bash_output, "iscsiadm -m fw"))["stdout"]:"";
  foreach(string row, splitstring(from_bios, "\n"), {
   list<string> key_val=splitstring(row, "=");
//   if (size(key_val[0]:"")>0) ibft[key_val[0]:""] = key_val[1]:"";
   string kv = String::CutBlanks(key_val[0]:"");
   if (size(kv) > 0) ibft[kv] = String::CutBlanks(key_val[1]:"");
  });
 }
 y2milestone("iBFT %1", hidePassword(ibft));
 return ibft;
}


// get accessor for service status
global boolean GetStartService() {
 boolean status = Service::Enabled("open-iscsi");
 y2milestone("Status of open-iscsi %1", status);
 return status;
}

// set accessor for service status
global void SetStartService(boolean status) {
 y2milestone("Set status of open-iscsi to %1", status);
 if (status == true) {
    Service::Enable("boot.open-iscsi");
    Service::Enable("open-iscsi");
 } else {
    Service::Disable("boot.open-iscsi");
    Service::Disable("open-iscsi");
 }
}


// read configuration file
global list <map<string, any> > getConfig(){
 // use cache if available
 if (size(config)==0){
  config = (map<string, any>) SCR::Read(.etc.iscsid.all);
  y2debug("read config %1", config);
 }
 return config["value"]:[];
}

global void setConfig(list new_config){
 config["value"]=new_config;
}

// do we use iSNS for targets?
global boolean useISNS(){
 boolean use = false;
 foreach(map<string, any> row, getConfig(), {
  if (row["name"]:""=="isns.address" || row["name"]:""=="isns.port") {
	 use = true;
	}
 });
 return use;
}


// write temporary changed old config
global void oldConfig(){
 y2milestone("Store temporary config %1", config);
 SCR::Write(.etc.iscsid.all, config);
 SCR::Write(.etc.iscsid, nil);
}


global map<string, any> getNode(){
  map<string, any> cmd = (map<string, any>)SCR::Execute(.target.bash_output, "iscsiadm -S -m node -T $TARGET -p $IP", $["TARGET":currentRecord[1]:"", "IP":currentRecord[0]:""]);
 if (cmd["exit"]:0!=0) return $[];
 map<string, any> auth = $[];
 foreach(string row, splitstring(cmd["stdout"]:"", "\n"), {
 string key = splitstring(row," = ")[0]:"";
 string val = splitstring(row," = ")[3]:"";
 if(val == "<empty>") val="";
  switch(key){
   case("node.session.auth.authmethod"):
		auth["authmethod"]=val;
		break;
   case("node.session.auth.username"):
		auth["username"]=val;
		break;
   case("node.session.auth.password"):
		auth["password"]=val;
		break;
   case("node.session.auth.username_in"):
		auth["username_in"]=val;
		break;
   case("node.session.auth.password_in"):
		auth["password_in"]=val;
		break;
  }
 });
 return auth;
}

// create map from given map in format needed by ini-agent
map<string, any> createMap(map<string, any> old_map, list<string> comments)
{
 string comment = "";
 foreach(string row, comments, {
  comment = sformat("%1%2", comment, row);
  });
 return $[ "name":old_map["KEY"]:"",
           "value":old_map["VALUE"]:"",
           "kind":"value",
           "type":1,
           "comment":comment
         ];
}

// add or modify given map
list <map<string, any> > setOrAdd(list <map<string, any> > old_list, string key, string value){
 list <map<string, any> > new_list = [];
 boolean found = false;
 foreach(map<string, any> row, old_list, {
  if (row["name"]:"" == key){
   found = true;
   row["value"] = value;
  }
  new_list = add(new_list, row);
 });
 if (!found) new_list = add(new_list, createMap($["KEY":key, "VALUE":value], []) );
 return new_list;
}

// delete record with given key
list <map<string, any> > delete(list <map<string, any> > old_list, string key){
 y2milestone("Delete record for %1", key);
 list <map<string, any> > new_list = [];
 foreach(map<string, any> row, old_list, {
  if (row["name"]:"" != key) new_list = add(new_list, row);
 });
 return new_list;
}

// temporary change config for discovery authentication
global void saveConfig(string user_in, string pass_in, string user_out, string pass_out){
 y2milestone("Save config");
 map<string, any> tmp_conf = config;
 list <map<string, any> > tmp_val = tmp_conf["value"]:[];

 if ((size(user_in)>0)&&(size(pass_in)>0)) {
	tmp_val = setOrAdd(tmp_val, "node.session.auth.username", user_in);
	tmp_val = setOrAdd(tmp_val, "node.session.auth.password", pass_in);
	}
  else {
	tmp_val = delete(tmp_val, "node.session.auth.username");
	tmp_val = delete(tmp_val, "node.session.auth.password");
	}

 if ((size(user_out)>0)&&(size(pass_out)>0)) {
	tmp_val = setOrAdd(tmp_val, "discovery.sendtargets.auth.authmethod", "CHAP");
	tmp_val = setOrAdd(tmp_val, "discovery.sendtargets.auth.username", user_out);
	tmp_val = setOrAdd(tmp_val, "discovery.sendtargets.auth.password", pass_out);
	}
  else {
	tmp_val = delete(tmp_val, "discovery.sendtargets.auth.authmethod");
	tmp_val = delete(tmp_val, "discovery.sendtargets.auth.username");
	tmp_val = delete(tmp_val, "discovery.sendtargets.auth.password");
	}
 tmp_conf["value"] = tmp_val;
 SCR::Write(.etc.iscsid.all, tmp_conf);
 SCR::Write(.etc.iscsid, nil);
}

// get all discovered targets
global list<string> getDiscovered(){
	 discovered=[];
    map<string, any> retcode = (map<string, any>)SCR::Execute(.target.bash_output, "iscsiadm -m node");
	if (size(retcode["stderr"]:"")==0) {
	      list<string> tmp_disc = filter(string row, splitstring(retcode["stdout"]:"", "\n"), {
                        return ( size(row)>0 && (search(row, "session")==nil) );
                        });
	foreach(string row, tmp_disc, {
	 list<string> tmp_row = splitstring(row, " ");
	 discovered = add(discovered, sformat("%1 %2", tmp_row[0]:"", tmp_row[1]:""));
	});
	}
 y2milestone("Discovered sessions %1", discovered);
 return discovered;
}


global void startIScsid(){
 SCR::Execute(.target.bash, "pgrep iscsid || iscsid");
 foreach(integer i,[0,1,2,3,4,5,6,7,8,9],{
  sleep(1*1000);
  map<string, any> cmd=(map<string, any>)SCR::Execute(.target.bash_output, "iscsiadm -m session");
  y2internal("iteration %1, retcode %2",i, cmd["exit"]:-1);
  if (cmd["exit"]:-1==0){
	y2internal("Good response from daemon, exit.");
	 break;
  }
 });
}

// get all connected targets
global boolean readSessions(){
 y2milestone("reading current settings");
    map<string, any> retcode = (map<string, any>)SCR::Execute(.target.bash_output, "iscsiadm -m session");
//	if ( retcode["exit"]:0 != 0 ) return false;
      list<string> tmp_sessions = [];
      tmp_sessions = filter(string row, splitstring(retcode["stdout"]:"", "\n"), {
                        return ( size(row)>0 && (search(row, "session")==nil) );
                        });
	sessions=[];
	foreach(string row, tmp_sessions, {
	list<string> tmp_row = splitstring(row, " ");
	sessions = add(sessions, sformat("%1 %2", tmp_row[2]:"", tmp_row[3]:""));
	});

  y2milestone("Return list from iscsiadm -m session: %1", sessions);
 return true;
}

/**
 * write InitiatorName, create backup from previous if needed
 */
global boolean writeInitiatorName(string new_value){
 boolean ret=true;
 string file="/etc/iscsi/initiatorname.iscsi";
 if ( ((map<string, any>)SCR::Read (.target.lstat, file))["size"]:0>0 )
 {
   y2milestone("%1 file exists, create backup", file);
   SCR::Execute(.target.bash, sformat("mv %1 /etc/iscsi/initiatorname.yastbackup", file));
 }
 ret = (boolean)SCR::Write (.target.string, file, sformat("InitiatorName=%1\n", new_value));
 SCR::Execute (.target.bash, "chmod 0600 $FILE" ,$["FILE":file]);
 if (ret){
  initiatorname = new_value;
  y2milestone("Initiatorname %1 written", initiatorname);
 }
 // reload service when initiatorname is changed to re-read new value (bnc#482429)
 Service::Reload("open-iscsi");
 return ret;
}

string getReverseDomainName(){
 list<string> host_fq = Hostname::SplitFQ(((map<string,any>)SCR::Execute(.target.bash_output, "hostname -f|tr -d '\n'"))["stdout"]:"");
 y2internal("hostfw%1", host_fq);
 string domain = "";

 foreach(string item, splitstring(host_fq[1]:"example.com", "."),{
  y2internal("item %1", item);
  domain = (size(domain)==0) ? item : sformat("%1.%2", item, domain);
 });

 y2milestone("domain %1", domain);
 return domain;
}

// check initiatorname if exist, if no - create it
global boolean checkInitiatorName(){
 boolean ret=true;
 string file="/etc/iscsi/initiatorname.iscsi";
 string name_from_bios = getiBFT()["iface.initiatorname"]:"";
// if (size((map<string, any>)SCR::Read (.target.lstat, file)) == 0 || ((map<string, any>)SCR::Read (.target.lstat, file))["size"]:0==0){
    initiatorname=((map<string, any>)SCR::Execute(.target.bash_output,
			sformat("grep -v '^#' %1 | grep InitiatorName | cut -d'=' -f2 | tr -d '\n'", file)))["stdout"]:"";
// }
  if(size(initiatorname)==0){
   if (size(name_from_bios)>0){
    y2milestone("%1 is empty or doesnt exists - replace with name stored in iBFT", file);
    initiatorname = name_from_bios;
   } else {
	y2milestone("InitiatorName does not exist - generate it");
	 string domain = ((map<string,any>)SCR::Execute(.target.bash_output, ""))["stdout"]:"com.example";
	 map<string, any> output = (map<string, any>)SCR::Execute (.target.bash_output,
		sformat("/sbin/iscsi-iname -p iqn.%1.%2:01 | tr -d '\n'","`date +%Y-%m`", getReverseDomainName()), $[]);
	 if (size(output["stderr"]:"")==0){
	  initiatorname=output["stdout"]:"";
	} else ret = false;
    }
  ret = writeInitiatorName(initiatorname);
 } else {
    y2internal("initiatorname=%1", initiatorname);
   if (size(name_from_bios)>0 && name_from_bios!=initiatorname)
   {
    Popup::Warning( _("InitiatorName from iBFT and from <tt>/etc/iscsi/initiatorname.iscsi</tt> differ.
The old initiatorname will be replaced by the value of iBFT and create a backup.
If you want to use a different initiatorname, change it in the BIOS.") );
    y2milestone("replacing old name %1 by name %2 from iBFT", initiatorname, name_from_bios);
    initiatorname = name_from_bios;
    ret = writeInitiatorName(initiatorname);
   }
  }
 return ret;
}


// delete deiscovered target from database
global boolean deleteRecord(){
 boolean ret = true;
 y2milestone("Delete record %1", currentRecord);

    map<string, any> retcode = (map<string, any>)SCR::Execute(.target.bash_output, sformat("iscsiadm -m node -T %1 -p %2 --logout", currentRecord[1]:"", currentRecord[0]:""));
        if (size(retcode["stderr"]:"")>0) return false;

 readSessions();
 return ret;
}

// get (manual/onboot) status of target connecting
global string getStartupStatus(){
 string status = "";
 y2milestone("Getting status of record %1", currentRecord);
     map<string, any> retcode = (map<string, any>)SCR::Execute(.target.bash_output, sformat("iscsiadm -m node -T %1 -p %2", currentRecord[1]:"", currentRecord[0]:""));
    if (size(retcode["stderr"]:"")>0) return "";
    foreach(string row, splitstring(retcode["stdout"]:"", "\n"), {
     if (issubstring(row, "node.conn[0].startup")){
	status = (splitstring(row, " "))[2]:"";
       break;
      }
    });
 y2milestone("Startup status for %1 is %2", currentRecord, status);
 return status;
}

// update authentication value
global boolean setValue(string name, string value){
 y2milestone("set %1  for record %2", name, currentRecord);
 string command = sformat("iscsiadm -m node -T %1 -p %2 --op=update --name=%3 --value=%4", currentRecord[1]:"", currentRecord[0]:"", name, value);
 y2milestone("execute command - %1", command );
 boolean ret = true;
        map<string, any> retcode = (map<string, any>) SCR::Execute(.target.bash_output, command);
    if (size(retcode["stderr"]:"")>0) {
				y2error("%1", retcode["stderr"]:"");
				ret =  false;
				}
y2milestone("return value %1", ret);
 return ret;
}


// check if given target is connected
global boolean connected(boolean check_ip){
y2internal("check connected status for %1 with IP check:%2", currentRecord, check_ip);
 boolean ret = false;
 foreach(string row, sessions, {
 list<string> list_row = splitstring(row, " ");
  if (list_row[1]:"" == currentRecord[1]:"" && (check_ip ? splitstring(list_row[0]:"", ",")[0]:"" == splitstring(currentRecord[0]:"", ",")[0]:"" : true)){
   ret = true;
   break;
  }
 });
 return ret;
}

// change startup status (manual/onboot) for target
global boolean setStartupStatus(string status){
 y2milestone("Set startup status for %1 to %2", currentRecord, status);
 boolean ret = true;
 map<string, any> retcode = (map<string, any>) SCR::Execute(.target.bash_output,
	sformat("iscsiadm -m node -T %1 -p %2 --op=update --name=node.conn[0].startup --value=%3", currentRecord[1]:"", currentRecord[0]:"", status));
    if (size(retcode["stderr"]:"")>0) return false;
	else retcode = (map<string, any>) SCR::Execute(.target.bash_output,
        sformat("iscsiadm -m node -T %1 -p %2 --op=update --name=node.startup --value=%3", currentRecord[1]:"", currentRecord[0]:"", status));

y2internal("retcode %1", retcode);
 return ret;
}

global boolean autoLogOn(){
y2milestone("begin of autoLogOn function");
 if (size(getiBFT())>0){
  y2milestone("Autologin into iBFT : %1", SCR::Execute(.target.bash_output, "iscsiadm -m fw -l"));
 }
 return true;
}


global boolean loginIntoTarget(map target){
 currentRecord = [target["portal"]:"", target["target"]:""];
 if (target["authmethod"]:"None"!="None"){
  string user_in = target["username_in"]:"";
  string pass_in = target["password_in"]:"";
  if (size(user_in)>0 && size(pass_in)>0){
   setValue("node.session.auth.username_in", user_in);
   setValue("node.session.auth.password_in", pass_in);
  } else{
           setValue("node.session.auth.username_in", "");
           setValue("node.session.auth.password_in", "");
   }
  string user_out = target["username"]:"";
  string pass_out = target["password"]:"";
  if (size(user_out)>0 && size(pass_out)>0){
   setValue("node.session.auth.username", user_out);
   setValue("node.session.auth.password", pass_out);
   setValue("node.session.auth.authmethod", "CHAP");
  } else {
           setValue("node.session.auth.username", "");
           setValue("node.session.auth.password", "");
           setValue("node.session.auth.authmethod", "");
    }
 } else setValue("node.session.auth.authmethod", "None");

  map<string, any> output = (map<string, any>)SCR::Execute(.target.bash_output,
		sformat("iscsiadm -m node -T %1 -p %2 --login", target["target"]:"", target["portal"]:""));
 y2internal("output %1", output);
// if (output["exit"]:-1==0){
  // set startup status to auto by default (bnc#400610)
  if (!Mode::autoinst()) setStartupStatus("onboot");
  return true;
/*
 } else {
	y2error("Error while Log-on into target : %1", output);
	return false;
	}
*/
}


// get status of open-iscsi
global boolean getServiceStatus(){
 boolean ret = true;
 if (Stage::initial()){
  ModuleLoading::Load("iscsi_tcp", "", "", "", false, true);
  // start daemon before
  startIScsid();

 } else {
  if (Service::Status("open-iscsi") == 0) serviceStatus=true;
  y2milestone("Service status = %1", serviceStatus);
  // if not enabled, start it manually
  if (!serviceStatus) Service::Start("open-iscsi");
 }
 return ret;
}

// set startup status of open-iscsi
global boolean setServiceStatus(){
 boolean ret = true;
// if disabled and no connected targets - stop it
// otherwise keep it running
 if (!GetStartService()){
	 readSessions();
	 if (size(sessions)==0) {
		 y2milestone("No active sessions - stopping service");
		 Service::Stop("open-iscsi");
		}
	}
 y2milestone("Status service for open-iscsi: %1", ret);
 return ret;
}


global boolean autoyastPrepare(){
 initiatorname = ay_settings["initiatorname"]:"";
 if (size(initiatorname)>0){
  string file="/etc/iscsi/initiatorname.iscsi";
  SCR::Write (.target.string, file, sformat("InitiatorName=%1\n", initiatorname));
  SCR::Execute (.target.bash, "chmod 0600 $FILE" ,$["FILE":file]);
 } else checkInitiatorName();
 // start daemon before
 startIScsid();
}

global boolean autoyastWrite(){
// do discovery first
list<string> portals = [];
foreach(map target, ay_settings["targets"]:[], {
 if (!contains(portals, target["portal"]:"")){
  SCR::Execute(.target.bash, sformat("iscsiadm -m discovery -t st -p %1", target["portal"]:""));
  portals = add(portals, target["portal"]:"");
 }
});
 foreach(map target, ay_settings["targets"]:[], {
y2internal("login into target %1", target);
  loginIntoTarget(target);
  currentRecord = [target["portal"]:"", target["target"]:""];
  setStartupStatus(target["startup"]:"manual");
 });
 return true;
}


}

ACC SHELL 2018