diff --git a/xCAT-server/lib/xcat/plugins/rescanplugins.pm b/xCAT-server/lib/xcat/plugins/rescanplugins.pm new file mode 100644 index 000000000..207eb594d --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/rescanplugins.pm @@ -0,0 +1,194 @@ +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +#------------------------------------------------------- + +=head1 + xCAT plugin package to tell xcatd daemon to rescan plugin directory + + Supported command: + rescanplugins->rescanplugins + +=cut + +#------------------------------------------------------- +package xCAT_plugin::rescanplugins; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl"; +use xCAT::Utils; +use xCAT::MsgUtils; +use Getopt::Long; +use strict; +1; + +#------------------------------------------------------- + +=head3 handled_commands + +Return list of commands handled by this plugin + +=cut + +#------------------------------------------------------- + +sub handled_commands +{ + return {rescanplugins => "rescanplugins"}; +} + +#------------------------------------------------------- + +=head3 preprocess_request + + If hierarchy, send request to xcatd on service nodes + +=cut + +#------------------------------------------------------- +sub preprocess_request +{ + my $req = shift; + my $callback = shift; + my $subreq = shift; + $::CALLBACK=$callback; + my $args = $req->{arg}; + my $envs = $req->{env}; + + + #if already preprocessed, go straight to request + if (($req->{_xcatpreprocessed}) and + ($req->{_xcatpreprocessed}->[0] == 1) ) { return [$req]; } + + + # do your processing here + # return info + if ($args) { + @ARGV = @{$args}; # get arguments + } + Getopt::Long::Configure("posix_default"); + Getopt::Long::Configure("no_gnu_compat"); + Getopt::Long::Configure("bundling"); + my %options = (); + if ( + !GetOptions( + 'h|help' => \$options{'help'}, + 's|servicenodes' => \$options{'servicenodes'}, + 'v|version' => \$options{'version'}, + 'V|Verbose' => \$options{'verbose'} + ) + ) + { + &usage; + exit 1; + } + + if ($options{'help'}) + { + &usage; + exit 0; + } + + if ($options{'version'}) + { + my $version = xCAT::Utils->Version(); + #$version .= "\n"; + my $rsp={}; + $rsp->{data}->[0] = $version; + xCAT::MsgUtils->message("I",$rsp,$callback, 0); + exit 0; + } + + + if ( @ARGV && $ARGV[0] ) { + my $rsp={}; + $rsp->{data}->[0] = "Ignoring arguments ". join(',',@ARGV); + xCAT::MsgUtils->message("I",$rsp,$callback, 0); + } + + if ( $req->{node} && $req->{node}->[0] ) { + my $rsp={}; + $rsp->{data}->[0] = "Ignoring nodes ". join(',',@{$req->{node}}); + xCAT::MsgUtils->message("I",$rsp,$callback, 0); + $req->{node}=[]; + } + + if ($options{'servicenodes'}) { + + # Run rescanplugins on MN and all service nodes + # build an individual request for each service node + my @requests; + my $MNreq = {%$req}; + $MNreq->{_xcatpreprocessed}->[0] = 1; + push @requests, $MNreq; + + foreach my $sn (xCAT::ServiceNodeUtils->getAllSN()) + { + my $SNreq = {%$req}; + $SNreq->{'_xcatdest'} = $sn; + $SNreq->{_xcatpreprocessed}->[0] = 1; + push @requests, $SNreq; + + } + return \@requests; # return requests for all Service nodes + } + + return [$req]; +} + +#------------------------------------------------------- + +=head3 process_request + + Process the command + +=cut + +#------------------------------------------------------- +sub process_request +{ + my $req = shift; + my $callback = shift; + my $subreq = shift; + + # The xcatd daemon should intercept this command and process it directly + + print "in rescanplugins->process_request -- xcatd should process this request directly. WE SHOULD NEVER GET HERE \n"; + my $rsp={}; + $rsp->{data}->[0] = "in rescanplugins->process_request: xcatd should process this request directly. WE SHOULD NEVER GET HERE"; + xCAT::MsgUtils->message("I", $rsp, $callback, 0); + return; + +} +#------------------------------------------------------------------------------- + +=head3 + usage + + puts out usage message for help + + Arguments: + None + + Returns: + + Globals: + + Error: + None + + +=cut + +#------------------------------------------------------------------------------- + +sub usage +{ +## usage message + my $usagemsg = " rescanplugins [-h|--help] \n rescanplugins [-v|--version] \n rescanplugins [-s|--servicenodes]\n"; +### end usage mesage + my $rsp = {}; + $rsp->{data}->[0] = $usagemsg; + xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); + return; +} diff --git a/xCAT-server/sbin/xcatd b/xCAT-server/sbin/xcatd index be95c4e6a..f2cad92f7 100755 --- a/xCAT-server/sbin/xcatd +++ b/xCAT-server/sbin/xcatd @@ -749,6 +749,8 @@ sleep 0.05; sub scan_plugins { my $serialdest = shift; + my $rescan = shift; + %cmd_handlers=(); my @plugins=glob($plugins_dir."/*.pm"); foreach (@plugins) { /.*\/([^\/]*).pm$/; @@ -784,14 +786,16 @@ sub scan_plugins { } } } - foreach (@plugins) { - no strict 'refs'; - /.*\/([^\/]*).pm$/; - my $modname = $1; - unless (defined(${"xCAT_plugin::".$modname."::"}{init_plugin})) { - next; + if ( ! $rescan ) { + foreach (@plugins) { + no strict 'refs'; + /.*\/([^\/]*).pm$/; + my $modname = $1; + unless (defined(${"xCAT_plugin::".$modname."::"}{init_plugin})) { + next; + } + ${"xCAT_plugin::".$modname."::"}{init_plugin}->(\&do_request); } - ${"xCAT_plugin::".$modname."::"}{init_plugin}->(\&do_request); } if ($serialdest) { store_fd(\%cmd_handlers,$serialdest); }; #print $serialdest freeze(\%cmd_handlers); }; } @@ -977,6 +981,17 @@ xCAT::NotifHandler::setup($$, $dbmaster); #start the monitoring process xCAT_monitoring::monitorctrl::start($$); +# Set up communication pipe to have subcommand process be able to reload the +# cmd_handlers hash and pass it back to this parent when rescanplugins requested +my $chreadpipe; +my $chwritepipe; +if ( !(socketpair($chreadpipe, $chwritepipe,AF_UNIX,SOCK_STREAM,PF_UNSPEC)) ) { + xCAT::MsgUtils->message("S", "socketpair failed: $!"); +} +my $chrselect = new IO::Select; +$chrselect->add($chreadpipe); + + my $peername; my $ssltimeout; my $retry=1; @@ -1075,6 +1090,14 @@ until ($quit) { $listenwatcher->can_read(0.1); #when next connection tries to come in or a tenth of a second, whichever comes first next; #just keep pulling things off listen queue onto our own } + # before we fork, check to see if rescanplugins was previously processed and + # we now have a new cmd_handlers hash to refresh + my @chdata; + if (@chdata = $chrselect->can_read(0)) { + foreach my $chd (@chdata) { + %cmd_handlers = %{fd_retrieve($chd)}; + } + } #we have a pending connection and we are under the threshold, grab one from the list and process it... my $cnnection=shift @pendingconnections; #my $previous = select ($cnnection); #assure that perl buffering is not in play at the low level @@ -1421,7 +1444,13 @@ sub plugin_command { dispatch_request($req,$callback,$modname); } else { $SIG{CHLD}='DEFAULT'; - ${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request); + # Call the plugin to process the command request + # rescanplugins request gets handled directly here in xcatd + if ($req->{command}->[0] eq 'rescanplugins') { + scan_plugins($chwritepipe,'1'); + } else { + ${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request); + } } $$progname=$oldprogname; }; #REMOVEEVALFORDEBUG @@ -1509,7 +1538,13 @@ sub plugin_command { dispatch_request($req,$callback,$modname); } else { $SIG{CHLD}='DEFAULT'; - ${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request); + # Call the plugin to process the command request + # rescanplugins request gets handled directly here in xcatd + if ($req->{command}->[0] eq 'rescanplugins') { + scan_plugins($chwritepipe,'1'); + } else { + ${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request); + } } $$progname=$oldprogname; $parent_fd = $org_parent_fd; @@ -1735,7 +1770,13 @@ sub dispatch_request { $SIG{CHLD}='DEFAULT'; "" =~ m/()/; #clear $1 that we may have sitting around if ($_->{'_xcatdelay'} and not ref $_->{'_xcatdelay'}) { sleep $_->{'_xcatdelay'}; } - ${"xCAT_plugin::".$modname."::"}{process_request}->($_,$dispatch_cb,\&do_request); + # Call the plugin to process the command request + # rescanplugins request gets handled directly here in xcatd + if ($_->{command}->[0] eq 'rescanplugins') { + scan_plugins($chwritepipe,'1'); + } else { + ${"xCAT_plugin::".$modname."::"}{process_request}->($_,$dispatch_cb,\&do_request); + } return; } @@ -1818,7 +1859,13 @@ sub dispatch_request { } else { $$progname.=": locally executing"; $SIG{CHLD}='DEFAULT'; - ${"xCAT_plugin::".$modname."::"}{process_request}->($_,\&dispatch_callback,\&do_request); + # Call the plugin to process the command request + # rescanplugins request gets handled directly here in xcatd + if ($_->{command}->[0] eq 'rescanplugins') { + scan_plugins($chwritepipe,'1'); + } else { + ${"xCAT_plugin::".$modname."::"}{process_request}->($_,\&dispatch_callback,\&do_request); + } last; } } @@ -1852,6 +1899,7 @@ sub do_request { } } + #my $sock = shift; #If no sock, will return a response hash if ($cmd_handlers{$req->{command}->[0]}) { return plugin_command($req,$sock,$rsphandler);