mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 11:22:27 +00:00 
			
		
		
		
	support invoking prescripts once for each nodes at the same time
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@5690 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
		| @@ -846,18 +846,25 @@ prescripts => { | ||||
|   # Do not put description text past column 88, so it displays well in a 100 char wide window. | ||||
|   # ----------------------------------------------------------------------------------| | ||||
| 	begin =>  | ||||
|    "The scripts to be run at the beginning of the nodeset (Linux) command.\n\n".  | ||||
|    "The scripts to be run at the beginning of the nodeset (Linux) command.\n".  | ||||
|    " The format is:\n". | ||||
|    "   [action1:]s1,s2...[|action2:s3,s4,s5...]\n". | ||||
|    " where:\n". | ||||
|    "  - action1 and action2 are the nodeset/nimnodeset actions specified in the command\n". | ||||
|    "  - s1 and s2 are the scripts to run for action1 in order\n". | ||||
|    "  - s3, s4, and s5 are the scripts to run for actions2\n\n". | ||||
|    "  - s3, s4, and s5 are the scripts to run for actions2\n". | ||||
|    " If actions are omitted, the scripts apply to all actions.\n". | ||||
|    " All the scripts should be copied to /install/prescripts directory.\n\n". | ||||
|    " Examples:\n". | ||||
|    "   myscript1,myscript2\n". | ||||
|    "   install:myscript1,myscript2|netboot:myscript3", | ||||
|    "   install:myscript1,myscript2|netboot:myscript3\n\n". | ||||
|    " All the scripts should be copied to /install/prescripts directory.\n". | ||||
|    " The following two environment variables will be passed to each script: \n". | ||||
|    "   NODES a coma separated list of node names that need to run the script for\n". | ||||
|    "   ACTION current nodeset action.\n\n". | ||||
|    " If '#xCAT setting:MAX_INSTANCE=number' is specified in the script, the script\n". | ||||
|    " will get invoked for each node in parallel, but no more than number of instances\n". | ||||
|    " will be invoked at at a time. If it is not sepcified, the script will be invoked\n". | ||||
|    " once for all the nodes.\n", | ||||
|     end => "The scripts to be run at the end of the nodeset (Linux) command. The format is the same as the 'begin' column.", | ||||
| 	comments => 'Any user-written notes.', | ||||
| 	disable => "Set to 'yes' or '1' to comment out this row.", | ||||
|   | ||||
| @@ -30,7 +30,8 @@ B<nodeset> only sets the next boot state, but does not reboot. | ||||
| B<nodeset>  is  called  by rinstall and winstall and is also called by the | ||||
| installation process remotely to set the boot state back to "boot". | ||||
|  | ||||
| User can supply their own scripts to be run on the mn or on the service node (if their is hierarchy) for a node during the nodeset command. Such scripts are called B<prescripts>. They should be copied to /install/prescripts dirctory. A table called I<prescripts> is used to specify the scripts and their associated actions. The scripts to be run at the beginning of the nodeset command are stored in the 'begin' column of I<prescripts> table. The scripts to be run at the end of the noodeset command are stored in the 'end' column of I<prescripts> table. Please run 'tabdump prescripts -d' command for details. The following two environment variables will be passed to each script: NODES contains all the names of the nodes that need to run the script for and ACTION contains the current nodeset action. | ||||
| User can supply their own scripts to be run on the mn or on the service node (if their is hierarchy) for a node during the nodeset command. Such scripts are called B<prescripts>. They should be copied to /install/prescripts dirctory. A table called I<prescripts> is used to specify the scripts and their associated actions. The scripts to be run at the beginning of the nodeset command are stored in the 'begin' column of I<prescripts> table. The scripts to be run at the end of the noodeset command are stored in the 'end' column of I<prescripts> table. Please run 'tabdump prescripts -d' command for details. The following two environment variables will be passed to each script: NODES contains all the names of the nodes that need to run the script for and ACTION contains the current nodeset action. If I<#xCAT setting:MAX_INSTANCE=number> is specified in the script, the script will get invoked for each node in parallel, but no more than I<number> of instances will be invoked at at a time. If it is not sepcified, the script will be invoked once for all the nodes. | ||||
|  | ||||
|  | ||||
| =head1 B<Options> | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,10 @@ require xCAT::Utils; | ||||
| require xCAT::MsgUtils; | ||||
| use Getopt::Long; | ||||
| use Sys::Hostname; | ||||
| use Time::HiRes qw(gettimeofday sleep); | ||||
| use POSIX "WNOHANG"; | ||||
|  | ||||
|  | ||||
| 1; | ||||
|  | ||||
| #------------------------------------------------------- | ||||
| @@ -158,26 +162,43 @@ sub runbeginpre | ||||
| 	my $runnodes=$script_hash{$scripts}; | ||||
|         if ($runnodes && (@$runnodes>0)) { | ||||
| 	    my $runnodes_s=join(',', @$runnodes); | ||||
| 	    my $rsp = {}; | ||||
| 	    $rsp->{data}->[0]="$localhostname: Running begin scripts $scripts for nodes $runnodes_s."; | ||||
| 	    $callback->($rsp); | ||||
|  | ||||
| 	    #now run the scripts  | ||||
| 	    undef $SIG{CHLD}; | ||||
| 	    my @script_array=split(',', $scripts); | ||||
|             foreach my $s (@script_array) { | ||||
| 		my $ret=`NODES=$runnodes_s ACTION=$action $installdir/prescripts/$s 2>&1`; | ||||
| 		my $err_code=$?; | ||||
| 		if ($ret) { | ||||
| 		    my $rsp = {}; | ||||
| 		    $rsp->{data}->[0]="$localhostname: $s: $ret"; | ||||
| 		    $callback->($rsp); | ||||
| 		my $rsp = {}; | ||||
| 		$rsp->{data}->[0]="$localhostname: Running begin script $s for nodes $runnodes_s."; | ||||
| 		$callback->($rsp); | ||||
|  | ||||
|                 #check if the script need to be invoked for each node in parallel.  | ||||
|                 #script must contian a line like this in order to be run this way: #xCAT setting: MAX_INSTANCE=4 | ||||
|                 #where 4 is the maximum instance at a time | ||||
|                 my $max_instance=0;  | ||||
|                 my $ret=`grep -E '#+xCAT setting: *MAX_INSTANCE=' $installdir/prescripts/$s`; | ||||
|                 if ($? == 0) { | ||||
| 		   $max_instance=`echo "$ret" | cut -d= -f2`;  | ||||
|                    chomp($max_instance); | ||||
| 		} | ||||
| 		if ($err_code != 0) { | ||||
| 		    $rsp = {}; | ||||
| 		    $rsp->{error}->[0]="$localhostname: $s: return code=$err_code. Error message=$ret"; | ||||
| 		    $callback->($rsp); | ||||
| 		    #last; | ||||
|                  | ||||
|                 if ($max_instance > 0) { | ||||
| 		    #run the script for each node in paralell, no more than max_instance at a time | ||||
| 		    run_script_single_node($installdir, $s,$action,$max_instance,$runnodes,$callback); | ||||
| 		} else {  | ||||
| 		    undef $SIG{CHLD}; | ||||
|                     #pass all the nodes to the script, only invoke the script once | ||||
| 		    my $ret=`NODES=$runnodes_s ACTION=$action $installdir/prescripts/$s 2>&1`; | ||||
| 		    my $err_code=$?; | ||||
| 		    if ($err_code != 0) { | ||||
| 			my $rsp = {}; | ||||
| 			$rsp->{error}->[0]="$localhostname: $s: return code=$err_code. Error message=$ret"; | ||||
| 			$callback->($rsp); | ||||
| 		    } else { | ||||
| 			if ($ret) { | ||||
| 			    my $rsp = {}; | ||||
| 			    $rsp->{data}->[0]="$localhostname: $s: $ret"; | ||||
| 			    $callback->($rsp); | ||||
| 			} | ||||
| 		    } | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
| @@ -206,26 +227,41 @@ sub runendpre | ||||
| 	    my $runnodes_s=join(',', @$runnodes); | ||||
|             my %runnodes_hash=(); | ||||
|  | ||||
| 	    my $rsp = {}; | ||||
| 	    $rsp->{data}->[0]="$localhostname: Running end scripts $scripts for nodes $runnodes_s."; | ||||
| 	    $callback->($rsp); | ||||
|  | ||||
| 	    #now run the scripts  | ||||
| 	    undef $SIG{CHLD}; | ||||
| 	    my @script_array=split(',', $scripts); | ||||
|             foreach my $s (@script_array) { | ||||
| 		my $ret=`NODES=$runnodes_s ACTION=$action $installdir/prescripts/$s 2>&1`; | ||||
| 		my $err_code=$?; | ||||
| 		if ($ret) { | ||||
| 		    my $rsp = {}; | ||||
| 		    $rsp->{data}->[0]="$localhostname: $s: $ret"; | ||||
| 		    $callback->($rsp); | ||||
| 		my $rsp = {}; | ||||
| 		$rsp->{data}->[0]="$localhostname: Running end script $s for nodes $runnodes_s."; | ||||
| 		$callback->($rsp); | ||||
|  | ||||
|                 #check if the script need to be invoked for each node in parallel.  | ||||
|                 #script must contian a line like this in order to be run this way: #xCAT setting: MAX_INSTANCE=4 | ||||
|                 #where 4 is the maximum instance at a time | ||||
|                 my $max_instance=0;  | ||||
|                 my $ret=`grep -E '#+xCAT setting: *MAX_INSTANCE=' $installdir/prescripts/$s`; | ||||
|                 if ($? == 0) { | ||||
| 		   $max_instance=`echo "$ret" | cut -d= -f2`;  | ||||
|                    chomp($max_instance); | ||||
| 		} | ||||
| 		if ($err_code != 0) { | ||||
| 		    $rsp = {}; | ||||
| 		    $rsp->{error}->[0]="$localhostname: $s: return code=$err_code. Error message=$ret"; | ||||
| 		    $callback->($rsp); | ||||
| 		    #last; | ||||
|                  | ||||
|                 if ($max_instance > 0) { | ||||
| 		    #run the script for each node in paralell, no more than max_instance at a time | ||||
| 		    run_script_single_node($installdir, $s,$action,$max_instance,$runnodes,$callback); | ||||
| 		} else {  | ||||
| 		    undef $SIG{CHLD}; | ||||
| 		    my $ret=`NODES=$runnodes_s ACTION=$action $installdir/prescripts/$s 2>&1`; | ||||
| 		    my $err_code=$?; | ||||
| 		    if ($err_code != 0) { | ||||
| 			my $rsp = {}; | ||||
| 			$rsp->{error}->[0]="$localhostname: $s: return code=$err_code. Error message=$ret"; | ||||
| 			$callback->($rsp); | ||||
| 		    } else { | ||||
| 			if ($ret) { | ||||
| 			    my $rsp = {}; | ||||
| 			    $rsp->{data}->[0]="$localhostname: $s: $ret"; | ||||
| 			    $callback->($rsp); | ||||
| 			} | ||||
| 		    } | ||||
| 		} | ||||
| 	    } | ||||
| 	} | ||||
| @@ -324,3 +360,70 @@ sub  parseprescripts | ||||
|     } | ||||
|     return $ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| #------------------------------------------------------- | ||||
| =head3  run_script_single_node | ||||
|     | ||||
| =cut | ||||
| #------------------------------------------------------- | ||||
| sub  run_script_single_node | ||||
| { | ||||
|     my $installdir=shift; #/install | ||||
|     my $s=shift;  #script name | ||||
|     my $action=shift; | ||||
|     my $max=shift;  #max number of instances to be run at a time | ||||
|     my $nodes=shift; #nodes to be run | ||||
|     my $callback=shift; #callback | ||||
|      | ||||
|     my $children=0; | ||||
|     my $localhostname=hostname(); | ||||
|      | ||||
|     foreach my $node ( @$nodes ) { | ||||
| 	$SIG{CHLD} = sub { my $pid = 0; while (($pid = waitpid(-1, WNOHANG)) > 0) {  $children--; } }; | ||||
| 	 | ||||
| 	while ( $children >= $max ) { | ||||
| 	    Time::HiRes::sleep(0.5); | ||||
| 	    next; | ||||
| 	} | ||||
| 	 | ||||
| 	my $pid = xCAT::Utils->xfork; | ||||
| 	if ( !defined($pid) ) { | ||||
| 	    # Fork error | ||||
| 	    my $rsp = {}; | ||||
| 	    $rsp->{data}->[0]="$localhostname: Fork error before running script $s for node $node"; | ||||
| 	    $callback->($rsp); | ||||
| 	    return 1; | ||||
| 	} | ||||
| 	elsif ( $pid == 0 ) { | ||||
| 	    # Child process | ||||
| 	    undef $SIG{CHLD}; | ||||
| 	    my $ret=`NODES=$node ACTION=$action $installdir/prescripts/$s 2>&1`; | ||||
| 	    my $err_code=$?; | ||||
| 	    my $rsp = {}; | ||||
| 	    if ($err_code != 0) { | ||||
| 		$rsp = {}; | ||||
| 		$rsp->{error}->[0]="$localhostname: $s: node=$node. return code=$err_code. Error message=$ret"; | ||||
| 		$callback->($rsp); | ||||
| 	    } else { | ||||
| 		if ($ret) { | ||||
| 		    $rsp->{data}->[0]="$localhostname: $s: node=$node. $ret"; | ||||
| 		    $callback->($rsp); | ||||
| 		} | ||||
| 	    }     | ||||
| 	    exit $err_code; | ||||
| 	} | ||||
| 	else { | ||||
| 	    # Parent process | ||||
| 	    $children++; | ||||
| 	} | ||||
|     } | ||||
|      | ||||
|     #drain one more time | ||||
|     while ($children > 0) { | ||||
| 	Time::HiRes::sleep(0.5); | ||||
| 	 | ||||
| 	$SIG{CHLD} = sub { my $pid = 0; while (($pid = waitpid(-1, WNOHANG)) > 0) { $children--; } }; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user