2008-02-07 18:54:58 +00:00
package xCAT_plugin::packimage ;
2009-09-24 18:51:53 +00:00
BEGIN
{
$ ::XCATROOT = $ ENV { 'XCATROOT' } ? $ ENV { 'XCATROOT' } : '/opt/xcat' ;
}
use lib "$::XCATROOT/lib/perl" ;
2008-02-07 18:54:58 +00:00
use xCAT::Table ;
use Getopt::Long ;
use File::Path ;
2008-04-23 20:03:51 +00:00
use File::Copy ;
2008-02-07 18:54:58 +00:00
use Cwd ;
use File::Temp ;
2010-04-07 15:14:29 +00:00
use File::Basename ;
use File::Path ;
2009-07-22 05:59:11 +00:00
use xCAT::Utils qw( genpassword ) ;
use xCAT::SvrUtils ;
2008-02-07 18:54:58 +00:00
Getopt::Long:: Configure ( "bundling" ) ;
Getopt::Long:: Configure ( "pass_through" ) ;
sub handled_commands {
return {
packimage = > "packimage" ,
}
}
sub process_request {
my $ request = shift ;
my $ callback = shift ;
my $ doreq = shift ;
2010-02-24 08:06:42 +00:00
my $ installroot = xCAT::Utils - > getInstallDir ( ) ;
2008-02-07 18:54:58 +00:00
@ ARGV = @ { $ request - > { arg } } ;
2009-04-14 15:51:20 +00:00
my $ argc = scalar @ ARGV ;
if ( $ argc == 0 ) {
2009-10-02 18:55:54 +00:00
$ callback - > ( { info = > [ "packimage -h \npackimage -v \npackimage [-p profile] [-a architecture] [-o OS] [-m method]\npackimage imagename" ] } ) ;
2009-04-14 15:51:20 +00:00
return ;
}
2009-09-24 18:51:53 +00:00
my $ osver ;
my $ arch ;
my $ profile ;
my $ method = 'cpio' ;
my $ exlistloc ;
my $ syncfile ;
my $ rootimg_dir ;
my $ destdir ;
my $ imagename ;
2008-02-07 18:54:58 +00:00
GetOptions (
"profile|p=s" = > \ $ profile ,
"arch|a=s" = > \ $ arch ,
"osver|o=s" = > \ $ osver ,
2008-03-20 14:45:08 +00:00
"method|m=s" = > \ $ method ,
"help|h" = > \ $ help ,
"version|v" = > \ $ version
2008-02-07 18:54:58 +00:00
) ;
2008-03-20 14:45:08 +00:00
if ( $ version ) {
2008-07-07 18:29:55 +00:00
my $ version = xCAT::Utils - > Version ( ) ;
$ callback - > ( { info = > [ $ version ] } ) ;
2008-03-20 14:45:08 +00:00
return ;
}
2009-04-14 15:51:20 +00:00
if ( $ help ) {
2009-10-02 18:55:54 +00:00
$ callback - > ( { info = > [ "packimage -h \npackimage -v \npackimage [-p profile] [-a architecture] [-o OS] [-m method]\npackimage imagename" ] } ) ;
2008-03-20 14:45:08 +00:00
return ;
}
2009-09-24 18:51:53 +00:00
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 ) {
$ callback - > ( { error = > [ "The osimage table cannot be opened." ] , errorcode = > [ 1 ] } ) ;
return ;
}
my $ linuximagetab = xCAT::Table - > new ( 'linuximage' , - create = > 1 ) ;
if ( ! $ linuximagetab ) {
$ callback - > ( { error = > [ "The linuximage table cannot be opened." ] , errorcode = > [ 1 ] } ) ;
return ;
}
( my $ ref ) = $ osimagetab - > getAttribs ( { imagename = > $ imagename } , 'osvers' , 'osarch' , 'profile' , 'provmethod' , 'synclists' ) ;
if ( ! $ ref ) {
$ callback - > ( { error = > [ "Cannot find image \'$imagename\' from the osimage table." ] , errorcode = > [ 1 ] } ) ;
return ;
}
( my $ ref1 ) = $ linuximagetab - > getAttribs ( { imagename = > $ imagename } , 'exlist' , 'rootimgdir' ) ;
if ( ! $ ref1 ) {
$ callback - > ( { error = > [ "Cannot find $imagename from the linuximage table." ] , errorcode = > [ 1 ] } ) ;
return ;
}
$ osver = $ ref - > { 'osvers' } ;
$ arch = $ ref - > { 'osarch' } ;
$ profile = $ ref - > { 'profile' } ;
$ syncfile = $ ref - > { 'synclists' } ;
my $ provmethod = $ ref - > { 'provmethod' } ;
unless ( $ osver and $ arch and $ profile and $ provmethod ) {
$ callback - > ( { error = > [ "osimage.osvers, osimage.osarch, osimage.profile and osimage.provmethod must be specified for the image $imagename in the database." ] , errorcode = > [ 1 ] } ) ;
return ;
}
if ( $ provmethod ne 'netboot' ) {
$ callback - > ( { error = > [ "\'$imagename\' cannot be used to build diskless image. Make sure osimage.provmethod is 'netboot'." ] , errorcode = > [ 1 ] } ) ;
return ;
}
$ exlistloc = $ ref1 - > { 'exlist' } ;
$ destdir = $ ref1 - > { 'rootimgdir' } ;
}
if ( ! $ destdir )
{
$ destdir = "$installroot/netboot/$osver/$arch/$profile" ;
}
$ rootimg_dir = "$destdir/rootimg" ;
2008-02-07 18:54:58 +00:00
my $ distname = $ osver ;
2008-02-12 19:10:33 +00:00
until ( - 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 ;
}
2008-02-07 18:54:58 +00:00
unless ( $ installroot ) {
$ callback - > ( { error = > [ "No installdir defined in site table" ] , errorcode = > [ 1 ] } ) ;
return ;
}
my $ oldpath = cwd ( ) ;
2009-09-24 18:51:53 +00:00
if ( ! $ imagename ) {
$ exlistloc = xCAT::SvrUtils - > get_exlist_file_name ( "$installroot/custom/netboot/$distname" , $ profile , $ osver , $ arch ) ;
if ( ! $ exlistloc ) { $ exlistloc = xCAT::SvrUtils - > get_exlist_file_name ( "$::XCATROOT/share/xcat/netboot/$distname" , $ profile , $ osver , $ arch ) ; }
}
2008-09-12 22:40:15 +00:00
2009-09-24 18:51:53 +00:00
#if (!$exlistloc)
#{
# $callback->({data=>["WARNING: Unable to find file exclusion list under $installroot/custom/netboot/$distname or $::XCATROOT/share/xcat/netboot/$distname/ for $profile/$arch/$osver\n"]});
#}
2009-05-19 18:56:27 +00:00
2008-02-07 18:54:58 +00:00
my $ excludestr = "find . " ;
2009-05-19 18:56:27 +00:00
my $ includestr ;
2009-04-13 14:39:55 +00:00
if ( $ exlistloc ) {
my $ exlist ;
2010-04-07 15:14:29 +00:00
my $ excludetext ;
2009-04-13 14:39:55 +00:00
open ( $ exlist , "<" , $ exlistloc ) ;
2009-05-19 18:56:27 +00:00
system ( "echo -n > /tmp/xcat_packimg.txt" ) ;
2009-04-13 14:39:55 +00:00
while ( <$exlist> ) {
2010-04-07 15:14:29 +00:00
$ excludetext . = $ _ ;
}
close ( $ exlist ) ;
2010-04-15 13:06:52 +00:00
2010-04-07 15:14:29 +00:00
#handle the #INLCUDE# tag recursively
my $ idir = dirname ( $ exlistloc ) ;
my $ doneincludes = 0 ;
while ( not $ doneincludes ) {
$ doneincludes = 1 ;
2010-04-15 13:06:52 +00:00
if ( $ excludetext =~ /#INCLUDE:[^#^\n]+#/ ) {
2010-04-07 15:14:29 +00:00
$ doneincludes = 0 ;
2010-04-15 13:06:52 +00:00
$ excludetext =~ s/#INCLUDE:([^#^\n]+)#/include_file($1,$idir)/eg ;
2010-04-07 15:14:29 +00:00
}
2010-04-15 13:06:52 +00:00
2010-04-07 15:14:29 +00:00
}
my @ tmp = split ( "\n" , $ excludetext ) ;
foreach ( @ tmp ) {
chomp $ _ ;
2009-04-13 14:39:55 +00:00
s/\s*#.*// ; #-- remove comments
next if /^\s*$/ ; #-- skip empty lines
2009-05-19 18:56:27 +00:00
if ( /^\+/ ) {
s/^\+// ; #remove '+'
$ includestr . = "-path '" . $ _ . "' -o " ;
} else {
s/^\-// ; #remove '-' if any
$ excludestr . = "'!' -path '" . $ _ . "' -a " ;
}
2009-04-13 14:39:55 +00:00
}
2009-05-19 18:56:27 +00:00
}
$ excludestr =~ s/-a $// ;
if ( $ includestr ) {
$ includestr =~ s/-o $// ;
$ includestr = "find . " . $ includestr ;
}
2010-04-15 13:06:52 +00:00
# print "\nexcludestr=$excludestr\n\n includestr=$includestr\n\n";
2008-04-23 20:03:51 +00:00
2009-05-19 18:56:27 +00:00
# add the xCAT post scripts to the image
2009-09-24 18:51:53 +00:00
if ( ! - d "$rootimg_dir" ) {
$ callback - > ( { error = > [ "$rootimg_dir does not exist, run genimage -o $osver -p $profile on a server with matching architecture" ] } ) ;
2008-05-12 19:41:17 +00:00
return ;
}
2009-04-23 19:12:33 +00:00
#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
2009-09-24 18:51:53 +00:00
`umount $rootimg_dir/proc` ;
copybootscript ( $ installroot , $ rootimg_dir , $ osver , $ arch , $ profile , $ callback ) ;
2008-05-07 14:51:12 +00:00
my $ passtab = xCAT::Table - > new ( 'passwd' ) ;
if ( $ passtab ) {
( my $ pent ) = $ passtab - > getAttribs ( { key = > 'system' , username = > 'root' } , 'password' ) ;
if ( $ pent and defined ( $ pent - > { password } ) ) {
my $ pass = $ pent - > { password } ;
my $ shadow ;
2009-09-24 18:51:53 +00:00
open ( $ shadow , "<" , "$rootimg_dir/etc/shadow" ) ;
2008-06-26 15:41:34 +00:00
my @ shadents = <$shadow> ;
close ( $ shadow ) ;
2009-09-24 18:51:53 +00:00
open ( $ shadow , ">" , "$rootimg_dir/etc/shadow" ) ;
2008-05-07 14:51:12 +00:00
unless ( $ pass =~ /^\$1\$/ ) {
$ pass = crypt ( $ pass , '$1$' . genpassword ( 8 ) ) ;
}
print $ shadow "root:$pass:13880:0:99999:7:::\n" ;
2008-06-26 15:41:34 +00:00
foreach ( @ shadents ) {
unless ( /^root:/ ) {
print $ shadow "$_" ;
}
}
2008-05-07 14:51:12 +00:00
close ( $ shadow ) ;
}
}
2009-07-15 13:08:51 +00:00
# sync fils configured in the synclist to the rootimage
2009-09-24 18:51:53 +00:00
if ( ! $ imagename ) {
$ syncfile = xCAT::SvrUtils - > getsynclistfile ( undef , $ osver , $ arch , $ profile , "netboot" ) ;
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` ;
}
}
2008-04-23 20:03:51 +00:00
2008-04-24 12:47:21 +00:00
my $ verb = "Packing" ;
if ( $ method =~ /nfs/ ) {
2008-04-24 13:34:55 +00:00
$ verb = "Prepping" ;
2008-04-24 12:47:21 +00:00
}
if ( $ method =~ /nfs/ ) {
2009-09-24 18:51:53 +00:00
$ callback - > ( { data = > [ "\nNOTE: Contents of $rootimg_dir\nMUST be available on all service and management nodes and NFS exported." ] } ) ;
2008-04-24 12:47:21 +00:00
}
2008-02-07 18:54:58 +00:00
my $ temppath ;
2008-05-09 15:31:09 +00:00
my $ oldumask ;
2009-09-24 18:51:53 +00:00
if ( ! - d $ rootimg_dir ) {
$ callback - > ( { error = > [ "$rootimg_dir does not exist, run genimage -o $osver -p $profile on a server with matching architecture" ] } ) ;
2008-05-09 15:31:09 +00:00
return ;
}
2009-09-24 18:51:53 +00:00
$ callback - > ( { data = > [ "$verb contents of $rootimg_dir" ] } ) ;
unlink ( "$destdir/rootimg.gz" ) ;
unlink ( "$destdir/rootimg.sfs" ) ;
unlink ( "$destdir/rootimg.nfs" ) ;
2008-02-07 18:54:58 +00:00
if ( $ method =~ /cpio/ ) {
2009-04-13 14:39:55 +00:00
if ( ! $ exlistloc ) {
$ excludestr = "find . |cpio -H newc -o | gzip -c - > ../rootimg.gz" ;
} else {
2009-09-24 18:51:53 +00:00
chdir ( "$rootimg_dir" ) ;
2009-05-19 18:56:27 +00:00
system ( "$excludestr >> /tmp/xcat_packimg.txt" ) ;
if ( $ includestr ) {
system ( "$includestr >> /tmp/xcat_packimg.txt" ) ;
}
#$excludestr =~ s!-a \z!|cpio -H newc -o | gzip -c - > ../rootimg.gz!;
$ excludestr = "cat /tmp/xcat_packimg.txt|cpio -H newc -o | gzip -c - > ../rootimg.gz" ;
2009-04-13 14:39:55 +00:00
}
$ oldmask = umask 0077 ;
2008-02-07 18:54:58 +00:00
} elsif ( $ method =~ /squashfs/ ) {
$ temppath = mkdtemp ( "/tmp/packimage.$$.XXXXXXXX" ) ;
2008-10-09 22:51:57 +00:00
chmod 0755 , $ temppath ;
2009-09-24 18:51:53 +00:00
chdir ( "$rootimg_dir" ) ;
2009-05-19 18:56:27 +00:00
system ( "$excludestr >> /tmp/xcat_packimg.txt" ) ;
if ( $ includestr ) {
system ( "$includestr >> /tmp/xcat_packimg.txt" ) ;
}
2010-04-19 19:17:35 +00:00
$ excludestr = "cat /tmp/xcat_packimg.txt|cpio -dump $temppath" ;
2008-04-24 12:47:21 +00:00
} elsif ( $ method =~ /nfs/ ) {
$ excludestr = "touch ../rootimg.nfs" ;
2008-02-21 20:09:41 +00:00
} else {
$ callback - > ( { error = > [ "Invalid method '$method' requested" ] , errorcode = > [ 1 ] } ) ;
2008-02-07 18:54:58 +00:00
}
2009-09-24 18:51:53 +00:00
chdir ( "$rootimg_dir" ) ;
2008-02-07 18:54:58 +00:00
system ( $ excludestr ) ;
2008-05-09 15:31:09 +00:00
if ( $ method =~ /cpio/ ) {
2009-09-24 18:51:53 +00:00
chmod 0644 , "$destdir/rootimg.gz" ;
2008-05-09 15:31:09 +00:00
umask $ oldmask ;
} elsif ( $ method =~ /squashfs/ ) {
2008-02-07 18:54:58 +00:00
my $ flags ;
if ( $ arch =~ /x86/ ) {
$ flags = "-le" ;
} elsif ( $ arch =~ /ppc/ ) {
$ flags = "-be" ;
}
2008-04-24 13:31:45 +00:00
if ( ! - x "/sbin/mksquashfs" ) {
$ callback - > ( { error = > [ "mksquashfs not found, squashfs-tools rpm should be installed on the management node" ] , errorcode = > [ 1 ] } ) ;
return ;
}
2008-02-28 02:11:40 +00:00
my $ rc = system ( "mksquashfs $temppath ../rootimg.sfs $flags" ) ;
if ( $ rc ) {
$ callback - > ( { error = > [ "mksquashfs could not be run successfully" ] , errorcode = > [ 1 ] } ) ;
return ;
}
2008-05-07 19:48:09 +00:00
$ rc = system ( "rm -rf $temppath" ) ;
if ( $ rc ) {
$ callback - > ( { error = > [ "Failed to clean up temp space" ] , errorcode = > [ 1 ] } ) ;
return ;
}
2008-02-07 18:54:58 +00:00
chmod ( 0644 , "../rootimg.sfs" ) ;
}
2009-09-19 17:03:14 +00:00
chdir ( $ oldpath ) ;
2009-09-24 18:51:53 +00:00
if ( ! $ imagename ) {
my @ ret = xCAT::SvrUtils - > update_tables_with_diskless_image ( $ osver , $ arch , $ profile ) ;
if ( $ ret [ 0 ] != 0 ) {
$ callback - > ( { error = > [ "Error when updating the osimage tables: " . $ ret [ 1 ] ] } ) ;
}
2009-09-19 17:03:14 +00:00
}
2008-02-07 18:54:58 +00:00
}
2008-04-23 20:03:51 +00:00
###########################################################
#
# copybootscript - copy the xCAT diskless init scripts to the image
#
#############################################################
sub copybootscript {
my $ installroot = shift ;
2009-09-24 18:51:53 +00:00
my $ rootimg_dir = shift ;
2008-04-23 20:03:51 +00:00
my $ osver = shift ;
my $ arch = shift ;
my $ profile = shift ;
my $ callback = shift ;
2010-04-04 04:01:05 +00:00
my @ timezone = xCAT::Utils - > get_site_attribute ( "timezone" ) ;
2008-05-01 20:52:16 +00:00
2008-04-23 20:03:51 +00:00
if ( - f "$installroot/postscripts/xcatdsklspost" ) {
# copy the xCAT diskless post script to the image
2009-09-24 18:51:53 +00:00
mkpath ( "$rootimg_dir/opt/xcat" ) ;
2008-04-23 20:03:51 +00:00
2009-09-24 18:51:53 +00:00
copy ( "$installroot/postscripts/xcatdsklspost" , "$rootimg_dir/opt/xcat/xcatdsklspost" ) ;
2010-04-04 04:01:05 +00:00
if ( $ timezone [ 0 ] ) {
copy ( "$rootimg_dir/usr/share/zoneinfo/$timezone[0]" , "$rootimg_dir/etc/localtime" ) ;
}
2008-04-23 20:03:51 +00:00
2009-09-24 18:51:53 +00:00
chmod ( 0755 , "$rootimg_dir/opt/xcat/xcatdsklspost" ) ;
2008-04-23 20:03:51 +00:00
} else {
my $ rsp ;
push @ { $ rsp - > { data } } , "Could not find the script $installroot/postscripts/xcatdsklspost.\n" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
2010-04-04 04:01:05 +00:00
# the following block might need to be removed as xcatdsklspost.aix may no longer be used
2008-05-01 20:52:16 +00:00
if ( - f "$installroot/postscripts/xcatdsklspost.aix" ) {
2009-09-24 18:51:53 +00:00
copy ( "$installroot/postscripts/xcatdsklspost.aix" , "$rootimg_dir/opt/xcat/xcatdsklspost.aix" ) ;
chmod ( 0755 , "$rootimg_dir/opt/xcat/xcatdsklspost.aix" ) ;
2008-05-01 20:52:16 +00:00
}
2008-04-23 20:03:51 +00:00
2010-06-07 19:42:44 +00:00
#if ( -f "$installroot/postscripts/xcatpostinit") {
2008-04-23 20:03:51 +00:00
# copy the linux diskless init script to the image
# - & set the permissions
2010-06-07 19:42:44 +00:00
#copy ("$installroot/postscripts/xcatpostinit","$rootimg_dir/etc/init.d/xcatpostinit");
2008-04-23 20:03:51 +00:00
2010-06-07 19:42:44 +00:00
#chmod(0755,"$rootimg_dir/etc/init.d/xcatpostinit");
2008-04-23 20:03:51 +00:00
# run chkconfig
2009-09-24 18:51:53 +00:00
#my $chkcmd = "chroot $rootimg_dir chkconfig --add xcatpostinit";
2010-06-07 19:42:44 +00:00
#symlink "/etc/init.d/xcatpostinit","$rootimg_dir/etc/rc3.d/S84xcatpostinit";
#symlink "/etc/init.d/xcatpostinit","$rootimg_dir/etc/rc4.d/S84xcatpostinit";
#symlink "/etc/init.d/xcatpostinit","$rootimg_dir/etc/rc5.d/S84xcatpostinit";
2008-05-07 19:11:13 +00:00
#my $rc = system($chkcmd);
#if ($rc) {
#my $rsp;
# push @{$rsp->{data}}, "Could not run the chkconfig command.\n";
# xCAT::MsgUtils->message("E", $rsp, $callback);
# return 1;
# }
2010-06-07 19:42:44 +00:00
#} else {
#my $rsp;
# push @{$rsp->{data}}, "Could not find the script $installroot/postscripts/xcatpostinit.\n";
# xCAT::MsgUtils->message("E", $rsp, $callback);
# return 1;
#}
2008-04-23 20:03:51 +00:00
return 0 ;
}
2010-04-07 15:14:29 +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 ) ;
}