2009-12-15 20:38:34 +00:00
package xCAT_plugin::statelite ;
BEGIN
{
$ ::XCATROOT = $ ENV { 'XCATROOT' } ? $ ENV { 'XCATROOT' } : '/opt/xcat' ;
}
use lib "$::XCATROOT/lib/perl" ;
use xCAT::Table ;
use Getopt::Long ;
use File::Basename ;
use File::Path ;
use File::Copy ;
use File::Find ;
use Cwd ;
use File::Temp ;
use xCAT::Utils qw( genpassword ) ;
2012-08-09 04:07:40 +00:00
use xCAT::TableUtils qw( get_site_attribute ) ;
2009-12-15 20:38:34 +00:00
use xCAT::SvrUtils ;
use Data::Dumper ;
Getopt::Long:: Configure ( "bundling" ) ;
Getopt::Long:: Configure ( "pass_through" ) ;
my $ cmdname = "liteimg" ;
my $ statedir = ".statelite" ;
2010-05-26 08:12:55 +00:00
my $ verbose = "0" ;
2009-12-15 20:38:34 +00:00
sub handled_commands {
return {
$ cmdname = > "statelite"
}
}
# function to handle request. Basically, get the information
# about the image and then do the action on it. Is that vague enough?
sub process_request {
my $ request = shift ;
my $ callback = shift ;
my $ doreq = shift ;
2012-05-23 05:57:41 +00:00
#my $sitetab = xCAT::Table->new('site');
#my $ent = $sitetab->getAttribs({key=>'installdir'},['value']);
2012-08-09 04:07:40 +00:00
my @ entries = xCAT::TableUtils - > get_site_attribute ( "installdir" ) ;
2012-05-23 05:57:41 +00:00
my $ t_entry = $ entries [ 0 ] ;
2009-12-15 20:38:34 +00:00
my $ installroot = "/install" ;
# get /install directory
2012-05-23 05:57:41 +00:00
if ( defined ( $ t_entry ) ) {
$ installroot = $ t_entry ;
2009-12-15 20:38:34 +00:00
}
# if not defined, error out... or should we set it as default?
unless ( $ installroot ) {
$ callback - > ( { error = > [ "No installdir defined in site table" ] , errorcode = > [ 1 ] } ) ;
return ;
}
@ ARGV = @ { $ request - > { arg } } ;
my $ argc = scalar @ ARGV ;
if ( $ argc == 0 ) {
2010-07-06 06:33:21 +00:00
$ callback - > ( { info = > [ "$cmdname -h # this help message\n$cmdname -v # version\n$cmdname -V # verbose\n$cmdname -p <profile> -a <architecture> -o <OS>\n$cmdname imagename" ] } ) ;
2009-12-15 20:38:34 +00:00
return ;
}
2011-01-06 06:54:06 +00:00
my $ rootfstype ;
my $ exlistloc ; # borrowed from packimage.pm
2009-12-15 20:38:34 +00:00
my $ osver ;
my $ arch ;
my $ profile ;
my $ rootimg_dir ;
2011-01-06 06:54:06 +00:00
my $ exlist ; # it is used when rootfstype = ramdisk
2009-12-15 20:38:34 +00:00
my $ destdir ;
my $ imagename ;
2014-05-15 14:23:48 +00:00
my $ dotorrent ;
2009-12-15 20:38:34 +00:00
GetOptions (
2011-01-06 06:54:06 +00:00
"rootfstype|t=s" = > \ $ rootfstype ,
2009-12-15 20:38:34 +00:00
"profile|p=s" = > \ $ profile ,
"arch|a=s" = > \ $ arch ,
"osver|o=s" = > \ $ osver ,
"help|h" = > \ $ help ,
2014-05-15 14:23:48 +00:00
"tracker" = > \ $ dotorrent ,
2009-12-15 20:38:34 +00:00
"version|v" = > \ $ version ,
"verbose|V" = > \ $ verbose
) ;
if ( $ version ) {
my $ version = xCAT::Utils - > Version ( ) ;
$ callback - > ( { info = > [ $ version ] } ) ;
return ;
}
if ( $ help ) {
2010-06-11 07:18:35 +00:00
$ callback - > ( { info = > [ "$cmdname -h # this help message\n$cmdname -v # version\n$cmdname -V # verbose\n$cmdname [-p profile] [-a architecture] [-o OS]\n$cmdname imagename" ] } ) ;
2009-12-15 20:38:34 +00:00
return ;
}
# if they only gave us the image name:
if ( @ ARGV > 0 ) {
$ imagename = $ ARGV [ 0 ] ;
if ( $ arch or $ osver or $ profile ) {
$ callback - > ( { error = > [ "-o, -p and -a options are not allowed when a image name is specified." ] , errorcode = > [ 1 ] } ) ;
return ;
}
#load the module in memory
eval { require ( "$::XCATROOT/lib/perl/xCAT/Table.pm" ) } ;
if ( $@ ) {
$ callback - > ( { error = > [ $@ ] , errorcode = > [ 1 ] } ) ;
return ;
}
#get the info from the osimage and linux
my $ osimagetab = xCAT::Table - > new ( 'osimage' , - create = > 1 ) ;
if ( ! $ osimagetab ) {
# os image doesn't exist in table.
$ callback - > ( { error = > [ "The osimage table cannot be opened." ] , errorcode = > [ 1 ] } ) ;
return ;
}
# open the linux image table to get more attributes... for later.
my $ linuximagetab = xCAT::Table - > new ( 'linuximage' , - create = > 1 ) ;
if ( ! $ linuximagetab ) {
$ callback - > ( { error = > [ "The linuximage table cannot be opened." ] , errorcode = > [ 1 ] } ) ;
return ;
}
# get the os, arch, and profile from the image name table.
2011-09-19 21:08:09 +00:00
( my $ ref ) = $ osimagetab - > getAttribs ( { imagename = > $ imagename } , 'rootfstype' , 'osvers' , 'osarch' , 'profile' , 'provmethod' ) ;
2009-12-15 20:38:34 +00:00
if ( ! $ ref ) {
$ callback - > ( { error = > [ "Cannot find image \'$imagename\' from the osimage table." ] , errorcode = > [ 1 ] } ) ;
return ;
}
2011-09-19 21:08:09 +00:00
my $ provmethod = $ ref - > { 'provmethod' } ;
if ( $ provmethod !~ /statelite/ ) {
$ callback - > ( { error = > [ "Please make sure that osimage.provmethod is set to statelite before calling this command." ] , errorcode = > [ 1 ] } ) ;
return ;
}
$ rootfstype = $ ref - > { 'rootfstype' } ;
2009-12-15 20:38:34 +00:00
$ osver = $ ref - > { 'osvers' } ;
$ arch = $ ref - > { 'osarch' } ;
$ profile = $ ref - > { 'profile' } ;
2011-01-06 06:54:06 +00:00
# get the exlist and rootimgdir attributes
( my $ ref1 ) = $ linuximagetab - > getAttribs ( { imagename = > $ imagename } , 'exlist' , 'rootimgdir' ) ;
unless ( $ ref1 ) {
$ callback - > ( { error = > [ qq{ Cannot find image '$imagename' from the osimage table. } ] , errorcode = > [ 1 ] } ) ;
}
$ destdir = $ ref1 - > { 'rootimgdir' } ;
$ exlistloc = $ ref1 - > { 'exlist' } ;
$ rootimg_dir = "$destdir/rootimg" ;
2009-12-15 20:38:34 +00:00
} # end of case where they give us osimage.
unless ( $ osver and $ arch and $ profile ) {
$ callback - > ( { error = > [ "osimage.osvers, osimage.osarch, and osimage.profile and must be specified for the image $imagename in the database, or you must specify -o os -p profile -a arch." ] , errorcode = > [ 1 ] } ) ;
return ;
}
2011-01-06 06:54:06 +00:00
unless ( $ destdir ) {
$ destdir = "$installroot/netboot/$osver/$arch/$profile" ;
$ rootimg_dir = "$destdir/rootimg" ;
}
2009-12-15 20:38:34 +00:00
my $ oldpath = cwd ( ) ;
# now we have all the info we need:
# - rootimg_dir
# - osver
# - arch
# - profile
$ callback - > ( { info = > [ "going to modify $rootimg_dir" ] } ) ;
2010-02-11 02:24:48 +00:00
2012-09-25 02:51:23 +00:00
#copy $installroot/postscripts into the image at /xcatpost
if ( - e "$rootimg_dir/xcatpost" ) {
system ( "rm -rf $rootimg_dir/xcatpost" ) ;
}
system ( "mkdir -p $rootimg_dir/xcatpost" ) ;
system ( "cp -r $installroot/postscripts/* $rootimg_dir/xcatpost/" ) ;
2010-02-11 02:24:48 +00:00
#get the root password for the node
my $ passtab = xCAT::Table - > new ( 'passwd' ) ;
if ( $ passtab ) {
2011-12-21 06:45:37 +00:00
my $ pass = 'cluster' ;
2010-02-11 02:24:48 +00:00
( my $ pent ) = $ passtab - > getAttribs ( { key = > 'system' , username = > 'root' } , 'password' ) ;
if ( $ pent and defined ( $ pent - > { password } ) ) {
2011-12-21 06:45:37 +00:00
$ pass = $ pent - > { password } ;
}
2010-09-16 13:41:16 +00:00
my $ oldmask = umask ( 0077 ) ;
2010-02-11 02:24:48 +00:00
my $ shadow ;
open ( $ shadow , "<" , "$rootimg_dir/etc/shadow" ) ;
my @ shadents = <$shadow> ;
close ( $ shadow ) ;
open ( $ shadow , ">" , "$rootimg_dir/etc/shadow" ) ;
2013-01-14 14:56:44 +00:00
# 1 - MD5, 5 - SHA256, 6 - SHA512
unless ( ( $ pass =~ /^\$1\$/ ) || ( $ pass =~ /^\$5\$/ ) || ( $ pass =~ /^\$6\$/ ) ) {
2010-02-11 02:24:48 +00:00
$ pass = crypt ( $ pass , '$1$' . genpassword ( 8 ) ) ;
}
print $ shadow "root:$pass:13880:0:99999:7:::\n" ;
foreach ( @ shadents ) {
unless ( /^root:/ ) {
print $ shadow "$_" ;
}
}
close ( $ shadow ) ;
2010-09-16 13:41:16 +00:00
umask ( $ oldmask ) ;
2010-02-11 02:24:48 +00:00
}
2011-01-06 06:54:06 +00:00
my $ distname = $ osver ;
unless ( - r "$::XCATROOT/share/xcat/netboot/$distname/" or not $ distname ) {
chop ( $ distname ) ;
}
unless ( $ distname ) {
$ callback - > ( { error = > [ "Unable to find $::XCATROOT/share/xcat/netboot directory for $osver" ] , errorcode = > [ 1 ] } ) ;
return ;
}
unless ( $ imagename ) {
2010-02-19 18:39:56 +00:00
#store the image in the DB
my @ ret = xCAT::SvrUtils - > update_tables_with_diskless_image ( $ osver , $ arch , $ profile , 'statelite' ) ;
2011-01-06 06:54:06 +00:00
if ( $ ret [ 0 ] ) {
$ callback - > ( { error = > [ "Error when updating the osimage tables: " . $ ret [ 1 ] ] } ) ;
2010-02-19 18:39:56 +00:00
}
2011-01-06 06:54:06 +00:00
$ imagename = "$osver-$arch-statelite-$profile" ;
$ exlistloc = xCAT::SvrUtils - > get_exlist_file_name ( "$installroot/custom/netboot/$distname" , $ profile , $ osver , $ arch ) ;
unless ( $ exlistloc ) {
$ exlistloc = xCAT::SvrUtils - > get_exlist_file_name ( "$::XCATROOT/share/xcat/netboot/$distname" , $ profile , $ osver , $ arch ) ;
}
2010-02-19 18:39:56 +00:00
}
2012-01-19 08:01:57 +00:00
#sync fils configured in the synclist to the rootimage
$ syncfile = xCAT::SvrUtils - > getsynclistfile ( undef , $ osver , $ arch , $ profile , "netboot" , $ imagename ) ;
if ( defined ( $ syncfile ) && - f $ syncfile
&& - d $ rootimg_dir ) {
print "sync files from $syncfile to the $rootimg_dir\n" ;
`$::XCATROOT/bin/xdcp -i $rootimg_dir -F $syncfile` ;
}
2010-03-11 07:03:56 +00:00
# check if the file "litefile.save" exists or not
# if it doesn't exist, then we get the synclist, and run liteMe
# if it exists, it means "liteimg" has run more than one time, we need to compare with the synclist
my @ listSaved ;
if ( - e "$rootimg_dir/.statelite/litefile.save" ) {
open SAVED , "$rootimg_dir/.statelite/litefile.save" ;
# store all its contents to @listSaved;
while ( <SAVED> ) {
chomp $ _ ;
push @ listSaved , $ _ ;
}
close SAVED ;
}
2010-05-26 07:55:36 +00:00
my % hashSaved = ( ) ;
if ( parseLiteFiles ( \ @ listSaved , \ % hashSaved ) ) {
$ callback - > ( { error = > [ "parseLiteFiles failed for listSaved!" ] } ) ;
return ;
}
2009-12-15 20:38:34 +00:00
# now get the files for the node
2010-02-19 18:39:56 +00:00
my @ synclist = xCAT::Utils - > runcmd ( "ilitefile $imagename" , 0 , 1 ) ;
2010-05-26 07:55:36 +00:00
unless ( @ synclist ) {
2010-02-19 18:39:56 +00:00
$ callback - > ( { error = > [ "There are no files to sync for $imagename. You have to have some files read/write filled out in the synclist table." ] , errorcode = > [ 1 ] } ) ;
2009-12-15 20:38:34 +00:00
return ;
}
2010-03-11 07:03:56 +00:00
my $ listNew = $ synclist [ 0 ] ;
2011-02-24 08:04:45 +00:00
# for compatible reason, replace "tmpfs,rw" with "link" option in xCAT 2.5 or higher
for ( @ { $ listNew } ) {
s/tmpfs,rw/link/ ;
}
2010-05-26 07:55:36 +00:00
2010-11-30 09:25:14 +00:00
# the directory/file in litefile table must be the absolute path ("/***")
foreach my $ entry ( @$ listNew ) {
my @ tmp = split ( /\s+/ , $ entry ) ;
2012-11-16 14:02:36 +00:00
# check the validity of the option
2013-01-08 05:31:08 +00:00
if ( $ tmp [ 1 ] !~ /^(tmpfs|persistent|localdisk|rw|ro|con|link|tmpfs,rw|link,ro|link,persistent|link,con)$/ ) {
2013-01-08 06:32:46 +00:00
$ callback - > ( { error = > [ qq{ $tmp[2] has invalid option. The valid options: tmpfs persistent localdisk rw ro con link tmpfs,rw link,ro link,persistent link,con } ] , errorcode = > [ 1 ] } ) ;
2012-11-16 14:02:36 +00:00
return ;
}
2010-11-30 09:25:14 +00:00
unless ( $ tmp [ 2 ] =~ m {^/} ) {
$ callback - > ( { error = > [ qq{ $tmp[2] is not one absolute path. } ] , errorcode = > [ 1 ] } ) ;
return ;
}
if ( $ tmp [ 1 ] =~ m {con} and $ tmp [ 2 ] =~ m {/$} ) {
$ callback - > ( { error = > [ qq{ $tmp[2] is directory, don't use "con" as its option } ] , errorcode = > [ 1 ] } ) ;
return ;
}
}
2010-05-26 07:55:36 +00:00
my % hashNew = ( ) ;
if ( parseLiteFiles ( $ listNew , \ % hashNew ) ) {
$ callback - > ( { error = > [ "parseLiteFiles failed for listNew!" ] } ) ;
return ;
}
2010-11-06 07:36:48 +00:00
# validate the options for all litefile entries
# if there is any scenario not supported, the command exits
2010-05-26 07:55:36 +00:00
foreach my $ entry ( keys % hashNew ) {
my @ tmp = split ( /\s+/ , $ entry ) ;
2010-11-06 07:36:48 +00:00
my $ f = $ tmp [ 1 ] ;
2010-11-30 09:25:14 +00:00
2010-06-04 09:39:17 +00:00
if ( $ hashNew { $ entry } ) {
2010-11-06 07:36:48 +00:00
if ( $ tmp [ 0 ] =~ m/ro$/ or $ tmp [ 0 ] =~ m/con$/ ) {
$ callback - > ( { error = > [ qq{ the directory "$f" should not be with "ro" or "con" as its option } ] , errorcode = > [ 1 ] } ) ;
2010-09-17 09:54:47 +00:00
return ;
}
2010-05-26 07:55:36 +00:00
foreach my $ child ( @ { $ hashNew { $ entry } } ) {
my @ tmpc = split ( /\s+/ , $ child ) ;
2010-08-15 16:15:58 +00:00
my $ fc = $ tmpc [ 1 ] ;
2010-11-06 07:36:48 +00:00
if ( $ tmp [ 0 ] =~ m/link/ ) {
if ( $ tmpc [ 0 ] eq "link,ro" ) {
$ callback - > ( { error = > [ qq{ Based on the option of $f, $fc should not use "link,ro" as its option } ] , errorcode = > [ 1 ] } ) ;
return ;
}
if ( $ tmpc [ 0 ] !~ m/link/ ) {
$ callback - > ( { error = > [ qq{ Based on the option of $f, $fc can only use "link"-based options } ] , errorcode = > [ 1 ] } ) ;
return ;
}
} else {
if ( $ tmpc [ 0 ] =~ m/link/ ) {
2013-05-14 02:19:49 +00:00
# The /etc/mtab is a specific file which can only be handled by link option.
# It need to be existed in rootimage and during the runing of statelite,
# and after running of statelite, it need to be linked to /proc/mount
2013-05-09 02:43:30 +00:00
if ( $ tmpc [ 1 ] != "/etc/mtab" ) {
2013-05-14 02:19:49 +00:00
$ callback - > ( { error = > [ qq{ Based on the option of $f, $fc should not use "link"-based options } ] , errorcode = > [ 1 ] } ) ;
return ;
2013-05-09 02:43:30 +00:00
}
2010-11-06 07:36:48 +00:00
}
2010-06-04 09:39:17 +00:00
}
2010-11-06 07:36:48 +00:00
if ( ( $ tmp [ 0 ] =~ m {persistent} ) and ( $ tmpc [ 0 ] !~ m {persistent} ) ) {
# TODO: if the parent is "persistent", the child can be ro/persistent/rw/con
2010-05-26 07:55:36 +00:00
$ callback - > ( { error = > [ "$fc should have persistent option like $f " ] , errorcode = > [ 1 ] } ) ;
return ;
}
}
}
2010-06-04 09:39:17 +00:00
2010-05-26 07:55:36 +00:00
}
# backup the file/directory before recovering the files in litefile.save
unless ( - d "$rootimg_dir/.statebackup" ) {
if ( - e "$rootimg_dir/.statebackup" ) {
xCAT::Utils - > runcmd ( "rm $rootimg_dir/.statebackup" , 0 , 1 ) ;
}
$ verbose && $ callback - > ( { info = > [ "mkdir $rootimg_dir/.statebackup" ] } ) ;
xCAT::Utils - > runcmd ( "mkdir $rootimg_dir/.statebackup" , 0 , 1 ) ;
}
# recovery the files in litefile.save if necessary
foreach my $ line ( keys % hashSaved ) {
2010-03-11 07:03:56 +00:00
my @ oldentry = split ( /\s+/ , $ line ) ;
2010-08-15 16:15:58 +00:00
my $ f = $ oldentry [ 1 ] ;
2010-05-26 07:55:36 +00:00
my @ newentries = grep /\s+$f$/ , @ { $ listNew } ;
2010-03-11 07:03:56 +00:00
my @ entry ;
2010-05-26 07:55:36 +00:00
if ( scalar @ newentries == 1 ) {
@ entry = split ( /\s+/ , $ newentries [ 0 ] ) ;
}
2010-03-11 07:03:56 +00:00
2010-05-26 07:55:36 +00:00
# backup the children to .statebackup
if ( $ hashSaved { $ line } ) {
my $ childrenRef = $ hashSaved { $ line } ;
unless ( - d "$rootimg_dir/.statebackup$f" ) {
xCAT::Utils - > runcmd ( "rm -rf $rootimg_dir/.statebackup$f" , 0 , 1 ) if ( - e "$rootimg_dir/.statebackup$f" ) ;
$ verbose && $ callback - > ( { info = > [ "mkdir $rootimg_dir/.statebackup$f" ] } ) ;
xCAT::Utils - > runcmd ( "mkdir -p $rootimg_dir/.statebackup$f" ) ;
}
foreach my $ child ( @ { $ childrenRef } ) {
my @ tmpc = split ( /\s+/ , $ child ) ;
2010-08-15 16:15:58 +00:00
my $ name = $ rootimg_dir . $ tmpc [ 1 ] ;
2010-05-26 07:55:36 +00:00
if ( - e $ name ) {
2010-08-13 10:27:29 +00:00
$ verbose && $ callback - > ( { info = > [ "cp -r -a $name $rootimg_dir/.statebackup$f" ] } ) ;
xCAT::Utils - > runcmd ( "cp -r -a $name $rootimg_dir/.statebackup$f" ) ;
2010-05-26 07:55:36 +00:00
}
}
2010-03-11 07:03:56 +00:00
}
2010-11-06 07:36:48 +00:00
# there's one parent directory, whose option is different from the old one
2010-09-17 09:54:47 +00:00
unless ( $ entry [ 1 ] eq $ oldentry [ 0 ] ) {
2010-05-26 07:55:36 +00:00
recoverFiles ( $ rootimg_dir , \ @ oldentry , $ callback ) ;
2010-11-06 07:36:48 +00:00
# if its children items exist, we need to copy the backup files from .statebackup to the rootfs,
2010-05-26 07:55:36 +00:00
if ( $ hashSaved { $ line } ) {
2010-11-06 07:36:48 +00:00
$ verbose && $ callback - > ( { info = > [ "$f has child file/directory in the litefile table." ] } ) ;
2010-05-26 07:55:36 +00:00
my $ childrenRef = $ hashSaved { $ line } ;
foreach my $ child ( @ { $ childrenRef } ) {
# recover them from .statebackup to $rootimg_dir
my @ tmpc = split ( /\s+/ , $ child ) ;
2010-08-15 16:15:58 +00:00
my $ name = $ tmpc [ 1 ] ;
2010-05-26 07:55:36 +00:00
my @ newentries = grep /\s+$name$/ , @ { listNew } ;
my $ destf = $ rootimg_dir . $ name ;
2010-08-13 10:27:29 +00:00
my $ srcf = $ rootimg_dir . "/.statebackup" . $ name ;
2010-05-26 07:55:36 +00:00
if ( - e $ destf ) {
$ verbose && $ callback - > ( { info = > [ "rm -rf $destf" ] } ) ;
xCAT::Utils - > runcmd ( "rm -rf $destf" , 0 , 1 ) ;
2010-04-16 01:40:33 +00:00
}
2010-05-26 07:55:36 +00:00
2010-11-06 07:36:48 +00:00
# maybe the dir of $destf doesn't exist, so we will create one
my $ dirDestf = dirname $ destf ;
unless ( - d $ dirDestf ) {
$ verbose && $ callback - > ( { info = > [ "mkdir -p $dirDestf" ] } ) ;
xCAT::Utils - > runcmd ( "mkdir -p $dirDestf" , 0 , 1 ) ;
}
2010-05-26 07:55:36 +00:00
if ( - e $ srcf ) {
$ verbose && $ callback - > ( { info = > [ "recovering from $srcf to $destf" ] } ) ;
2010-08-13 10:27:29 +00:00
xCAT::Utils - > runcmd ( "cp -r -a $srcf $destf" , 0 , 1 ) ;
2010-03-31 12:35:45 +00:00
}
2010-05-26 07:55:36 +00:00
2010-03-11 07:03:56 +00:00
}
2010-05-26 07:55:36 +00:00
}
}
2010-03-11 07:03:56 +00:00
2010-05-26 07:55:36 +00:00
# recover the children
if ( $ hashSaved { $ line } ) {
2010-11-06 07:36:48 +00:00
$ verbose && $ callback - > ( { info = > [ "$f has child file/directory in the litefile table." ] } ) ;
2010-05-26 07:55:36 +00:00
my $ childrenRef = $ hashSaved { $ line } ;
foreach my $ child ( @ { $ childrenRef } ) {
my @ tmpc = split ( /\s+/ , $ child ) ;
2010-08-15 16:15:58 +00:00
my $ name = $ tmpc [ 1 ] ;
2011-02-22 07:24:28 +00:00
my @ newentries = grep /\s+$name$/ , @ { $ listNew } ;
2010-05-26 07:55:36 +00:00
my @ entry ;
if ( scalar @ newentries == 1 ) {
@ entry = split ( /\s+/ , $ newentries [ 0 ] ) ;
}
2010-09-17 09:54:47 +00:00
unless ( $ tmpc [ 0 ] eq $ entry [ 1 ] ) {
2010-05-26 07:55:36 +00:00
recoverFiles ( $ rootimg_dir , \ @ tmpc , $ callback ) ;
}
2010-03-11 07:03:56 +00:00
}
}
2010-05-26 07:55:36 +00:00
2010-03-11 07:03:56 +00:00
}
2010-05-26 07:55:36 +00:00
# remove .statebackup
$ verbose && $ callback - > ( { info = > [ "remove .statebackup" ] } ) ;
2010-05-26 08:12:55 +00:00
xCAT::Utils - > runcmd ( "rm -rf $rootimg_dir/.statebackup" , 0 , 1 ) ;
2010-05-26 07:55:36 +00:00
2010-03-11 07:03:56 +00:00
# then store the @synclist to litefile.save
#system("cp $rootimg_dir/.statelite/litefile.save $rootimg_dir/.statelite/litefile.save1");
open SAVED , ">$rootimg_dir/.statelite/litefile.save" ;
foreach my $ line ( @ { $ listNew } ) {
print SAVED "$line\n" ;
}
close SAVED ;
2010-02-19 18:39:56 +00:00
2010-09-17 09:54:47 +00:00
liteMe ( $ rootimg_dir , \ % hashNew , $ callback ) ;
2010-02-19 18:39:56 +00:00
2010-06-11 08:16:30 +00:00
# now stick the rc file in:
# this is actually a pre-rc file because it gets run before the node boots up all the way.
$ verbose && $ callback - > ( { info = > [ "put the statelite rc file to $rootimg_dir/etc/init.d/" ] } ) ;
2013-12-12 10:13:02 +00:00
# rh5,rh6.1 to rh6.4 use rc.statelite.ppc.redhat, otherwise use rc.statelite
if ( ( $ osver =~ m/^rh[a-zA-Z]*5/ ) or ( $ osver =~ m/^rh[a-zA-Z]*6(\.)?[1-4]/ ) and $ arch eq "ppc64" ) { # special case for redhat5/6.x on PPC64
2010-06-11 08:16:30 +00:00
system ( "cp -a $::XCATROOT/share/xcat/netboot/add-on/statelite/rc.statelite.ppc.redhat $rootimg_dir/etc/init.d/statelite" ) ;
} else {
system ( "cp -a $::XCATROOT/share/xcat/netboot/add-on/statelite/rc.statelite $rootimg_dir/etc/init.d/statelite" ) ;
}
2011-01-06 06:54:06 +00:00
# newly-introduced code for the rootfs with "ramdisk" as its type
if ( $ rootfstype eq "ramdisk" ) {
my $ xcat_packimg_tmpfile = "/tmp/xcat_packimg.$$" ;
my $ excludestr = "find . " ;
my $ includestr ;
if ( $ exlistloc ) {
2012-10-29 12:39:54 +00:00
my @ excludeslist = split ',' , $ exlistloc ;
foreach my $ exlistlocname ( @ excludeslist ) {
my $ exlist ;
my $ excludetext ;
open ( $ exlist , "<" , $ exlistlocname ) ;
system ( "echo -n > $xcat_packimg_tmpfile" ) ;
while ( <$exlist> ) {
$ excludetext . = $ _ ;
}
close ( $ exlist ) ;
#handle the #INLCUDE# tag recursively
my $ idir = dirname ( $ exlistlocname ) ;
my $ doneincludes = 0 ;
while ( not $ doneincludes ) {
$ doneincludes = 1 ;
if ( $ excludetext =~ /#INCLUDE:[^#^\n]+#/ ) {
$ doneincludes = 0 ;
$ excludetext =~ s/#INCLUDE:([^#^\n]+)#/include_file($1,$idir)/eg ;
}
2011-01-06 06:54:06 +00:00
}
2012-10-29 12:39:54 +00:00
my @ tmp = split ( "\n" , $ excludetext ) ;
foreach ( @ tmp ) {
chomp $ _ ;
s/\s*#.*// ; #-- remove comments
next if /^\s*$/ ; #-- skip empty lines
if ( /^\+/ ) {
s/^\+// ; #remove '+'
$ includestr . = "-path '" . $ _ . "' -o " ;
} else {
s/^\-// ; #remove '-' if any
$ excludestr . = "'!' -path '" . $ _ . "' -a " ;
}
2011-01-06 06:54:06 +00:00
}
}
}
$ excludestr =~ s/-a $// ;
if ( $ includestr ) {
$ includestr =~ s/-o $// ;
$ includestr = "find . " . $ includestr ;
}
print "\nexcludestr=$excludestr\n\n includestr=$includestr\n\n" ; # debug
# some rpms like atftp mount the rootimg/proc to /proc, we need to make sure rootimg/proc is free of junk
# before packaging the image
system ( "umount $rootimg_dir/proc" ) ;
my $ verb = "Packing" ;
my $ temppath ;
my $ oldmask ;
$ callback - > ( { data = > [ "$verb contents of $rootimg_dir" ] } ) ;
unlink ( "$destdir/rootimg-statelite.gz" ) ;
if ( $ exlistloc ) {
chdir ( "$rootimg_dir" ) ;
system ( "$excludestr >> $xcat_packimg_tmpfile" ) ;
if ( $ includestr ) {
system ( "$includestr >> $xcat_packimg_tmpfile" ) ;
}
$ excludestr = "cat $xcat_packimg_tmpfile |cpio -H newc -o | gzip -c - > ../rootimg-statelite.gz" ;
} else {
$ excludestr = "find . |cpio -H newc -o | gzip -c - > ../rootimg-statelite.gz" ;
}
$ oldmask = umask 0077 ;
chdir ( "$rootimg_dir" ) ;
xCAT::Utils - > runcmd ( "$excludestr" ) ;
chmod 0644 , "$destdir/rootimg-statelite.gz" ;
2014-05-15 14:23:48 +00:00
if ( $ dotorrent ) {
my $ currdir = getcwd ;
chdir ( $ destdir ) ;
unlink ( "rootimg-statelite.gz.metainfo" ) ;
system ( "ctorrent -t -u $dotorrent -l 1048576 -s rootimg-statelite.gz.metainfo rootimg.gz" ) ;
chmod 0644 , "rootimg-statelite.gz.metainfo" ;
chdir ( $ currdir ) ;
}
2011-01-06 06:54:06 +00:00
umask $ oldmask ;
system ( "rm -f $xcat_packimg_tmpfile" ) ;
}
chdir ( $ oldpath ) ;
2010-05-26 07:55:36 +00:00
}
2010-09-17 09:54:47 +00:00
sub liteMe {
2010-05-26 07:55:36 +00:00
my $ rootimg_dir = shift ;
my $ hashNewRef = shift ;
my $ callback = shift ;
unless ( - d $ rootimg_dir ) {
$ callback - > ( { error = > [ "no rootimage dir" ] , errorcode = > [ 1 ] } ) ;
return ;
}
2010-12-14 07:04:12 +00:00
unless ( - d "$rootimg_dir/$statedir" ) {
# snapshot directory for tmpfs and persistent data.
if ( - e "$rootimg_dir/$statedir" ) {
xCAT::Utils - > runcmd ( "rm -rf $rootimg_dir/$statedir" , 0 , 1 ) ;
}
$ callback - > ( { info = > [ "creating $rootimg_dir/$statedir" ] } ) ;
xCAT::Utils - > runcmd ( "mkdir -p $rootimg_dir/$statedir" , 0 , 1 ) ;
}
2010-05-26 07:55:36 +00:00
unless ( - d "$rootimg_dir/$statedir/tmpfs" ) {
xCAT::Utils - > runcmd ( "mkdir -p $rootimg_dir/$statedir/tmpfs" , 0 , 1 ) ;
}
foreach my $ line ( keys % { $ hashNewRef } ) {
liteItem ( $ rootimg_dir , $ line , 0 , $ callback ) ;
if ( $ hashNewRef - > { $ line } ) { # there're children
my $ childrenRef = $ hashNewRef - > { $ line } ;
foreach my $ child ( @ { $ childrenRef } ) {
liteItem ( $ rootimg_dir , $ child , 1 , $ callback ) ;
}
}
}
2010-12-14 07:04:12 +00:00
$ callback - > ( { info = > [ "done." ] } ) ;
2010-05-26 07:55:36 +00:00
# end loop, synclist should now all be in place.
2009-12-15 20:38:34 +00:00
}
sub getRelDir {
my $ f = shift ;
$ f = dirname ( $ f ) ;
if ( $ f eq "/" ) {
return "." ;
}
my $ l = "" ;
my @ arr = split ( "/" , $ f ) ;
foreach ( 1 .. $# arr ) {
$ l . = "../" ;
}
chop ( $ l ) ; # get rid of last /
return $ l
}
2011-08-31 12:11:14 +00:00
sub include_file
{
my $ file = shift ;
my $ idir = shift ;
my @ text = ( ) ;
unless ( $ file =~ /^\// ) {
$ file = $ idir . "/" . $ file ;
}
open ( INCLUDE , $ file ) || \
return "#INCLUDEBAD:cannot open $file#" ;
while ( <INCLUDE> ) {
chomp ( $ _ ) ;
s/\s+$// ; #remove trailing spaces
next if /^\s*$/ ; #-- skip empty lines
push ( @ text , $ _ ) ;
}
close ( INCLUDE ) ;
return join ( "\n" , @ text ) ;
}
2010-05-26 07:55:36 +00:00
= head3 parseLiteFiles
In the liteentry table , one directory and its sub - items ( including sub - directory and entries ) can co - exist ;
In order to handle such a scenario , one hash is generated to show the hirarachy relationship
For example , one array with entry names is used as the input:
my @ entries = (
2010-11-06 07:36:48 +00:00
"imagename persistent /var/" ,
"imagename tempfs /var/tmp/" ,
"imagename link /root/" ,
"imagename link /root/.bashrc" ,
"imagename link /root/test/" ,
"imagename link /root/second/third" ,
"imagename tempfs /etc/resolv.conf" ,
"imagename tempfs /var/run/"
2010-05-26 07:55:36 +00:00
) ;
Then , one hash will generated as:
% hashentries = {
2010-11-06 07:36:48 +00:00
'persistent /var/' = > [
'tempfs /var/tmp/' ,
'tempfs /var/run/'
] ,
'tempfs /etc/resolv.conf' = > undef ,
'link /root/' = > [
'link /root/.bashrc' ,
'link /root/test/' ,
' link /root/s econd / third "
]
} ;
2010-05-26 07:55:36 +00:00
Arguments:
one array with entrynames ,
one hash to hold the entries parsed
Returns:
0 if sucucess
1 if fail
= cut
sub parseLiteFiles {
my ( $ flref , $ dhref ) = @ _ ;
my @ entries = @ { $ flref } ;
foreach ( @ entries ) {
my $ entry = $ _ ;
my @ str = split /\s+/ , $ entry ;
2010-11-06 07:36:48 +00:00
shift @ str ; # remove the imgname in @entries
2010-08-15 16:15:58 +00:00
$ entry = join "\t" , @ str ;
my $ file = $ str [ 1 ] ;
2010-05-26 07:55:36 +00:00
chop $ file if ( $ file =~ m {/$} ) ;
unless ( exists $ dhref - > { "$entry" } ) {
2010-11-06 07:36:48 +00:00
my $ parent = dirname $ file ;
my @ res ;
my $ found = 0 ;
while ( $ parent ne "/" ) {
# to see whether $parent exists in @entries or not
$ parent . = "/" unless ( $ parent =~ m/\/$/ ) ;
@ res = grep { $ _ =~ m/\Q$parent\E$/ } @ entries ;
$ found = scalar @ res ;
last if ( $ found eq 1 ) ;
$ parent = dirname $ parent ;
2010-05-26 07:55:36 +00:00
}
if ( $ found eq 1 ) { # $parent is found in @entries
2010-08-15 16:15:58 +00:00
# handle $res[0];
my @ tmpresentry = split /\s+/ , $ res [ 0 ] ;
2010-11-06 07:36:48 +00:00
shift @ tmpresentry ; # remove the imgname in @tmpresentry
2010-08-15 16:15:58 +00:00
$ res [ 0 ] = join "\t" , @ tmpresentry ;
2010-05-26 07:55:36 +00:00
chop $ parent ;
my @ keys = keys % { $ dhref } ;
my $ kfound = grep { $ _ =~ m/\Q$res[0]\E$/ } @ keys ;
if ( $ kfound eq 0 ) {
$ dhref - > { $ res [ 0 ] } = [] ;
}
push @ { $ dhref - > { "$res[0]" } } , $ entry ;
} else {
$ dhref - > { "$entry" } = ( ) ;
}
}
}
return 0 ;
}
= head3
recoverFiles
= cut
sub recoverFiles {
my ( $ rootimg_dir , $ oldentry , $ callback ) = @ _ ;
2010-09-15 02:54:26 +00:00
$ f = $ oldentry - > [ 1 ] ;
2010-05-26 07:55:36 +00:00
#$callback->({info => ["! updating $f ..."]});
2010-11-06 07:36:48 +00:00
if ( $ oldentry - > [ 0 ] =~ m {^link} ) {
2010-05-26 07:55:36 +00:00
my $ target = $ rootimg_dir . $ f ;
if ( - l $ target ) { #not one directory
my $ location = readlink $ target ;
# if it is not linked from tmpfs, it should have been modified by the .postinstall file
if ( $ location =~ /\.statelite\/tmpfs/ ) {
xCAT::Utils - > runcmd ( "rm -rf $target" , 0 , 1 ) ;
my $ default = $ rootimg_dir . "/.default" . $ f ;
if ( - e $ default ) {
2010-07-19 11:05:38 +00:00
xCAT::Utils - > runcmd ( "cp -r -a $default $target" , 0 , 1 ) ;
2010-05-26 07:55:36 +00:00
} else { # maybe someone deletes the copy in .default directory
xCAT::Utils - > runcmd ( "touch $target" , 0 , 1 ) ;
}
}
} else {
chop $ target ;
if ( - l $ target ) {
my $ location = readlink $ target ;
if ( $ location =~ /\.statelite\/tmpfs/ ) {
xCAT::Utils - > runcmd ( "rm -rf $target" , 0 , 1 ) ;
my $ default = $ rootimg_dir . "/.default" . $ f ;
if ( - e $ default ) {
2010-07-19 11:05:38 +00:00
xCAT::Utils - > runcmd ( "cp -r -a $default $target" , 0 , 1 ) ;
2010-05-26 07:55:36 +00:00
} else {
xCAT::Utils - > runcmd ( "mkdir $target" , 0 , 1 ) ;
}
}
}
}
$ target = $ rootimg_dir . "/.statelite/tmpfs" . $ f ;
xCAT::Utils - > runcmd ( "rm -rf $target" , 0 , 1 ) ;
2010-09-17 09:54:47 +00:00
} else {
# shouldn't copy back from /.default, maybe the user has replaced the file/directory in .postinstall file
my $ default = $ rootimg_dir . $ f ;
xCAT::Utils - > runcmd ( "rm -rf $default" , 0 , 1 ) ; # TODO: not sure whether it's necessary right now
2010-05-26 07:55:36 +00:00
}
return 0 ;
}
= head3
liteItem
= cut
sub liteItem {
2010-08-15 16:15:58 +00:00
my ( $ rootimg_dir , $ item , $ isChild , $ callback ) = @ _ ;
2010-05-26 07:55:36 +00:00
my @ entry = split ( /\s+/ , $ item ) ;
2010-08-15 16:15:58 +00:00
2010-11-06 07:36:48 +00:00
my $ f = $ entry [ 1 ] ; # file name
2010-05-26 07:55:36 +00:00
2010-11-06 07:36:48 +00:00
my $ rif = $ rootimg_dir . $ f ; # the file's location in rootimg_dir
2010-05-26 07:55:36 +00:00
my $ d = dirname ( $ f ) ;
2010-09-20 17:16:25 +00:00
if ( $ entry [ 0 ] =~ m/link/ ) {
2010-05-26 07:55:36 +00:00
# 1. copy original contents if they exist to .default directory
# 2. remove file
# 3. create symbolic link to .statelite
2013-05-14 02:19:49 +00:00
# the /etc/mtab should be handled every time even the parent /etc/ has been handled.
# if adding /etc/ to litefile, only tmpfs should be used.
2013-05-09 02:43:30 +00:00
if ( $ entry [ 1 ] == "/etc/mtab" ) {
$ isChild = 0 ;
}
2010-05-26 07:55:36 +00:00
if ( $ isChild == 0 ) {
#check if the file has been moved to .default by its parent or by last liteimg, if yes, then do nothing
my $ ret = `readlink -m $rootimg_dir$f` ;
if ( $? == 0 ) {
if ( $ ret =~ /$rootimg_dir\/.default/ ) {
$ verbose && $ callback - > ( { info = > [ "do nothing for file $f" ] } ) ;
next ;
}
}
# copy the file to /.defaults
if ( - f "$rif" or - d "$rif" ) {
# if its already a link then leave it alone.
unless ( - l $ rif ) {
# mk the directory if it doesn't exist:
2010-08-13 10:27:29 +00:00
unless ( - d "$rootimg_dir/.default$d" ) {
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir/.default$d" ] } ) ;
system ( "mkdir -p $rootimg_dir/.default$d" ) ;
}
2010-05-26 07:55:36 +00:00
# copy the file in place.
2010-07-19 11:05:38 +00:00
$ verbose && $ callback - > ( { info = > [ "cp -r -a $rif $rootimg_dir/.default$d" ] } ) ;
system ( "cp -r -a $rif $rootimg_dir/.default$d" ) ;
2010-05-26 07:55:36 +00:00
# remove the real file
$ verbose && $ callback - > ( { info = > [ "rm -rf $rif" ] } ) ;
system ( "rm -rf $rif" ) ;
}
} else {
# in this case the file doesn't exist in the image so we create something to it.
# here we're modifying the read/only image
unless ( - d "$rootimg_dir$d" ) {
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir$d" ] } ) ;
system ( "mkdir -p $rootimg_dir$d" ) ;
}
unless ( - d "$rootimg_dir/.default$d" ) {
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir/.default$d" ] } ) ;
system ( "mkdir -p $rootimg_dir/.default$d" ) ;
}
# now make touch the file:
if ( $ f =~ /\/$/ ) {
# if its a directory, make the directory in .default
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir/.default$f" ] } ) ;
system ( "mkdir -p $rootimg_dir/.default$f" ) ;
} else {
# if its just a file then link it.
$ verbose && $ callback - > ( { info = > [ "touch $rootimg_dir/.default$f" ] } ) ;
system ( "touch $rootimg_dir/.default$f" ) ;
}
}
# now create the spot in tmpfs
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir/$statedir/tmpfs$d" ] } ) ;
system ( "mkdir -p $rootimg_dir/$statedir/tmpfs$d" ) ;
# now for each file, create a symbollic link to /.statelite/tmpfs/
# strip the last / if its a directory for linking, but be careful!
# doing ln -sf ../../tmp <blah>../tmp when tmp is a directory creates 50 levels of links.
# have to do:
# ln -sf ../../tmp <blah>../../tmp/ <- note the / on the end!
if ( $ f =~ /\/$/ ) {
$ f =~ s/\/$//g ;
}
# now do the links.
# link the .default file to the .statelite file and the real file to the .statelite file.
# ../ for tmpfs
# ../ for .statelite
# the rest are for the paths in the file.
my $ l = getRelDir ( $ f ) ;
$ verbose && $ callback - > ( { info = > [ "ln -sf ../../$l/.default$f $rootimg_dir/$statedir/tmpfs$f" ] } ) ;
system ( "ln -sfn ../../$l/.default$f $rootimg_dir/$statedir/tmpfs/$f" ) ;
$ verbose && $ callback - > ( { info = > [ "ln -sf $l/$statedir/tmpfs$f $rootimg_dir$f" ] } ) ;
system ( "ln -sfn $l/$statedir/tmpfs$f $rootimg_dir$f" ) ;
} else {
# since its parent directory has been linked to .default and .statelite/tmpfs/,
2010-11-06 07:36:48 +00:00
# what we need to do is only to check whether it exists in .default directory
2010-05-26 07:55:36 +00:00
if ( $ f =~ m {/$} ) { # one directory
unless ( - d "$rootimg_dir/.default$f" ) {
if ( - e "$rootimg_dir/.default$f" ) {
xCAT::Utils - > runcmd ( "rm -rf $rootimg_dir/.default$f" , 0 , 1 ) ;
}
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir/.default$f" ] } ) ;
xCAT::Utils - > runcmd ( "mkdir -p $rootimg_dir/.default$f" , 0 , 1 ) ;
}
} else { # only one file
my $ fdir = dirname ( $ f ) ;
unless ( - d "$rootimg_dir/.default$fdir" ) {
2010-11-06 07:36:48 +00:00
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir/.default$fdir" ] } ) ;
2010-05-26 07:55:36 +00:00
xCAT::Utils - > runcmd ( "mkdir -p $rootimg_dir/.default$fdir" , 0 , 1 ) ;
}
2010-08-13 10:27:29 +00:00
unless ( - e "$rootimg_dir/.default$f" ) {
$ verbose && $ callback - > ( { info = > [ "touch $rootimg_dir/.default$f" ] } ) ;
xCAT::Utils - > runcmd ( "touch $rootimg_dir/.default$f" , 0 , 1 ) ;
}
2010-05-26 07:55:36 +00:00
}
}
2010-09-17 09:54:47 +00:00
} else {
# if no such file like $rif, create one
unless ( - e "$rif" ) {
if ( $ f =~ m {/$} ) {
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rif" ] } ) ;
system ( "mkdir -p $rif" ) ;
} else {
# check whether its directory exists or not
my $ rifdir = $ rootimg_dir . $ d ;
unless ( - e $ rifdir ) {
$ verbose && $ callback - > ( { info = > [ "mkdir $rifdir" ] } ) ;
mkdir ( $ rifdir ) ;
}
$ verbose && $ callback - > ( { info = > [ "touch $rif" ] } ) ;
system ( "touch $rif" ) ;
}
}
2010-05-26 07:55:36 +00:00
2010-09-17 09:54:47 +00:00
unless ( - e "$rootimg_dir/.default$d" ) {
$ verbose && $ callback - > ( { info = > [ "mkdir -p $rootimg_dir/.default$d" ] } ) ;
system ( "mkdir -p $rootimg_dir/.default$d" ) ;
}
# copy the file to /.defaults
$ verbose && $ callback - > ( { info = > [ "cp -r -a $rif $rootimg_dir/.default$d" ] } ) ;
system ( "cp -r -a $rif $rootimg_dir/.default$d" ) ;
}
2010-05-26 07:55:36 +00:00
}
2009-12-15 20:38:34 +00:00
1 ;