home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / modules / AutoinstClone.ycp < prev    next >
Text File  |  2006-11-29  |  18KB  |  555 lines

  1. /**
  2.  * File:
  3.  *   modules/AutoinstClone.ycp
  4.  *
  5.  * Package:
  6.  *   Autoinstallation Configuration System
  7.  *
  8.  * Summary:
  9.  *   Create a control file from an exisiting machine
  10.  *
  11.  * Authors:
  12.  *   Anas Nashif <nashif@suse.de>
  13.  *
  14.  * $Id: AutoinstClone.ycp 33482 2006-10-18 08:50:05Z ug $
  15.  *
  16.  *
  17.  */
  18. {
  19.     module "AutoinstClone";
  20.     import "Mode";
  21.  
  22.     import "XML";
  23.     import "Call";
  24.     import "Profile";
  25.     import "Y2ModuleConfig";
  26.     import "Misc";
  27.     import "Storage";
  28.     import "AutoinstConfig";
  29.     import "StorageDevices";
  30.     import "Storage";
  31.     import "Partitions";
  32.     import "Report";
  33.  
  34.     include "autoinstall/xml.ycp";
  35.  
  36.     global map Profile = $[];
  37.  
  38.     integer bytes_per_unit = 0;
  39.  
  40.  
  41.     // spceial treatment for base resources
  42.     global list<string> base = [];
  43.  
  44.     // aditional configuration resources o be cloned
  45.     global list<string> additional = [];
  46.  
  47.  
  48.     /**
  49.      * Constructor
  50.      */
  51.     global define void AutoinstClone()
  52.     {
  53.         Mode::SetMode ("normal");
  54.         return;
  55.     }
  56.  
  57.     /**
  58.      * Set root password
  59.      */
  60.     define list root() ``{
  61.         list<map> shadow = (list<map>) SCR::Read(.etc.shadow);
  62.         map rootacct = (map) filter(map acct, shadow, ``(acct["username"]:"" == "root"))[0]:$[];
  63.         list users = [];
  64.         map rootacct_mod = $[];
  65.         rootacct_mod["user_password"] = rootacct["password"]:"";
  66.         rootacct_mod["encrypted"] = true;
  67.         rootacct_mod["username"] = "root";
  68.         users = add(users, rootacct_mod);
  69.         return users;
  70.     }
  71.  
  72.  
  73.     /**
  74.      * Find mount points in running system
  75.      * @param string device name
  76.      * @param map partition
  77.      * @param list mount points
  78.      * @return string
  79.      */
  80.     define string findMountpoint(string device, map p, list<map> mounts)
  81.     {
  82.         string mountPoint = "";
  83.         foreach(map mount , mounts, ``{
  84.             string m = sformat("%1%2", device ,  p["nr"]:nil);
  85.             if (mount["spec"]:"" ==  m )
  86.             {
  87.                 mountPoint = mount["file"]:"";
  88.             }
  89.         });
  90.         return mountPoint;
  91.     }
  92.  
  93.     /**
  94.      * Convert units to size
  95.      * @param list region
  96.      * @return integer size
  97.      */
  98.     define integer units_to_size (list region)
  99.     {
  100.         integer units = (integer) region[1]:0;
  101.         return (units * bytes_per_unit)  -  bytes_per_unit + 1;
  102.     };
  103.  
  104.  
  105.     /**
  106.      * Create a partition plan for the calling client
  107.      * @return list partition plan
  108.      */
  109.     global define list Partitioning()
  110.     {
  111.         Mode::SetMode("normal");
  112.         StorageDevices::InitDone();
  113.         map<string, map> StorageMap = eval(Storage::GetTargetMap());
  114.  
  115.         StorageMap=filter(string d, map p, StorageMap, ``( d != "/dev/evms" && size(p["partitions"]:[]) > 0));
  116.         y2milestone("Storagemap %1", StorageMap);
  117.         list evms_vgs = [];
  118.  
  119.         list drives = maplist(string k, map v, StorageMap, ``{
  120.             list partitions = [];
  121.             list winp = [];
  122.             list<integer> usepartitions = [];
  123.             foreach(map pe, v["partitions"]:[], ``{
  124.                 map new_pe = $[];
  125.                 boolean skipwin = false;
  126.                 if (haskey(pe,"enc_type")) {
  127.                     new_pe["enc_type"] = pe["enc_type"]:`twofish;
  128.                     new_pe["crypt_key"] = "ENTER KEY HERE";
  129.                     new_pe["loop_fs"] = true;
  130.                     new_pe["crypt_fs"] = true;
  131.                 }
  132.                 if (haskey(pe,"fsid"))
  133.                 {
  134.                     integer fsid = pe["fsid"]:131;
  135.                     list wintypes = union(Partitions::fsid_wintypes, Partitions::fsid_dostypes);
  136.                     list allwin = union(wintypes, Partitions::fsid_ntfstypes);
  137.                     if (contains(allwin, fsid) && ! issubstring(pe["mount"]:"", "/boot") )
  138.                     {
  139.                         y2debug("Windows partitions found: %1", fsid );
  140.                         winp = add(winp, pe["nr"]:0);
  141.                         skipwin = true;
  142.                     }
  143.                     if( contains(allwin, fsid) && issubstring(pe["mount"]:"", "/boot") ) {
  144.                         new_pe["partition_id"] = 259;
  145.                     } else {
  146.                         new_pe["partition_id"] = pe["fsid"]:131;
  147.                     }
  148.                     // PPC boot (/boot is just an indicator)
  149.                     if( pe["fsid"]:0 == 65 ) {
  150.                         //new_pe["mount"] = "/boot";
  151.                         new_pe["format"] = false;
  152.                     }
  153.                 }
  154.                 if( haskey(pe,"type") && pe["type"]:`x == `primary ) {
  155.                     new_pe["partition_type"] = "primary"; // can we always copy that element?
  156.                 }
  157.                 if (haskey(pe,"region"))
  158.                 {
  159.                     // don't clone the exact region.
  160.                     // I don't see any benefit in cloning that strict.
  161.                     //new_pe["region"] = pe["region"]:[];
  162.                     new_pe["size"] = sformat("%1", pe["size_k"]:0*1024);
  163.                 }
  164.                 if (haskey(pe,"label")) {
  165.                     new_pe["label"] = pe["label"]:"";
  166.                 }
  167.                 if (haskey(pe,"mountby")) {
  168.                     new_pe["mountby"] = pe["mountby"]:`nomb;
  169.                 }
  170.                 // LVM Group
  171.                 if (haskey(pe,"used_by_type") && pe["used_by_type"]:`nothing == `UB_LVM)
  172.                 {
  173.                     new_pe["lvm_group"] = pe["used_by"]:"";
  174.                 }
  175.  
  176.                 // EVMS Group
  177.                 if (haskey(pe,"used_by_type") && pe["used_by_type"]:`nothing == `UB_EVMS) {
  178.                     integer index = findlastof( pe["used_by"]:"", "/" );
  179.                     new_pe["evms_group"] = substring( pe["used_by"]:"", index+1);
  180.                 }
  181.  
  182.                 // LV
  183.                 if (pe["type"]:`unknown == `lvm || pe["type"]:`unknown == `evms )
  184.                 {
  185.                     new_pe["lv_name"] = pe["name"]:"";
  186.                     new_pe["size"] = sformat("%1", pe["size_k"]:0*1024);
  187.                 }
  188.                 if (haskey(pe,"used_by_type") && pe["used_by_type"]:`nothing == `UB_MD)
  189.                 {
  190.                     new_pe["raid_name"] = "/dev/"+pe["used_by"]:"";
  191.                 }
  192.  
  193.                 // Used Filesystem
  194.                 // Raid devices get the filesystem lying on them as
  195.                 // detected_fs!
  196.                 if (haskey(pe,"used_fs") && pe["fsid"]:0 != 253)
  197.                 {
  198.                     new_pe["filesystem"] = pe["used_fs"]:`reiser;
  199.                     new_pe["format"] = pe["format"]:true;
  200.                 }
  201.  
  202.                 if (haskey(pe,"nr") && pe["type"]:`unknown != `lvm)
  203.                 {
  204.                     if (!skipwin)
  205.                     {
  206.                         y2debug("Adding partition to be used: %1",  pe["nr"]:0);
  207.                         usepartitions = add(usepartitions, pe["nr"]:0);
  208.                     }
  209.                     new_pe["partition_nr"] = pe["nr"]:0;
  210.                 }
  211.                 if (pe["mount"]:"" != "")
  212.                 {
  213.                     new_pe["mount"] = pe["mount"]:"";
  214.                 }
  215.                 if (k == "/dev/md")
  216.                 {
  217.                     map raid_options = $[];
  218.                     raid_options["persistent_superblock"] =
  219.                             pe["persistent_superblock"]:false;
  220.                     raid_options["raid_type"] = pe["raid_type"]:"raid0";
  221.                     new_pe["raid_options"] = raid_options;
  222.                 }
  223.  
  224.                 if (!skipwin && new_pe["partition_id"]:0 != 15 ) {
  225.                     partitions=add(partitions,new_pe);
  226.                 }
  227.             });
  228.  
  229.  
  230.             map drive = $[];
  231.             drive["partitions"]    = partitions;
  232.             drive["device"]    = k;
  233.             if( v["type"]:`CT_UNKNOWN==`CT_LVM)
  234.             {
  235.                 drive["pesize"] = sformat("%1M", v["pesize"]:1 / (1024*1024) );
  236.                 drive["type"] = `CT_LVM;
  237.             } else if( v["type"]:`CT_UNKNOWN==`CT_EVMS ) {
  238.                 drive["pesize"] = sformat("%1M", v["pesize"]:1 / (1024*1024) );
  239.                 drive["type"] = `CT_EVMS;
  240.                 integer index = findlastof( drive["device"]:"", "/" );
  241.                 string vg_name = substring(drive["device"]:"", index);
  242.                 drive["device"] = "/dev"+vg_name;
  243.                 evms_vgs = add( evms_vgs, "/dev"+vg_name );
  244.             }
  245.             if (haskey(v,"lvm2") && v["lvm2"]:false)
  246.             {
  247.                 drive["lvm2"] = true;
  248.             }
  249.  
  250.             if (size(partitions) > 0 )
  251.             {
  252.                 if (size(winp) == 0 )
  253.                 {
  254.                     drive["use"]    = "all";
  255.                 }
  256.                 else
  257.                 {
  258.                     list<string> up = [];
  259.                     foreach(integer i, usepartitions, ``{
  260.                         up = add (up, sformat("%1", i));
  261.                     });
  262.                     drive["use"]    = mergestring(up, ",");
  263.                 }
  264.             }
  265.             return drive;
  266.         });
  267.         drives = filter( map v, (list<map>)drives, ``{
  268.             if( ! (contains( evms_vgs, v["device"]:"") && v["type"]:`x == `CT_LVM ) )
  269.                 return true;
  270.             y2milestone("kicking LVM %1 out of the profile because an EVMS with that name exists",v);
  271.             return false;
  272.         });
  273.         Mode::SetMode("autoinst_config");
  274.         return drives;
  275.     }
  276.  
  277.  
  278.     /**
  279.      * Return list of software packages of calling client
  280.      * @return map map of installed software package
  281.      *        "patterns" -> list<string> addon selections
  282.      *        "packages" -> list<string> user selected packages
  283.      *      "remove-packages" -> list<string> packages to remove
  284.      */
  285.     global define map<string, any > Software()
  286.     {
  287.         boolean ret = Pkg::TargetInit("/", false);
  288.  
  289.         list<string> inst = Pkg::GetPackages(`installed, true);
  290.         list<map<string,any> > all_patterns = Pkg::ResolvableProperties ("", `pattern, "");
  291.         list<map<string,any> > all_xpatterns = Pkg::ResolvableDependencies ("", `pattern, "");
  292.         list<string> patterns = [];
  293.  
  294.         foreach( map<string,any> m, all_patterns, ``{
  295.             if( m["status"]:`nothing == `installed )
  296.                 patterns = add( patterns, m["name"]:"" );
  297.         });
  298.  
  299.  
  300.         Pkg::TargetFinish ();
  301.  
  302.         string tmproot = AutoinstConfig::tmpDir;
  303.         SCR::Execute(.target.mkdir, tmproot + "/rootclone");
  304.         Pkg::TargetInit( tmproot + "/rootclone", true);
  305.         y2debug("SourceStartCache: %1", Pkg::SourceStartCache(false));
  306.  
  307.         Pkg::SourceStartManager(true);
  308.  
  309.  
  310.         /* FIXME: if this would work, it would be the better solution
  311.         foreach(string p, patterns, ``{
  312.             Pkg::ResolvableInstall( p, `pattern );
  313.         });
  314.         Pkg::PkgSolve(false);
  315.         */
  316.  
  317.         list<string> packages = Pkg::FilterPackages(false, false, true, true);
  318.         Pkg::TargetFinish ();
  319.         // Remove kernel packages
  320.         list<string> userpackages =  packages;
  321.         list<string> removepackages = [];
  322.  
  323.         list<string> patternPackages = [];
  324.         foreach( string tmp_pattern, patterns, ``{
  325.             list<map<string,any> > xpattern = filter( map<string,any> p, all_xpatterns, ``( p["name"]:"" == tmp_pattern ) );
  326.             map<string,any> found = xpattern[0]:$[];
  327.             foreach( map<string,any> d, found["dependencies"]:[], ``{
  328.                 if( d["res_kind"]:"" == "package" && d["dep_kind"]:"" == "requires" )
  329.                     patternPackages = add(patternPackages, d["name"]:"");
  330.             });
  331.         });
  332.         map<string, any > software = $[];
  333.         if( size(patterns) > 0 ) {
  334.             foreach(string p, inst, ``{
  335.                 if (!contains(patternPackages, p))
  336.                     userpackages = add( userpackages, p );
  337.             });
  338.             foreach(string p, patternPackages, ``{
  339.                 if (!contains(inst,p))
  340.                     removepackages = add( removepackages, p );
  341.             });
  342.         }
  343.  
  344.         software["packages"] = sort( filter(string pkg, userpackages, ``(! regexpmatch(pkg, "kernel-.*") || pkg == "kernel-uml")) );
  345.         software["patterns"] = sort( patterns );
  346.         software["remove-packages"] = sort( removepackages );
  347.         return software;
  348.     }
  349.  
  350.  
  351.     /**
  352.      * Bootloader options
  353.      * @return map bootloader options
  354.      */
  355.     global define map Bootloader()
  356.     {
  357.         map bootloader = $[];
  358.  
  359.         boolean readret = (boolean)Call::Function("bootloader_auto", ["Read", $[] ]);
  360.         if (readret)
  361.         {
  362.             bootloader = (map)Call::Function("bootloader_auto", ["Export", $[] ]);
  363.         }
  364.  
  365.         return bootloader;
  366.  
  367.     };
  368.  
  369.  
  370.     /**
  371.      * General options
  372.      * @return map general options
  373.      */
  374.     global define map General()
  375.     {
  376.         import "Language";
  377.         import "Mode";
  378.         Mode::SetMode ("normal");
  379.         import "Keyboard";
  380.         import "Timezone";
  381.  
  382.         map general = $[];
  383.         general["language"] = Language::language;
  384.  
  385.         map keyboard = $[];
  386.         y2debug("Current Keyboard: %1", Keyboard::default_kbd);
  387.         keyboard["keymap"]  = Keyboard::current_kbd;
  388.  
  389.         general["keyboard"] = keyboard;
  390.         map clock = $[];
  391.         clock["timezone"]   = Misc::SysconfigRead(.sysconfig.clock.TIMEZONE, Timezone::timezone );
  392.         string hwclock = "";
  393.         if ( size( Storage::GetWinPrimPartitions( Storage::GetTargetMap() ) ) > 0 )
  394.         {
  395.             // Win partitions present ==> assume local time.
  396.             hwclock = "--localtime";
  397.             y2debug("Assuming local time");
  398.         }
  399.         else
  400.         {
  401.             // No Win partitions ==> assume UTC.
  402.             hwclock = "-u";
  403.             y2debug("Assuming UTC");
  404.         }
  405.         string hwc   = Misc::SysconfigRead(.sysconfig.clock.HWCLOCK, hwclock);
  406.         if (hwc == "--localtime")
  407.         {
  408.             clock["hwclock"] = "localtime";
  409.         }
  410.         else if (hwc == "-u")
  411.         {
  412.             clock["hwclock"] = "UTC";
  413.         }
  414.         else
  415.         {
  416.             clock["hwclock"] = "";
  417.         }
  418.         general["clock"]    = clock;
  419.  
  420.         map mouse = $[];
  421.         mouse["id"]        = Misc::SysconfigRead(.sysconfig.mouse.YAST_MOUSE, "probe" );
  422.         general["mouse"]    = mouse;
  423.         map mode = $[];
  424.         mode["confirm"] = false;
  425.         general["mode"] = mode;
  426.  
  427.         Mode::SetMode ("autoinst_config");
  428.         return general;
  429.     }
  430.  
  431.  
  432.  
  433.  
  434.  
  435.      /**
  436.       * Clone a Resource
  437.       * @param string resource
  438.       * @param map resource name
  439.       * @return list
  440.       */
  441.      define boolean CommonClone(string resource, map resourceMap)
  442.      {
  443.  
  444.          string data_type = resourceMap["X-SuSE-YaST-AutoInstDataType"]:"map";
  445.          string auto = resourceMap["X-SuSE-YaST-AutoInstClient"]:"";
  446.          resource = resourceMap["X-SuSE-YaST-AutoInstResource"]:resource;
  447.  
  448.          Call::Function(auto , ["Read"]);
  449.          Call::Function(auto , ["SetModified"]);
  450.  
  451.          return true;
  452.  
  453.      }
  454.  
  455.  
  456.  
  457.      /**
  458.       * Create a list of clonable resources
  459.       * @return list list to be used in widgets
  460.       */
  461.      global define list createClonableList()
  462.     {
  463.          list items = [];
  464.          foreach(string def_resource, map resourceMap, Y2ModuleConfig::ModuleMap, ``{
  465.              y2debug("r: %1 => %2", def_resource, resourceMap["X-SuSE-YaST-AutoInstClonable"]:"false" );
  466.              boolean clonable = ( resourceMap["X-SuSE-YaST-AutoInstClonable"]:"false" == "true" );
  467.              if (clonable)
  468.              {
  469.                  // Set resource name, if not using default value
  470.                  string resource = resourceMap["X-SuSE-YaST-AutoInstResource"]:"";
  471.                  if (resource == "")
  472.                     resource = def_resource;
  473.                  string name = resourceMap["Name"]:"";
  474.                  if (resource != "")
  475.                  {
  476.                      items = add(items, `item(`id(resource), name ) );
  477.                  }
  478.                  else
  479.                  {
  480.                      items = add(items, `item(`id(def_resource), name ) );
  481.                  }
  482.              }
  483.          });
  484.          return items;
  485.      }
  486.  
  487.     /**
  488.      * Build the profile
  489.      * @return void
  490.      */
  491.     global define void Process()
  492.     {
  493.         y2debug("Additional resources: %1 %2", base, additional);
  494.         Profile::Reset();
  495.         Profile::prepare = true;
  496.         foreach(string def_resource, map resourceMap, Y2ModuleConfig::ModuleMap, ``{
  497.  
  498.             // Set resource name, if not using default value
  499.             string resource = resourceMap["X-SuSE-YaST-AutoInstResource"]:"";
  500.             if (resource == "")
  501.                 resource = def_resource;
  502.             y2debug("current resource: %1", resource);
  503.             if (contains(additional, resource))
  504.             {
  505.                 boolean ret = CommonClone(def_resource, resourceMap);
  506.             }
  507.  
  508.         });
  509.  
  510.         Call::Function("storage_auto" , ["Import", Partitioning()]);
  511.         Call::Function("storage_auto" , ["SetModified"]);
  512.  
  513.         Call::Function("software_auto" , ["Import", Software()]);
  514.         Call::Function("software_auto" , ["SetModified"]);
  515.  
  516.         Call::Function("bootloader_auto" , ["Import", Bootloader()]);
  517.         Call::Function("bootloader_auto" , ["SetModified"]);
  518.  
  519.         Call::Function("general_auto" , ["Import", General()]);
  520.         Call::Function("general_auto" , ["SetModified"]);
  521.  
  522.         Call::Function("report_auto" , ["Import", Report::Export()]);
  523.         Call::Function("report_auto" , ["SetModified"]);
  524.  
  525.         Profile::Prepare();
  526.         return;
  527.     }
  528.  
  529.     /**
  530.      * Write the profile to a defined path
  531.      * @param string outputFile Output file path
  532.      * @return boolean true on success
  533.      */
  534.     global define boolean Write(string outputFile)
  535.     {
  536.         Process();
  537.         boolean ret =  Profile::Save( outputFile );
  538.         return ret;
  539.     }
  540.  
  541.  
  542.     /**
  543.      * Export profile, Used only from within autoyast2
  544.      * @return void
  545.      */
  546.     global define void Export()
  547.         ``{
  548.  
  549.         import "Profile";
  550.         Profile::Reset();
  551.         Process();
  552.         return;
  553.     }
  554. }
  555.