Added the new command "imgcapture" to svn trunk.
please run "man imgcapture" for more information. git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@9076 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
		
							
								
								
									
										101
									
								
								xCAT-client/pods/man1/imgcapture.1.pod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								xCAT-client/pods/man1/imgcapture.1.pod
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| =head1 NAME | ||||
|  | ||||
| B<imgcapture> - Captures an image from one running diskful Linux node, prepares the rootimg directory, kernel and initial ramdisks for the B<liteimg>/B<packimage> command to generate the statelite/stateless rootimg. | ||||
|  | ||||
| =head1 SYNOPSIS | ||||
|  | ||||
| B<imgcapture> node [B<-p>|B<--profile> I<profile>] [B<-i> I<nodebootif>] [B<-n> I<nodenetdrivers>] [B<-V>|B<--verbose>] | ||||
|  | ||||
| B<imgcapture> [B<-h> | B<--help>] | [B<-v> | B<--version>] | ||||
|  | ||||
| =head1 DESCRIPTION | ||||
|  | ||||
| The B<imgcapture> command will capture an image from one running diskful Linux node, prepares the rootimg directory, kernel and initial rmadisks for the B<liteimg>/B<packimage> command to generate the statelite/stateless rootimg. | ||||
|  | ||||
| The B<node> should be one diskful Linux node, managed by the xCAT MN, and the remote shell between MN and the B<node> should have been configured. AIX is not supported.  | ||||
|  | ||||
| The B<osver>, B<arch> and B<profile> attributes for the stateless/statelite image to be created are duplicated from the B<node>'s attribute. If the B<-p|--profile> I<profile> option is specified, the image will be created under "/<I<installroot>>/netboot/<osver>/<arch>/<I<profile>>/rootimg".  | ||||
|  | ||||
| The default files/directories excluded in the image are specified by /opt/xcat/share/xcat/netboot/<os>/<I<profile>>.<osver>.<arch>.imgcapture.exlist; also, you can put your customized file (<I<profile>>.<osver>.<arch>.imgcapture.exlist) to /install/custom/netboot/<osplatform>. The directories in the default I<.imgcapture.exlist> file are necessary to capture image from the diskful Linux node managed by xCAT, please don't remove it. | ||||
|  | ||||
| The image captured will be extracted into the /<I<installroot>>/netboot/<B<osver>>/<B<arch>>/<B<profile>>/rootimg directory.  | ||||
|  | ||||
| After the B<imgcapture> command returns without any errors, you can customize the rootimg and run the B<liteimg>/B<packimage> command for your own request. | ||||
|  | ||||
| =head1 OPTIONS | ||||
|  | ||||
| =over 12 | ||||
|  | ||||
| =item B<-p|--profile> I<profile>  | ||||
|  | ||||
| assign I<profile> as the profile of the image to be created. | ||||
|  | ||||
| =item B<-i> I<nodebootif> | ||||
|  | ||||
| The network interface the diskless node will boot over (e.g. eth0), which is used by the B<genimage> command to generate initial ramdisks. | ||||
|  | ||||
| This is optional. | ||||
|  | ||||
| =item B<-n> I<nodenetdrivers> | ||||
|  | ||||
| The driver modules needed for the network interface, which is used by the B<genimage> command to generate initial ramdisks. | ||||
|  | ||||
| This is optional. By default, the B<genimage> command can provide drivers for the following network interfaces: | ||||
|  | ||||
| For x86 or x86_64 platform: | ||||
|  | ||||
|     tg3 bnx2 bnx2x e1000 e1000e igb m1x_en | ||||
|  | ||||
| For ppc64 platform: | ||||
|  | ||||
|     e1000 e1000e igb ibmveth ehea | ||||
|  | ||||
| For S390x: | ||||
|  | ||||
|     qdio ccwgroup | ||||
|  | ||||
| If the network interface is not in the above list, you'd better specify the driver modules with this option. | ||||
|  | ||||
| =item B<-h|--help>  | ||||
|  | ||||
| Display the usage message. | ||||
|  | ||||
| =item B<-v|--version> | ||||
|  | ||||
| Display the version. | ||||
|  | ||||
| =item B<-V|--verbose> | ||||
|  | ||||
| Verbose output. | ||||
|  | ||||
| =back | ||||
|  | ||||
| =head1 RETRUN VALUE | ||||
|  | ||||
| 0 The command completed sucessfully. | ||||
|  | ||||
| 1 An error has occurred. | ||||
|  | ||||
| =head1 EXAMPLES | ||||
|  | ||||
| B<node1> is one diskful Linux node, which is managed by xCAT. | ||||
|  | ||||
| 1. In order to create the image, run the following command: | ||||
|  | ||||
|     imgcapture node1 | ||||
|  | ||||
| 2. In order to create the image with B<hpc> as profile, run the command: | ||||
|  | ||||
|     imgcapture node1 -p hpc | ||||
|  | ||||
| 3. Create the image: its profile is B<hpc>, and the network interface the diskless node will boot over is B<eth0>, the driver modules for this network interface is B<e1000e>. | ||||
|  | ||||
|     imgcapture node1 -p hpc -i eth0 -n e1000e | ||||
|   | ||||
| =head1 FILES | ||||
|  | ||||
| /opt/xcat/bin/imgcapture | ||||
|  | ||||
| =head1 SEE ALSO | ||||
|  | ||||
| L<genimage(1)|genimage.1>, L<imgimport(1)|imgimport.1>, L<imgexport(1)|imgexport.1>, L<packimage(1)|packimage.1>, L<liteimg(1)|liteimg.1> | ||||
| @@ -143,6 +143,7 @@ ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/lsflexnode | ||||
| ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/rmflexnode | ||||
| ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/mkflexnode | ||||
| ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/lsslp | ||||
| ln -sf ../bin/xcatclient $RPM_BUILD_ROOT/%{prefix}/bin/imgcapture | ||||
| ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/bin/nodegrpch | ||||
| ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/tabdump | ||||
| ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/tabprune | ||||
|   | ||||
| @@ -477,6 +477,16 @@ sub get_exlist_file_name { | ||||
|     return xCAT::SvrUtils::get_file_name($searchpath, "exlist", @_); | ||||
| } | ||||
|  | ||||
| # for the "imgcapture" command | ||||
|  | ||||
| sub get_imgcapture_exlist_file_name { | ||||
|     my $searchpath = shift; | ||||
|     if ($searchpath and $searchpath =~ m/xCAT::SvrUtils/) { | ||||
|         $searchpath = shift; | ||||
|     } | ||||
|     return xCAT::SvrUtils::get_file_name($searchpath, "imgcapture.exlist", @_); | ||||
| } | ||||
|  | ||||
|  | ||||
| #------------------------------------------------------------------------------- | ||||
|  | ||||
|   | ||||
| @@ -615,7 +615,7 @@ sub mknetboot | ||||
|         #} | ||||
|         # append the mac address | ||||
|         my $mac; | ||||
|         if( $useifname && $machash->{$node}->[0] && $machash->{$node}->[0]->{'mac'}) { | ||||
|         if($machash->{$node}->[0] && $machash->{$node}->[0]->{'mac'}) { | ||||
|             # TODO: currently, only "mac" attribute with classic style is used, the "|" delimited string of "macaddress!hostname" format is not used | ||||
|             $mac = $machash->{$node}->[0]->{'mac'}; | ||||
|             if ( (index($mac, "|") eq -1) and (index($mac, "!") eq -1) ) { | ||||
|   | ||||
							
								
								
									
										324
									
								
								xCAT-server/lib/xcat/plugins/imgcapture.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								xCAT-server/lib/xcat/plugins/imgcapture.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,324 @@ | ||||
| #!/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::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::Utils->getInstallDir(); | ||||
|     @ARGV = @{$request->{arg}} if (defined $request->{arg}); | ||||
|     my $argc = scalar @ARGV; | ||||
|  | ||||
|     my $usage = "Usage: imgcapture <node> [-p | --profile <profile>] [-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 $help; | ||||
|     my $version; | ||||
|  | ||||
|     GetOptions( | ||||
|         "profile|p=s" => \$profile, | ||||
|         "i=s" => \$bootif, | ||||
|         'n=s' => \$netdriver, | ||||
|         "help|h" => \$help, | ||||
|         "version|v" => \$version, | ||||
|         "verbose|V" => \$verbose | ||||
|     ); | ||||
|  | ||||
|     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}; | ||||
|     } | ||||
|      | ||||
|     imgcapture($node, $os, $arch, $profile, $bootif, $netdriver, $callback, $doreq); | ||||
| } | ||||
|  | ||||
| sub imgcapture { | ||||
|     my ($node, $os, $arch, $profile, $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+//; | ||||
|             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; | ||||
|     } | ||||
|  | ||||
|     xCAT::Utils->runxcmd({command => ["xdsh"], node => [$node], arg => [$excludestr]}, $subreq, -1, 1); | ||||
|     if($verbose) { | ||||
|         my $rsp = {}; | ||||
|         $rsp->{data}->[0] = qq{running "$excludestr" on $node via the "xdsh" command}; | ||||
|         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 "$excludestr" on $node}; | ||||
|         xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     # 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; | ||||
|     } | ||||
|  | ||||
|     # 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); | ||||
|     } | ||||
|  | ||||
|     my @spotslist = ("/tmp/", "/proc/", "/sys/", "/dev/"); | ||||
|  | ||||
|     if($verbose) { | ||||
|         my $rsp = {}; | ||||
|         $rsp->{data}->[0] = qq{The spots to be restored in the image are:}; | ||||
|         foreach (@spotslist) { | ||||
|             push @{$rsp->{data}}, $_; | ||||
|         } | ||||
|         xCAT::MsgUtils->message("D", $rsp, $callback); | ||||
|     } | ||||
|     # create the directories listed in @spotslist in the rootimg | ||||
|     foreach my $path (@spotslist) { | ||||
|         mkpath("$rootimgdir$path"); | ||||
|     }    | ||||
|  | ||||
|     # the next step is to call "genimage" | ||||
|     my $platform = getplatform($os); | ||||
|     if( -e "$::XCATROOT/share/xcat/netboot/$platform/genimage" ) { | ||||
|         my $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); | ||||
|         } | ||||
|         xCAT::Utils->runcmd($cmd); | ||||
|     } else { | ||||
|         my $rsp = {}; | ||||
|         $rsp->{data}->[0] = qq{Can't run the "genimage" command for $os}; | ||||
|         xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
|         return; | ||||
|     } | ||||
|     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; | ||||
		Reference in New Issue
	
	Block a user