home *** CD-ROM | disk | FTP | other *** search
- /**
- * File: modules/AutoInstallRules.ycp
- * Package: Auto-installation
- * Summary: Process Auto-Installation Rules
- * Author: Anas Nashif <nashif@suse.de>
- *
- * $Id: AutoInstallRules.ycp 29265 2006-03-22 14:48:47Z ug $
- */
- {
-
- module "AutoInstallRules";
- textdomain "autoinst";
-
-
- import "Arch";
- import "Stage";
- import "Installation";
- import "AutoinstConfig";
- import "XML";
- import "Storage";
- import "Kernel";
- import "Mode";
- import "Profile";
- import "Label";
- import "Report";
- import "Popup";
- import "URL";
- import "IP";
- import "Product";
-
- include "autoinstall/io.ycp";
-
- global boolean userrules = false;
- global boolean dontmergeIsDefault = true;
- global list<string> dontmergeBackup = [];
-
- global symbol Behaviour = `many;
-
- /////////////////////////////////////////////
- // Pre-defined Rules
- /////////////////////////////////////////////
-
- // All system attributes;
- map ATTR = $[];
-
- global string installed_product = "";
-
- global string installed_product_version = "";
-
- global string hostname = "";
-
- global string hostaddress = "";
-
- global string network = "";
-
- global string domain = "";
-
- global string arch = "";
-
- global string karch = "";
-
- // Taken from smbios
- global string product = "";
-
- // Taken from smbios
- global string product_vendor = "";
-
- // Taken from smbios
- global string board_vendor = "";
-
- // Taken from smbios
- global string board = "";
-
- global integer memsize = 0;
-
- global list<map<string, any> > disksize = [];
-
- global integer totaldisk = 0;
-
- global string hostid = "";
-
- global string mac = "";
-
- global integer linux = 0;
-
- global integer others = 0;
-
- global string xserver = "";
-
- global string haspcmcia = "0";
-
- /////////////////////////////////////////////
- /////////////////////////////////////////////
-
- global list NonLinuxPartitions = [];
-
- global list LinuxPartitions = [];
-
-
- global map<string, any> UserRules = $[];
-
- // Local Variables
- string shell = "";
- map env = $[];
-
- global list<string> tomerge = [];
-
-
-
- /**
- * Cleanup XML file from namespaces put by xslt
- */
- global define boolean XML_cleanup(string in, string out) ``{
- map ycpin = XML::XMLToYCPFile(in);
- y2debug("Writing clean XML file to %1, YCP is (%2)", out, ycpin);
- return XML::YCPToXMLFile(`profile, ycpin, out);
- }
-
-
- /**
- * StdErrLog()
- * Dialog for error messages
- */
- global define void StdErrLog( string stderr) ``{
- UI::OpenDialog(
- `opt( `decorated ),
- `VBox(
- `VSpacing(0.5),
- `HSpacing(50),
- `HBox (
- `HSpacing(0.5),
- `LogView(`id(`log), Label::ErrorMsg() , 10, 100 ),
- `HSpacing(0.5)
- ),
- `VSpacing(0.2),
- `PushButton( `id(`ok), `opt(`default), Label::OKButton() ),
- `VSpacing(0.5)
- )
- );
-
- UI::ChangeWidget(`id(`log),`Value, stderr);
- UI::UserInput();
- UI::CloseDialog();
-
- };
- /**
- * getMAC()
- * Return MAC address of active device
- * @return string mac address
- */
- global define string getMAC()
- {
- string tmpmac = "";
- if (Stage::initial ())
- {
- tmpmac = (string)SCR::Read (.etc.install_inf.HWAddr);
- }
- string cleanmac = deletechars((tmpmac!=nil)?tmpmac:"", ":");
- return cleanmac;
- }
-
-
- /**
- * Return host id (hex ip )
- * @return string host ID
- */
- global define string getHostid ()
- {
- string hex = IP::ToHex(hostaddress);
- return hex;
- }
-
-
- /**
- * Probe all system data to build a set of rules
- * @return void
- */
- global define void ProbeRules ()
- {
-
- // SMBIOS Data
- list bios = (list) SCR::Read(.probe.bios);
-
- if (size(bios) != 1)
- {
- y2warning("Warning: BIOS list size is %1", size(bios));
- }
-
- map biosinfo = (map)(bios[0]:$[]);
- list<map> smbios = (list<map>)(biosinfo["smbios"]:[]);
-
- map sysinfo = $[];
- map boardinfo = $[];
-
- foreach(map inf, smbios, ``{
- if (inf["type"]:"" == "sysinfo")
- {
- sysinfo = inf;
- }
- else if (inf["type"]:"" == "boardinfo")
- {
- boardinfo = inf;
- }
- });
-
- if (size(sysinfo) > 0)
- {
- product = (string)(sysinfo["product"]:"default");
- product_vendor = (string)(sysinfo["manufacturer"]:"default");
- }
-
- if (size(boardinfo) > 0)
- {
- board = (string)(boardinfo["product"]:"default");
- board_vendor = (string)(boardinfo["manufacturer"]:"default");
- }
-
- ATTR["product"] = product;
- ATTR["product_vendor"] = product_vendor;
- ATTR["board"] = board;
- ATTR["board_vendor"] = board_vendor;
-
- //
- // Architecture
- //
-
- arch = Arch::architecture ();
- karch = Kernel::GetPackages ()[0]:"kernel-default";
-
- ATTR["arch"] = arch;
- ATTR["karch"] = karch;
-
- //
- // Memory
- //
-
- integer memory = 0;
- list memories = (list)SCR::Read(.probe.memory);
- memory = memories[0,"resource","phys_mem",0,"range"]:0;
- memsize = memory / ( 1024 * 1024);
- ATTR["memsize"] = memsize;
-
- //
- // Disk sizes
- //
-
- map<string,map> storage = Storage::GetTargetMap();
- map<string,map> PhysicalTargetMap = filter(string k, map v, storage ,
- ``(Storage::IsRealDisk(v) ));
- totaldisk = 0;
- disksize = maplist( string k, map v, PhysicalTargetMap,
- ``{
- integer size_in_mb = v["size_k"]:0 / 1024;
- totaldisk = totaldisk + size_in_mb;
- return($["device":k, "size": size_in_mb]);
- });
- y2debug("disksize: %1", disksize);
- //
- // MAC
- //
- mac = getMAC();
- ATTR["mac"] = mac;
-
- //
- // Network
- //
- if (Stage::initial ())
- {
- hostaddress = (string)SCR::Read(.etc.install_inf.IP);
- }
- else
- {
- hostaddress = "192.168.1.1"; // FIXME
- }
- ATTR["hostaddress"] = hostaddress;
-
- //
- // Hostid (i.e. a8c00101);
- //
- hostid = getHostid();
-
- ATTR["hostid"] = hostid;
-
-
- hostname = (string)SCR::Read(.etc.install_inf.Hostname);
- ATTR["hostname"] = hostname;
- domain = (string)SCR::Read(.etc.install_inf.Domain);
- ATTR["domain"] = domain;
- network = (string)SCR::Read(.etc.install_inf.Network);
- ATTR["network"] = network;
- haspcmcia = (string)SCR::Read(.etc.install_inf.HasPCMCIA);
- ATTR["haspcmcia"] = haspcmcia;
- xserver = (string)SCR::Read(.etc.install_inf.XServer);
- ATTR["xserver"] = xserver;
-
- NonLinuxPartitions = Storage::GetForeignPrimary();
- others = size(NonLinuxPartitions );
-
- y2milestone ("Other primaries: %1", NonLinuxPartitions);
-
- LinuxPartitions = Storage::GetOtherLinuxPartitions();
- linux = size(LinuxPartitions);
-
- y2milestone ("Other linux parts: %1", LinuxPartitions);
-
- installed_product = Product::name;
- installed_product_version = Product::version;
- ATTR["installed_product"] = installed_product;
- ATTR["installed_product_version"] = installed_product_version;
-
- y2milestone("Installing %1 %2", installed_product, installed_product_version);
-
- return;
- }
-
-
-
-
- /**
- * Create shell command for rule verification
- * @param match
- * @param var
- * @param val
- * @param op
- * @param matchtype
- * @return void
- */
- define void shellseg (boolean match, string var, any val, string op, string matchtype)
- {
- if (op == "and")
- op = " && ";
- else if (op == "or")
- op = " || ";
-
- string tmpshell = " ( [";
- y2debug("Match type: %1", matchtype);
- if (is( val, string) && (string)val == "*")
- {
- // match anything
- tmpshell = tmpshell + " \"1\" = \"1\" ";
- }
- else if (matchtype == "exact")
- {
- tmpshell = tmpshell + sformat(" \"$%1\" = \"%2\" ", var, val);
- }
- else if (matchtype == "greater")
- {
- tmpshell = tmpshell + sformat(" \"$%1\" -gt \"%2\" ", var, val);
- }
- else if (matchtype == "lower")
- {
- tmpshell = tmpshell + sformat(" \"$%1\" -lt \"%2\" ", var, val);
- }
- else if (matchtype == "range")
- {
- list<string> range =splitstring(tostring(val), "-");
- y2debug("Range: %1", range);
- tmpshell = tmpshell + sformat(" \"$%1\" -gt \"%2\" -a \"$%1\" -lt \"%3\" ", var, range[0]:"0", range[1]:"0");
- }
- else if( matchtype == "regex" )
- {
- tmpshell = tmpshell + sformat("[ \"$%1\" =~ \"%2\" ]", var, val);
- }
-
- if (match)
- {
- shell = shell + sformat(" %1 %2] )", op, tmpshell);
- }
- else
- {
- shell = tmpshell + "] ) ";
- }
-
- y2debug("var: %1, val: %2", var, val);
- y2debug("shell: %1", shell);
- return;
- }
-
-
- /**
- * Verify rules using the shell
- * @return integer
- */
- define integer verifyrules ()
- {
-
- string script = sformat("if %1; then exit 0; else exit 1; fi", shell);
- map ret = (map)SCR::Execute (.target.bash_output, script, env);
-
- y2milestone("Bash return: %1 (%2) (%3)", script, ret, env);
-
- return ret["exit"]:-1;
- }
-
- string SubVars(string file)
- {
- y2milestone("file: %1" , file);
- string var = "";
- any first = findfirstof(file, "@");
- any last = findlastof(file, "@");
- if (first!= nil && last!=nil)
- {
- integer ffirst = (integer) first + 1;
- integer llast = (integer) last;
- if (first!=last)
- {
- var = substring(file,ffirst , llast - ffirst );
- }
- }
- y2milestone("var: %1", var);
- if (var!="")
- {
- string val = ATTR[var]:"";
- string new = regexpsub(file,"(.*)@.*@(.*)",sformat("\\1%1\\2", val));
- if (new!="")
- return new;
- }
- y2milestone("val: %1", file);
- return file;
-
- }
- /**
- * Read rules file
- * @return void
- */
- global define void Read()
- {
- UserRules = XML::XMLToYCPFile( AutoinstConfig::local_rules_file );
-
- if( UserRules == nil ) {
- string message = _("Parsing the rules file failed. XML parser reports:\n");
- Popup::Error( message + XML::XMLError() );
- }
- y2milestone("Rules: %1", UserRules);
-
- list<map <string, map> > rulelist = UserRules["rules"]:[];
- if (rulelist == nil) // check result of implicit type conversion
- {
- y2error ("Key 'rules' has wrong type");
- rulelist = [];
- }
-
- boolean ismatch = false;
- boolean go_on = true;
- foreach ( map<string, map> ruleset, rulelist, ``{
- y2debug("Ruleset: %1", ruleset);
- if (go_on) {
- foreach(string rule, map ruledef, ruleset, ``{
- y2debug("Rule: %1", rule);
- y2debug("Ruledef: %1", ruledef);
-
- string match = ruledef["match"]:"undefined";
-
- string op = ruledef["operator"]:"and";
- string matchtype = ruledef["match_type"]:"exact";
-
- list<string> easy_rules = [
- "hostname",
- "hostaddress",
- "installed_product_version",
- "installed_product",
- "domain",
- "network",
- "mac",
- "karch",
- "hostid",
- "arch",
- "board",
- "board_vendor",
- "product_vendor",
- "product" ];
- if ( contains(easy_rules, rule))
- {
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- env[rule] = ATTR[rule]:"";
- }
- else if ( rule == "custom1" || rule == "custom2" || rule == "custom3" || rule == "custom4" || rule == "custom5")
- {
- string script = ruledef["script"]:"exit -1";
- string tmpdir = AutoinstConfig::tmpDir;
-
- string scriptPath = sformat("%1/%2", tmpdir, "rule_" + rule);
-
- y2milestone("Writing rule script into %1", scriptPath);
- SCR::Write(.target.string, scriptPath, script);
-
- map out = (map) SCR::Execute (.target.bash_output, "/bin/sh " + scriptPath, $[]);
- string script_result = out["stdout"]:"";
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- ATTR[rule] = script_result;
- env[rule] = script_result;
- }
- else if ( rule == "linux" )
- {
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- env[rule] = linux;
- }
- else if ( rule == "others" )
- {
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- env[rule] = others;
- }
- else if ( rule == "xserver" )
- {
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- env[rule] = xserver;
- }
- else if ( rule == "memsize" )
- {
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- env[rule] = memsize;
- }
- else if ( rule == "totaldisk" )
- {
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- env[rule] = totaldisk;
- }
- else if ( rule == "haspcmcia" )
- {
- shellseg(ismatch, rule, match, op, matchtype);
- ismatch = true;
- env[rule] = haspcmcia;
- }
- else if ( rule == "disksize" )
- {
- y2debug("creating rule check for disksize");
- list<string> disk = splitstring(match, " ");
- integer i = 0;
- string t = "";
- if (shell != "" )
- {
- t = shell + sformat(" %1 ( ", (op == "and") ? "&&" : "||" );
- }
- else
- {
- t = shell + sformat(" ( ");
- }
- foreach(map<string, any> dev, disksize, {
- string var1 = sformat("disksize_size%1", i );
- string var2 = sformat("disksize_device%1", i );
-
- if (matchtype == "exact") {
- t = t + sformat(" [ \"$%1\" = \"%2\" -a \"$%3\" = \"%4\" ] ", var1, disk[1]:"" , var2, disk[0]:"");
- } else if (matchtype == "greater") {
- t = t + sformat(" [ \"$%1\" -gt \"%2\" -a \"$%3\" = \"%4\" ] ", var1, disk[1]:"" , var2, disk[0]:"");
- } else if (matchtype == "lower") {
- t = t + sformat(" [ \"$%1\" -lt \"%2\" -a \"$%3\" = \"%4\" ] ", var1, disk[1]:"" , var2, disk[0]:"");
- }
-
- env[var1] = dev["size"]:-1;
- env[var2] = dev["device"]:"";
- i = i + 1;
- if ( size(disksize) > i )
- {
- t = t + " || ";
- }
- });
- t = t + " ) ";
- shell = t;
- y2debug("shell: %1", shell);
- ismatch = true;
- }
- else if ( rule == "result" )
- {
- if ( verifyrules() == 0 )
- {
- string profile_name = ruledef["profile"]:"";
- profile_name = SubVars(profile_name);
- y2milestone("Final Profile name: %1", profile_name
- );
- if (ruledef["match_with_base"]:true)
- {
- tomerge = add(tomerge, profile_name);
- }
- // backdoor for merging problems.
- if( haskey(ruledef, "dont_merge") ) {
- if( dontmergeIsDefault ) {
- dontmergeBackup = AutoinstConfig::dontmerge;
- AutoinstConfig::dontmerge = [];
- }
- AutoinstConfig::dontmerge = (list<string>)union( AutoinstConfig::dontmerge, ruledef["dont_merge"]:[] );
- dontmergeIsDefault = false;
- y2milestone("user defined dont_merge for rules found. dontmerge is %1", AutoinstConfig::dontmerge);
- }
- go_on = ruledef["continue"]:false;
- }
- else
- {
- go_on = true;
- }
- shell = "";
- ismatch = false;
- }
-
- });
- }
- });
- return;
- }
-
-
-
- /**
- * Return list of file to merge (Order matters)
- * @return list list of files
- */
- global define list<string> Files ()
- {
- return tomerge;
- }
-
- /**
- * Return list of file to merge (Order matters)
- * @return boolean
- */
- global define boolean GetRules ()
- {
- y2milestone("Getting Rules: %1", tomerge);
-
- string scheme = AutoinstConfig::scheme;
- string host = AutoinstConfig::host;
- string filepath = AutoinstConfig::filepath;
- string directory = AutoinstConfig::directory;
-
- list<string> valid = [];
- boolean stop = false;
- foreach(string file, tomerge, ``{
- if (!stop) {
- string dir = dirname ( file );
- if (dir != "") {
- SCR::Execute(.target.mkdir, AutoinstConfig::local_rules_location + "/" + dir);
- }
-
- string localfile = AutoinstConfig::local_rules_location + "/" + file ;
- if (!Get( scheme, host, directory + "/" + file, localfile)) {
- y2error("Error while fetching file: %1", directory + "/" + file);
- } else {
- if (Behaviour == `one) {
- stop = true;
- }
- valid = add(valid, file);
- }
- }
- });
- tomerge = valid;
- if (size ( tomerge ) == 0 ) {
- y2milestone("No files from rules found");
- return (false);
- } else {
- return (true);
- }
- }
-
-
- /**
- * Merge Rule results
- * @param result_profile the resulting control file path
- * @return boolean true on success
- */
- global define boolean Merge ( string result_profile )
- {
-
- string tmpdir = AutoinstConfig::tmpDir;
- boolean ok = true;
- boolean skip = false;
- boolean error = false;
-
- string base_profile = tmpdir + "/base_profile.xml";
-
- foreach(string file, tomerge,
- ``{
- y2milestone("Working on file: %1", file);
-
- string current_profile = AutoinstConfig::local_rules_location + "/" + file;
- if (!skip)
- {
- if (!XML_cleanup(current_profile, tmpdir + "/base_profile.xml"))
- {
- y2error("Error reading XML file");
- string message = _("The XML parser reported an error while parsing the autoyast profile. The error message is:\n");
- message = message + XML::XMLError();
- Popup::Error ( message );
- error = true;
- }
- skip = true;
- }
- else if (!error )
- {
- string MergeCommand = "/usr/bin/xsltproc --novalid --param replace \"'false'\" ";
- string dontmerge_str = "";
- integer i = 1;
- foreach (string dm, AutoinstConfig::dontmerge, ``{
- dontmerge_str = dontmerge_str + sformat(" --param dontmerge%1 \"'%2'\" ", i, dm);
- i = i + 1;
- });
- MergeCommand = MergeCommand + dontmerge_str;
-
- MergeCommand = MergeCommand + "--param with ";
- MergeCommand = MergeCommand + "\"'" + current_profile + "'\" ";
- MergeCommand = MergeCommand + "--output " + tmpdir + "/result.xml";
- MergeCommand = MergeCommand + " /usr/share/autoinstall/xslt/merge.xslt ";
- MergeCommand = MergeCommand + base_profile + " ";
-
- map xsltret = (map)SCR::Execute(.target.bash_output, MergeCommand);
- y2milestone("Merge result: %1", xsltret);
- if (xsltret["exit"]:-1 != 0 || xsltret["stderr"]:"" != "")
- {
- y2error("Merge Failed");
- StdErrLog(xsltret["stderr"]:"");
- ok = false;
- }
-
- XML_cleanup(tmpdir + "/result.xml", tmpdir + "/base_profile.xml");
-
- }
- else
- {
- y2error ("Error while merging control files");
- }
- });
-
- if (error )
- {
- return !error;
- }
-
- SCR::Execute(.target.bash, "cp " + tmpdir + "/base_profile.xml " + result_profile );
-
- y2milestone("Ok=%1", ok);
- dontmergeIsDefault = true;
- AutoinstConfig::dontmerge = dontmergeBackup;
- return ok;
- }
-
-
- /**
- * Process Rules
- * @param string result_profile
- * @return boolean
- */
- global define boolean Process( string result_profile )
- {
-
- boolean ok = true;
- string tmpdir = AutoinstConfig::tmpDir;
- string prefinal = AutoinstConfig::local_rules_location + "/prefinal_autoinst.xml" ;
- if (!Merge ( prefinal ) )
- {
- return false;
- }
-
- tomerge = [];
-
-
- // Now check if there any classes defined in theis pre final control file
- if (! Profile::ReadXML( prefinal ))
- {
- Popup::Error(_("Error while parsing the control file.
- Check the log files for more details or fix the
- control file and try again.
- "));
- return false;
- }
- y2milestone("Checking classes...");
- if ( haskey(Profile::current, "classes") )
- {
- y2milestone("User defined classes available, processing....");
- list<map> classes = Profile::current["classes"]:[];
- foreach(map class, classes,
- ``{
- // backdoor for merging problems.
- if( haskey(class, "dont_merge") ) {
- if( dontmergeIsDefault )
- AutoinstConfig::dontmerge = [];
- AutoinstConfig::dontmerge = (list<string>)union( AutoinstConfig::dontmerge, class["dont_merge"]:[] );
- dontmergeIsDefault = false;
- y2milestone("user defined dont_merge for class found. dontmerge is %1", AutoinstConfig::dontmerge);
- }
-
- tomerge = add(tomerge, "classes/" + class["class_name"]:"none" + "/" + class["configuration"]:"none");
- });
-
- y2milestone("New files to process: %1", tomerge);
- Behaviour = `multiple;
- boolean ret = GetRules();
- if (ret)
- {
- tomerge = prepend(tomerge, "prefinal_autoinst.xml");
- ok = Merge ( result_profile );
- }
- else
- {
- Report::Error(_("
- User-defined classes could not be retrieved. Make sure all classes
- are defined correctly and available for this system via the network
- or locally. The system cannot be installed with the original control
- file without using classes.
- "));
-
- ok = false;
- SCR::Execute(.target.bash, "cp " + prefinal + " " + result_profile );
- }
- }
- else
- {
- SCR::Execute(.target.bash, "cp " + prefinal + " " + result_profile );
- }
- y2milestone("returns=%1", ok );
- return ok;
-
- }
-
-
- /**
- * Create default rule in case no rules file is available
- * This adds a list of file starting from full hex ip representation to
- * only the first letter. Then default and finally mac address.
- * @return void
- */
- global define void CreateDefault()
- {
- Behaviour = `one;
- string tmp_hex_ip = hostid;
- tomerge = add(tomerge, tmp_hex_ip );
- while (size(tmp_hex_ip) != 1)
- {
- tmp_hex_ip = substring(tmp_hex_ip, 0 , size ( tmp_hex_ip ) - 1 );
- tomerge = add(tomerge, tmp_hex_ip );
- }
- tomerge = add(tomerge, toupper(mac) );
- tomerge = add(tomerge, tolower(mac) );
- tomerge = add(tomerge, "default" );
- y2milestone("Created default rules=%1", tomerge);
- return;
- }
-
- /**
- * Create default rule in case no rules file is available (Only one file which is given by the user)
- * @param filename file name
- * @return void
- */
- global define void CreateFile(string filename)
- {
- tomerge = add (tomerge, filename);
- y2milestone("Created default rules: %1", tomerge);
- return;
- }
- /**
- * Constructor
- *
- */
- global define void AutoInstallRules () ``{
- return;
- }
-
-
- /**
- * Initialize
- */
- global define void Init () ``{
-
- if (Stage::initial () || Mode::test ())
- {
- ProbeRules();
- }
-
- return;
- }
-
-
- }
-