mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@13467 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			409 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			409 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| #!/usr/bin/perl
 | |
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| 
 | |
| package xCAT_plugin::imgcapture;
 | |
| 
 | |
| BEGIN
 | |
| {
 | |
|     $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | |
| }
 | |
| 
 | |
| use lib "$::XCATROOT/lib/perl";
 | |
| 
 | |
| use strict;
 | |
| 
 | |
| use Data::Dumper;   # for debug purpose
 | |
| use Getopt::Long;
 | |
| use xCAT::MsgUtils;
 | |
| use xCAT::Utils;
 | |
| use xCAT::TableUtils;
 | |
| use xCAT::SvrUtils;
 | |
| use xCAT::Table;
 | |
| use File::Path qw(mkpath);
 | |
| 
 | |
| Getopt::Long::Configure("bundling");
 | |
| Getopt::Long::Configure("pass_through");
 | |
| 
 | |
| my $verbose = 0;
 | |
| my $installroot = "/install";
 | |
| 
 | |
| sub handled_commands {
 | |
|     return { "imgcapture" => "imgcapture" };
 | |
| }
 | |
| 
 | |
| sub process_request {
 | |
|     my $request = shift;
 | |
|     my $callback = shift;
 | |
|     my $doreq = shift;
 | |
| 
 | |
|     my $node;
 | |
|     if (exists $request->{node}) {
 | |
|         $node = $request->{node}->[0];
 | |
|     }
 | |
| 
 | |
|     $installroot = xCAT::TableUtils->getInstallDir();
 | |
|     @ARGV = @{$request->{arg}} if (defined $request->{arg});
 | |
|     my $argc = scalar @ARGV;
 | |
| 
 | |
|     my $usage = "Usage: imgcapture <node> [-p | --profile <profile>] [-o|--osimage <osimage>] [-i <nodebootif>] [-n <nodenetdrivers>] [-V | --verbose] \n imgcapture [-h|--help] \n imgcapture [-v|--version]";
 | |
| 
 | |
|     my $os;
 | |
|     my $arch;
 | |
|     my $profile;
 | |
|     my $bootif;
 | |
|     my $netdriver;
 | |
|     my $osimg;
 | |
|     my $help;
 | |
|     my $version;
 | |
| 
 | |
|     GetOptions(
 | |
|         "profile|p=s" => \$profile,
 | |
|         "i=s" => \$bootif,
 | |
|         'n=s' => \$netdriver,
 | |
|         'osimage|o=s' => \$osimg,
 | |
|         "help|h" => \$help,
 | |
|         "version|v" => \$version,
 | |
|         "verbose|V" => \$verbose
 | |
|     );
 | |
| 
 | |
|     if ( defined( $ARGV[0] )) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "Invalid Argument: $ARGV[0]";
 | |
|         $rsp->{data}->[1] = $usage;
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|         return 0;
 | |
|     }
 | |
|     if($version) {
 | |
|         my $version = xCAT::Utils->Version();
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = $version;
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     if($help) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = $usage;
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     if( ! $node ) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = $usage;
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     my $nodetypetab = xCAT::Table->new("nodetype");
 | |
|     my $ref_nodetype = $nodetypetab->getNodeAttribs($node, ['os','arch','profile']);
 | |
|     $os = $ref_nodetype->{os};
 | |
|     $arch = $ref_nodetype->{arch};
 | |
|     unless($profile) {
 | |
|         $profile = $ref_nodetype->{profile};
 | |
|     }
 | |
| 
 | |
|     # -i flag is required with sles genimage
 | |
|     if (!$bootif && $os =~ /^sles/) {
 | |
|         $bootif = "eth0";
 | |
|     }
 | |
|     
 | |
| 
 | |
|     # check whether the osimage exists or not
 | |
|     if($osimg) {
 | |
|         my $osimgtab=xCAT::Table->new('osimage', -create=>1);
 | |
|         unless($osimgtab) {
 | |
|             # the osimage table doesn't exist
 | |
|             my $rsp = {};
 | |
|             $rsp->{data}->[0] = qq{Cannot open the osimage table};
 | |
|             $xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         my $linuximgtab = xCAT::Table->new('linuximage', -create=>1);
 | |
|         unless($linuximgtab) {
 | |
|             # the linuximage table doesn't exist
 | |
|             my $rsp = {};
 | |
|             $rsp->{data}->[0] = qq{Cannot open the linuximage table};
 | |
|             $xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         my ($ref) = $osimgtab->getAttribs({imagename => $osimg}, 'osvers', 'osarch', 'profile');
 | |
|         unless($ref) {
 | |
|             my $rsp = {};
 | |
|             $rsp->{data}->[0] = qq{Cannot find $osimg from the osimage table.};
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         my ($ref1) = $linuximgtab->getAttribs({imagename => $osimg}, 'imagename');
 | |
|         unless($ref1) {
 | |
|             my $rsp = {};
 | |
|             $rsp->{data}->[0] = qq{Cannot find $osimg from the linuximage table};
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         # make sure the "osvers" and "osarch" attributes match the node's attribute
 | |
|         unless($os eq $ref->{'osvers'} and $arch eq $ref->{'osarch'}) {
 | |
|             my $rsp = {};
 | |
|             $rsp->{data}->[0] = qq{The 'osvers' or 'osarch' attribute of the "$osimg" table doesn't match the node's attribute};
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     imgcapture($node, $os, $arch, $profile, $osimg, $bootif, $netdriver, $callback, $doreq);
 | |
| }
 | |
| 
 | |
| sub imgcapture {
 | |
|     my ($node, $os, $arch, $profile, $osimg, $bootif, $netdriver, $callback, $subreq) = @_;
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = "nodename is $node; os is $os; arch is $arch; profile is $profile";
 | |
|         $rsp->{data}->[1] = "bootif is $bootif; netdriver is $netdriver";
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     # make sure the "/" partion is on the disk, 
 | |
|     my $output = xCAT::Utils->runxcmd({command => ["xdsh"], node => [$node], arg =>["stat / -f |grep Type"]}, $subreq, -1, 1);
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{the output of "stat / -f |grep Type" on $node is:};
 | |
|         foreach my $o (@$output) {
 | |
|             push @{$rsp->{data}}, $o;
 | |
|         }
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     if($::RUNCMD_RC) { #failed
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{The "xdsh" command fails to run on the $node};
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     # parse the output of "stat / -f |grep Type", 
 | |
|     $output->[0] =~ m/Type:\s+(.*)$/;
 | |
|     my $fstype =  $1;
 | |
|     if ($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{The file type is $fstype};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     # make sure the rootfs type is not nfs or tmpfs
 | |
|     if($fstype eq "nfs" or $fstype eq "tmpfs") {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{This node might not be diskful Linux node, please check it.};
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     my $distname = $os;
 | |
|     while ( $distname and ( ! -r "$::XCATROOT/share/xcat/netboot/$distname/") ) {
 | |
|         chop($distname);
 | |
|     }
 | |
| 
 | |
|     unless($distname) {
 | |
|         $callback->({error=>["Unable to find $::XCATROOT/share/xcat/netboot directory for $os"], errorcode => [1]});
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     my $exlistloc = xCAT::SvrUtils->get_imgcapture_exlist_file_name("$installroot/custom/netboot/$distname", $profile, $os, $arch);
 | |
|     unless ($exlistloc) {
 | |
|         $exlistloc = xCAT::SvrUtils->get_imgcapture_exlist_file_name("$::XCATROOT/share/xcat/netboot/$distname", $profile, $os, $arch);
 | |
|     }
 | |
| 
 | |
|     my $xcat_imgcapture_tmpfile = "/tmp/xcat_imgcapture.$$";
 | |
| 
 | |
|     my $excludestr = "cd /; find .";
 | |
| 
 | |
|     if($exlistloc) {
 | |
|         my $exlist;
 | |
|         open $exlist, "<", $exlistloc;
 | |
| 
 | |
|         while(<$exlist>) {
 | |
|             $_ =~ s/^\s+//;
 | |
|             chomp $_;
 | |
|             unless($_ =~ m{^#}) {
 | |
|                 $excludestr .= qq{ ! -path "$_"};
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         close $exlist;
 | |
|     } else {
 | |
|         # the following directories must be exluded when capturing the image
 | |
|         my @default_exlist = ("./tmp/*", "./proc/*", "./sys/*", "./dev/*", "./xcatpost/*", "./install/*");
 | |
|         foreach my $item (@default_exlist) {
 | |
|             $excludestr .= qq{ ! -path "$item"};
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     $excludestr .= " |cpio -H newc -o |gzip -c - >$xcat_imgcapture_tmpfile";
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{The excludestr is "$excludestr"};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     # run the command via "xdsh"
 | |
| 
 | |
|     xCAT::Utils->runxcmd({command => ["xdsh"], node => [$node], arg => ["echo -n >$xcat_imgcapture_tmpfile"]}, $subreq, -1, 1);
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{running "echo -n > $xcat_imgcapture_tmpfile" on $node};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     if($::RUNCMD_RC) { # the xdsh command fails
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{The "xdsh" command fails to run "echo -n > $xcat_imgcapture_tmpfile" on $node};
 | |
|         xCAT:MsgUtils->message("E", $rsp, $callback);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     my $rsp = {};
 | |
|     $rsp->{data}->[0] = qq{Capturing image on $node...};
 | |
|     xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
| 
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{running "$excludestr" on $node via the "xdsh" command};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     xCAT::Utils->runxcmd({command => ["xdsh"], node => [$node], arg => [$excludestr]}, $subreq, -1, 1);
 | |
| 
 | |
|     if($::RUNCMD_RC) { # the xdsh command fails
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{The "xdsh" command fails to run "$excludestr" on $node};
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     $rsp = {};
 | |
|     $rsp->{data}->[0] = qq{Transfering the image captured on $node back...};
 | |
|     xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
| 
 | |
|     # copy the image captured on $node back via the "scp" command
 | |
|     xCAT::Utils->runcmd("scp $node:$xcat_imgcapture_tmpfile $xcat_imgcapture_tmpfile");
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{Running "scp $node:$xcat_imgcapture_tmpfile $xcat_imgcapture_tmpfile"};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     if($::RUNCMD_RC) {
 | |
|         my $rsp ={};
 | |
|         $rsp->{data}->[0] = qq{The scp command fails};
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     xCAT::Utils->runxcmd({command => ["xdsh" ], node => [$node], arg => ["rm -f $xcat_imgcapture_tmpfile"]}, $subreq, -1, 1);
 | |
| 
 | |
|     # extract the $xcat_imgcapture_tmpfile file to /install/netboot/$os/$arch/$profile/rootimg
 | |
|     my $rootimgdir = "$installroot/netboot/$os/$arch/$profile/rootimg";
 | |
| 
 | |
|     # empty the rootimg directory before extracting the image captured on the diskful Linux node
 | |
|     if( -d $rootimgdir ) {
 | |
|         unlink $rootimgdir;
 | |
|     }
 | |
|     mkpath($rootimgdir);
 | |
| 
 | |
|     xCAT::Utils->runcmd("cd $rootimgdir; gzip -cd $xcat_imgcapture_tmpfile|cpio -idum");
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{Extracting the image to $rootimgdir};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
|     if($::RUNCMD_RC) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{fails to run the "gzip -cd xx |cpio -idum" command};
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     if($verbose) {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{Creating the spots exluded when capturing on $node...};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     # the next step is to call "genimage"
 | |
|     my $platform = getplatform($os);
 | |
|     if( -e "$::XCATROOT/share/xcat/netboot/$platform/genimage" ) {
 | |
|         my $cmd;
 | |
| 
 | |
|         if( $osimg ) {
 | |
|             $cmd = "$::XCATROOT/bin/genimage $osimg ";
 | |
|         } else {
 | |
|             $cmd = "$::XCATROOT/share/xcat/netboot/$platform/genimage -o $os -a $arch -p $profile ";
 | |
|         }
 | |
| 
 | |
|         if($bootif) {
 | |
|             $cmd .= "-i $bootif ";
 | |
|         }
 | |
|         if($netdriver) {
 | |
|             $cmd .= "-n $netdriver";
 | |
|         }
 | |
| 
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{Generating kernel and initial ramdisks...};
 | |
|         xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
| 
 | |
|         if($verbose) {
 | |
|             my $rsp = {};
 | |
|             $rsp->{data}->[0] = qq{"The genimage command is: $cmd"};
 | |
|             xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
|         }
 | |
|         my @cmdoutput = xCAT::Utils->runcmd($cmd, 0);
 | |
|         if($::RUNCMD_RC) {
 | |
|             my $rsp = {};
 | |
|             foreach (@cmdoutput) {
 | |
|                 push @{$rsp->{data}}, $_;
 | |
|             }
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             unlink $xcat_imgcapture_tmpfile;
 | |
|             return;
 | |
|         }
 | |
|     } else {
 | |
|         my $rsp = {};
 | |
|         $rsp->{data}->[0] = qq{Can't run the "genimage" command for $os};
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     my $rsp = {};
 | |
|     $rsp->{data}->[0] = qq{Done.};
 | |
|     xCAT::MsgUtils->message("D", $rsp, $callback);
 | |
| 
 | |
|     unlink $xcat_imgcapture_tmpfile;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| sub getplatform {
 | |
|     my $os = shift;
 | |
|     my $platform;
 | |
|     if ($os =~ m/rh.*/) {
 | |
|         $platform = "rh";
 | |
|     } elsif ($os =~ m/centos.*/) {
 | |
|         $platform = "centos";
 | |
|     } elsif ($os =~ m/fedora.*/) {
 | |
|         $platform = "fedora";
 | |
|     } elsif ($os =~ m/SL.*/) {
 | |
|         $platform = "SL";
 | |
|     } elsif ($os =~ m/sles.*/) {
 | |
|         $platform = "sles";
 | |
|     } elsif ($os =~ m/suse.*/) {
 | |
|         $platform = "suse";
 | |
|     }
 | |
| 
 | |
|     return $platform;
 | |
| }
 | |
| 
 | |
| 1;
 |