From 82cbce395cccc5e29530eca3e202d0bd0750ea97 Mon Sep 17 00:00:00 2001 From: mellor Date: Thu, 22 May 2008 18:57:51 +0000 Subject: [PATCH] XCATBYPASS calls preprocess_request, updated copies of subroutines stolen from xcatd git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@1484 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT-2.0/xCAT/Client.pm | 207 ++++++++++++++++++++++++++++++++--- 1 file changed, 191 insertions(+), 16 deletions(-) diff --git a/perl-xCAT-2.0/xCAT/Client.pm b/perl-xCAT-2.0/xCAT/Client.pm index 51c8e2830..cc4903962 100644 --- a/perl-xCAT-2.0/xCAT/Client.pm +++ b/perl-xCAT-2.0/xCAT/Client.pm @@ -20,6 +20,7 @@ unless ($inet6support) { eval { require IO::Socket::INET }; } + use XML::Simple; if ($^O =~ /^linux/i) { $XML::Simple::PREFERRED_PARSER='XML::Parser'; @@ -164,8 +165,8 @@ sub submit_request { # will load all plugin perl modules and build a list of supported # commands # -# NOTE: This is copied from xcatd (last merge 10/3/07). -# Will eventually move to using common source.... +# NOTE: This is copied from xcatd (last merge 5/21/08). +# TODO: Will eventually move to using common source.... ################################### sub scan_plugins { my @plugins=glob($plugins_dir."/*.pm"); @@ -204,8 +205,8 @@ sub scan_plugins { # plugin_command # will invoke the correct plugin # -# NOTE: This is copied from xcatd (last merge 10/3/07). -# Will eventually move to using common source.... +# NOTE: This is copied from xcatd (last merge 5/21/08). +# TODO: Will eventually move to using common source.... ################################### sub plugin_command { my $req = shift; @@ -225,10 +226,11 @@ sub plugin_command { my @nodes; if ($req->{node}) { @nodes = @{$req->{node}}; - } elsif ($req->{noderange}) { + } elsif ($req->{noderange} and $req->{noderange}->[0]) { @nodes = xCAT::NodeRange::noderange($req->{noderange}->[0]); if (xCAT::NodeRange::nodesmissed()) { # my $rsp = {errorcode=>1,error=>"Invalid nodes in noderange:".join(',',xCAT::NodeRange::nodesmissed)}; + my $rsp->{serverdone} = {}; print "Invalid nodes in noderangex:".join(',',xCAT::NodeRange::nodesmissed())."\n"; # if ($sock) { # print $sock XMLout($rsp,RootName=>'xcatresponse' ,NoAttr=>1); @@ -236,14 +238,23 @@ sub plugin_command { # return ($rsp); return 1; } + unless (@nodes) { + $req->{emptynoderange} = [1]; + } } if (@nodes) { $req->{node} = \@nodes; } + my %unhandled_nodes; + foreach (@nodes) { + $unhandled_nodes{$_}=1; + } + my $useunhandled=0; if (defined($cmd_handlers{$req->{command}->[0]})) { my $hdlspec; foreach (@{$cmd_handlers{$req->{command}->[0]}}) { $hdlspec =$_->[1]; my $ownmod = $_->[0]; if ($hdlspec =~ /:/) { #Specificed a table lookup path for plugin name + $useunhandled=1; my $table; my $cols; ($table,$cols) = split(/:/,$hdlspec); @@ -266,6 +277,9 @@ sub plugin_command { } } + unless (@nodes) { #register the plugin in the event of usage + $handler_hash{$ownmod} = 1; + } foreach $node (@nodes) { my $attribs = $hdlrtable->getNodeAttribs($node,\@columns); unless (defined($attribs)) { next; } #TODO: This really ought to craft an unsupported response for this request @@ -275,15 +289,18 @@ sub plugin_command { if ($colvals->{$col}) { #A pattern match style request. if ($attribs->{$col} =~ /$colvals->{$col}/) { $handler_hash{$ownmod}->{$node} = 1; + delete $unhandled_nodes{$node}; last; } } else { $handler_hash{$attribs->{$col}}->{$node} = 1; + delete $unhandled_nodes{$node}; last; } } } } + $hdlrtable->close; } else { unless (@nodes) { $handler_hash{$hdlspec} = 1; @@ -297,10 +314,29 @@ sub plugin_command { print "$req->{command}->[0] xCAT command not found \n"; return 1; #TODO: error back that request has no known plugin for it } + if ($useunhandled) { + my $queuelist; + foreach (@{$cmd_handlers{$req->{command}->[0]}->[0]}) { + unless (/:/) { + next; + } + $queuelist .= "$_,"; + } + $queuelist =~ s/,$//; + $queuelist =~ s/:/./g; + foreach (keys %unhandled_nodes) { +# if ($sock) { +# print $sock XMLout({node=>[{name=>[$_],data=>["Unable to identify plugin for this command, check relevant tables: $queuelist"],errorcode=>[1]}]},NoAttr=>1,RootName=>'xcatresponse'); +# } else { + $callback->({node=>[{name=>[$_],data=>['Unable to identify plugin for this command, check relevant tables'],errorcode=>[1]}]}); +# } + } + } ## FOR NOW, DON'T FORK CHILD PROCESS TO MAKE BYPASS SIMPLER AND EASIER TO DEBUG -# my $children=0; -# $SIG{CHLD} = sub {while (waitpid(-1, WNOHANG) > 0) { $children--; } }; +# $plugin_numchildren=0; +# %plugin_children=(); +# $SIG{CHLD} = \&plugin_reaper; #sub {my $plugpid; while (($plugpid = waitpid(-1, WNOHANG)) > 0) { if ($plugin_children{$plugpid}) { delete $plugin_children{$plugpid}; $plugin_numchildren--; } } }; # my $check_fds; # if ($sock) { # $check_fds = new IO::Select; @@ -309,39 +345,50 @@ sub plugin_command { my $modname = $_; if (-r $plugins_dir."/".$modname.".pm") { require $plugins_dir."/".$modname.".pm"; -# $children++; +# $plugin_numchildren++; # my $pfd; #will be referenced for inter-process messaging. +# my $parfd; #not causing a problem that I discern yet, but theoretically # my $child; # if ($sock) { #If $sock not passed in, don't fork.. -# socketpair($pfd, $parent_fd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!"; +# socketpair($pfd, $parfd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!"; # #pipe($pfd,$cfd); -# $parent_fd->autoflush(1); +# $parfd->autoflush(1); # $pfd->autoflush(1); -# $child = fork; +# $child = xCAT::Utils->xfork; # } else { # $child = 0; # } # unless (defined $child) { die "Fork failed"; } # if ($child == 0) { +# $parent_fd = $parfd; + my $oldprogname=$$progname; + $$progname=$oldprogname.": $modname instance"; # if ($sock) { close $pfd; } unless ($handler_hash{$_} == 1) { my @nodes = sort {($a =~ /(\d+)/)[0] <=> ($b =~ /(\d+)/)[0] || $a cmp $b } (keys %{$handler_hash{$_}}); $req->{node}=\@nodes; } no strict "refs"; - ${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request); +# if ($dispatch_requests) { + dispatch_request($req,$callback,$modname); +# } else { +# undef $SIG{CHLD}; +# ${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request); +# } + $$progname=$oldprogname; # if ($sock) { # close($parent_fd); -# exit(0); +# xexit(0); # } # } else { -# close $parent_fd; +# $plugin_children{$child}=1; +# close $parfd; # $check_fds->add($pfd); # } } } unless ($sock) { return $Main::resps }; -# while ($children > 0) { +# while (($plugin_numchildren > 0) and ($check_fds->count > 0)) { #this tracks end of useful data from children much more closely # relay_fds($check_fds,$sock); # } # #while (relay_fds($check_fds,$sock)) {} @@ -355,11 +402,139 @@ sub plugin_command { + +################################### +# dispatch_request +# dispatch the requested command +# +# NOTE: This is copied from xcatd (last merge 5/21/08). +# All we really need from this subroutine is to call preprocess_request +# and to only run the command for nodes handled by the local server +# Will eventually move to using common source.... +################################### +sub dispatch_request { +# %dispatched_children=(); + my $req = shift; + $dispatch_cb = shift; + + my $modname = shift; + my $reqs = []; +# my $child_fdset = new IO::Select; + no strict "refs"; + + #Hierarchy support. Originally, the default scope for noderange commands was + #going to be the servicenode associated unless overriden. + #However, assume for example that you have blades and a blade is the service node + #rpower being executed by the servicenode for one of its subnodes would have to + #reach it's own management module. This has the potential to be non-trivial for some quite possible network configurations. + #Since plugins may commonly experience this, a preprocess_request implementation + #will for now be required for a command to be scaled through service nodes + #If the plugin offers a preprocess method, use it to set the request array + if (defined(${"xCAT_plugin::".$modname."::"}{preprocess_request})) { + undef $SIG{CHLD}; + $reqs = ${"xCAT_plugin::".$modname."::"}{preprocess_request}->($req,$dispatch_cb,\&do_request); + } else { #otherwise, pass it in without hierarchy support + $reqs = [$req]; + } + +# $dispatch_children=0; +# $SIG{CHLD} = \&dispatch_reaper; #sub {my $cpid; while (($cpid =waitpid(-1, WNOHANG)) > 0) { if ($dispatched_children{$cpid}) { delete $dispatched_children{$cpid}; $dispatch_children--; } } }; + foreach (@{$reqs}) { +# my $pfd; +# my $parfd; #use a private variable so it won't trounce itself recursively +# my $child; + delete $_->{noderange}; +#----- added to Client.pm -----# + if ($_->{node}) { + $_->{noderange}->[0]=join(',',@{$_->{node}}); + } +# socketpair($pfd, $parfd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!"; +# $parfd->autoflush(1); +# $pfd->autoflush(1); +# $child = xCAT::Utils->xfork; +# if ($child) { +# $dispatch_children++; +# $dispatched_children{$child}=1; +# $child_fdset->add($pfd); +# next; +# } +# unless (defined $child) { +# $dispatch_cb->({error=>['Fork failure dispatching request'],errorcode=>[1]}); +# } +# undef $SIG{CHLD}; +# $dispatch_parentfd = $parfd; + if ($_->{'_xcatdest'} and thishostisnot($_->{'_xcatdest'})) { +#----- added to Client.pm -----# + $dispatch_cb->({warning=>['XCATBYPASS is set, skipping hierarchy call to '.$_->{'_xcatdest'}.'']}); + +# $ENV{XCATHOST} = ( $_->{'_xcatdest'} =~ /:/ ? $_->{'_xcatdest'} : $_->{'_xcatdest'}.":3001" ); +# $$progname.=": connection to ".$ENV{XCATHOST}; +# eval { +# undef $_->{'_xcatdest'}; +# xCAT::Client::submit_request($_,\&dispatch_callback,$xcatdir."/cert/server-cred.pem",$xcatdir."/cert/server-cred.pem",$xcatdir."/cert/ca.pem"); +# }; +# if ($@) { +# dispatch_callback({error=>["Error dispatching command to ".$ENV{XCATHOST}.""],errorcode=>[1]}); +# syslog("local4|err","Error dispatching request: ".$@); +# } + } else { + $$progname.=": locally executing"; + undef $SIG{CHLD}; + ${"xCAT_plugin::".$modname."::"}{process_request}->($_,$dispatch_cb,\&do_request); + } +# xexit; + } +#while (($dispatch_children > 0) and ($child_fdset->count > 0)) { relay_dispatch($child_fdset) } +#while (relay_dispatch($child_fdset)) { } #Potentially useless drain. +} + + + + +################################### +# thishostisnot +# does the requested IP belong to this local host? +# +# NOTE: This is copied from xcatd (last merge 5/21/08). +# Will eventually move to using common source.... +################################### +sub thishostisnot { + my $comparison = shift; + + # use "ip addr" for linux, since ifconfig + # doesn't list "ip addr add" aliases for linux + # + my $cmd = ($^O !~ /^aix/i) ? "/sbin/ip addr" : "ifconfig -a"; + my @ips = split /\n/,`$cmd`; +#### +# TODO: AIX will hang on the inet_aton call if it gets passed an IPv6 +# address, since we have not added INET6 support to AIX yet. +# The ifconfig -a output may contain an IPv6 address for localhost. +# This code should only get called if using hierarchy, which +# is also not supported for AIX yet. +#### + my $comp=IO::Socket::inet_aton($comparison); + foreach (@ips) { + if (/^\s*inet/) { + my @ents = split(/\s+/); + my $ip=$ents[2]; + $ip =~ s/\/.*//; + if (IO::Socket::inet_aton($ip) eq $comp) { + return 0; + } + } + } + return 1; +} + + + + ################################### # do_request # called from a plugin to execute another xCAT plugin command internally # -# NOTE: This is copied from xcatd (last merge 10/3/07). +# NOTE: This is copied from xcatd (last merge 5/21/08). # Will eventually move to using common source.... ################################### sub do_request {