From 05c9e4b58fcbb3c12fbeeaadaa36a9de71d5c0e6 Mon Sep 17 00:00:00 2001 From: daniceexi Date: Thu, 4 Jun 2009 15:33:44 +0000 Subject: [PATCH] The first phase code drop for CFM like funtion git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@3514 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT/xCAT/Utils.pm | 124 +++++++++++++++++++++ xCAT-server/lib/perl/xCAT/Postage.pm | 43 +++++++ xCAT-server/lib/xcat/plugins/syncfiles.pm | 67 +++++++++++ xCAT-server/lib/xcat/plugins/updatenode.pm | 82 +++++++++++++- xCAT-server/sbin/xcatd | 4 + xCAT/postscripts/remoteshell | 4 + xCAT/postscripts/startsyncfiles.awk | 24 ++++ xCAT/postscripts/syncfiles | 69 ++++++++++++ xCAT/postscripts/xcataixpost | 7 ++ xCAT/postscripts/xcatdsklspost | 8 ++ 10 files changed, 427 insertions(+), 5 deletions(-) create mode 100644 xCAT-server/lib/xcat/plugins/syncfiles.pm create mode 100755 xCAT/postscripts/startsyncfiles.awk create mode 100644 xCAT/postscripts/syncfiles diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm index 83aa46d69..03e431059 100644 --- a/perl-xCAT/xCAT/Utils.pm +++ b/perl-xCAT/xCAT/Utils.pm @@ -3959,4 +3959,128 @@ sub checkCredFiles } + +#----------------------------------------------------------------------------- + + +=head3 getsynclistfile + Get the synclist file for the nodes; + The arguments $os,$arch,$profile,$insttype are only available when no $nodes is specified + + Arguments: + $nodes + $os + $arch + $profile + $insttype - installation type (can be install or netboot) + Returns: + When specified $nodes: reference of a hash of node=>synclist + Otherwise: full path of the synclist file + Globals: + none + Error: + Example: + my $node_syncfile=xCAT::Utils->getsynclistfile($nodes); + my $syncfile=xCAT::Utils->getsynclistfile(undef, 'sles11', 'ppc64', 'compute', 'netboot'); + Comments: + none + +=cut + +#----------------------------------------------------------------------------- + + + +sub getsynclistfile() +{ + my $nodes = shift; + if (($nodes) && ($nodes =~ /xCAT::Utils/)) + { + $nodes = shift; + } + + my ($os, $arch, $profile, $inst_type) = @_; + + # if does not specify the $node param, default consider for genimage command + if ($nodes) { + my %node_syncfile = (); + + my %node_insttype = (); + my %insttype_node = (); + # get the nodes installation type + xCAT::SvrUtils->getNodesetStates($nodes, \%insttype_node); + # convert the hash to the node=>type + foreach my $type (keys %insttype_node) { + foreach my $node (@{$insttype_node{$type}}) { + $node_insttype{$node} = $type; + } + } + + # get the os,arch,profile attributes for the nodes + my $nodetype_t = xCAT::Table->new('nodetype'); + unless ($nodetype_t) { + return ; + } + my $nodetype_v = $nodetype_t->getNodesAttribs($nodes, ['profile','os','arch']); + + foreach my $node (@$nodes) { + $inst_type = $node_insttype{$node}; + if ($inst_type eq "netboot" || $inst_type eq "diskless") { + $inst_type = "netboot"; + } else { + $inst_type = "install"; + } + + $profile = $nodetype_v->{$node}->[0]->{'profile'}; + $os = $nodetype_v->{$node}->[0]->{'os'}; + $arch = $nodetype_v->{$node}->[0]->{'arch'}; + + my $platform = ""; + if ($os) { + if ($os =~ /rh.*/) { $platform = "rh"; } + elsif ($os =~ /centos.*/) { $platform = "centos"; } + elsif ($os =~ /fedora.*/) { $platform = "fedora"; } + elsif ($os =~ /sles.*/) { $platform = "sles"; } + elsif ($os =~ /AIX.*/) { $platform = "AIX"; } + } + + my $base = "/install/custom/$inst_type/$platform"; + if (-r "$base/$profile.$os.$arch.synclist") { + $node_syncfile{$node} = "$base/$profile.$os.$arch.synclist"; + } elsif (-r "$base/$profile.$arch.synclist") { + $node_syncfile{$node} = "$base/$profile.$arch.synclist"; + } elsif (-r "$base/$profile.$os.synclist") { + $node_syncfile{$node} = "$base/$profile.$os.synclist"; + } elsif (-r "$base/$profile.synclist") { + $node_syncfile{$node} = "$base/$profile.synclist"; + } + } + + return \%node_syncfile; + } else { + my $platform = ""; + if ($os) { + if ($os =~ /rh.*/) { $platform = "rh"; } + elsif ($os =~ /centos.*/) { $platform = "centos"; } + elsif ($os =~ /fedora.*/) { $platform = "fedora"; } + elsif ($os =~ /sles.*/) { $platform = "sles"; } + elsif ($os =~ /AIX.*/) { $platform = "AIX"; } + } + + my $base = "/install/custom/$inst_type/$platform"; + if (-r "$base/$profile.$os.$arch.synclist") { + return "$base/$profile.$os.$arch.synclist"; + } elsif (-r "$base/$profile.$arch.synclist") { + return "$base/$profile.$arch.synclist"; + } elsif (-r "$base/$profile.$os.synclist") { + return "$base/$profile.$os.synclist"; + } elsif (-r "$base/$profile.synclist") { + return "$base/$profile.synclist"; + } + + } + +} + + 1; diff --git a/xCAT-server/lib/perl/xCAT/Postage.pm b/xCAT-server/lib/perl/xCAT/Postage.pm index 83f870abe..851a75a4b 100644 --- a/xCAT-server/lib/perl/xCAT/Postage.pm +++ b/xCAT-server/lib/perl/xCAT/Postage.pm @@ -228,6 +228,9 @@ sub makescript { push @scriptd, "NODESETSTATE=".$nodesetstate."\n"; push @scriptd, "export NODESETSTATE\n"; + # set the UPDATENODE flag in the script, the default it 0, that means not in the updatenode process + push @scriptd, "UPDATENODE=0\n"; + push @scriptd, "export UPDATENODE\n"; # see if this is a service or compute node? if (xCAT::Utils->isSN($node) ) { @@ -356,4 +359,44 @@ sub get_otherpkg_file_name { return ""; } +#---------------------------------------------------------------------------- + +=head3 syncfiles + + Use the xdcp command to sync files from Management node/Service node to the Compute node + + Arguments: + Returns: 0 - failed; 1 - succeeded; + Example: + xCAT::Postage->syncfiles($node, $callback); + + Comments: + +=cut + +#----------------------------------------------------------------------------- +sub syncfiles { + my $node = shift; + if ($node =~ /xCAT::Postage/) { + $node = shift; + } + my $callback = shift; + my $subreq = shift; + + #get the sync file base on the node type + my $synclist = xCAT::Utils->getsynclistfile([$node]); + if (!$synclist) { + xCAT::MsgUtils->message("S", "Cannot find synclist file for the $node"); + return 0; + } + + # call the xdcp plugin to handle the syncfile operation + my $args = ["-F", "$$synclist{$node}"]; + my $env = ["DSH_RSYNC_FILE=$$synclist{$node}"]; + $subreq->({command=>['xdcp'], node=>[$node], arg=>$args, env=>$env}, $callback); + + return 1; +} + + 1; diff --git a/xCAT-server/lib/xcat/plugins/syncfiles.pm b/xCAT-server/lib/xcat/plugins/syncfiles.pm new file mode 100644 index 000000000..cf1011eff --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/syncfiles.pm @@ -0,0 +1,67 @@ +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +#------------------------------------------------------- + +=head1 + xCAT plugin package to handle syncfiles command + +=cut + +#------------------------------------------------------- +package xCAT_plugin::syncfiles; +use xCAT::Utils; +use xCAT::MsgUtils; +use xCAT::NodeRange; + +1; + +#------------------------------------------------------- + +=head3 handled_commands + +Return list of commands handled by this plugin + +=cut + +#------------------------------------------------------- + +sub handled_commands +{ + return {'syncfiles' => "syncfiles"}; +} + + +#------------------------------------------------------- + +=head3 process_request + + Process the command + +=cut + +#------------------------------------------------------- +sub process_request +{ + my $request = shift; + my $callback = shift; + my $subreq = shift; + + my $client; + if ($request->{'_xcat_clienthost'}) { + $client = $request->{'_xcat_clienthost'}->[0]; + } + + if ($client) { ($client) = noderange($client) }; + unless ($client) { #Not able to do identify the host in question + xCAT::MsgUtils->message("S","Received syncfiles from $client, which couldn't be correlated to a node (domain mismatch?)"); + return; + } + + require xCAT::Postage; + my $rc = xCAT::Postage->syncfiles($client,$callback,$subreq); + if ($rc) { + xCAT::MsgUtils->message("S","Sync files to node $client completed"); + } else { + xCAT::MsgUtils->message("S","Encountered error when using xdcp sync files to $client"); + } +} + diff --git a/xCAT-server/lib/xcat/plugins/updatenode.pm b/xCAT-server/lib/xcat/plugins/updatenode.pm index 2d3bcc26d..3a2c4beab 100644 --- a/xCAT-server/lib/xcat/plugins/updatenode.pm +++ b/xCAT-server/lib/xcat/plugins/updatenode.pm @@ -56,13 +56,14 @@ sub preprocess_request { my $request = shift; my $callback = shift; + my $subreq = shift; my $command = $request->{command}->[0]; if ($request->{_xcatdest}) { return [$request]; } #exit if preprocessed my @requests=(); if ($command eq "updatenode") { - return preprocess_updatenode($request, $callback); + return preprocess_updatenode($request, $callback, $subreq); } elsif ($command eq "updatenodestat") { return [$request]; } @@ -89,11 +90,12 @@ sub process_request { my $request = shift; my $callback = shift; + my $subreq = shift; my $command = $request->{command}->[0]; my $localhostname=hostname(); if ($command eq "updatenode") { - return updatenode($request, $callback); + return updatenode($request, $callback, $subreq); } elsif ($command eq "updatenodestat") { return updatenodestat($request, $callback); } else { @@ -112,7 +114,7 @@ sub process_request Arguments: request - the request. The request->{arg} is of the format: [-h|--help|-v|--version] or - [noderange [postscripts]] + [noderange [-s | -S] [postscripts]] callback - the pointer to the callback function. Returns: A pointer to an array of requests. @@ -121,6 +123,7 @@ sub process_request sub preprocess_updatenode { my $request = shift; my $callback = shift; + my $subreq = shift; my $args=$request->{arg}; my @requests=(); @@ -130,7 +133,7 @@ sub preprocess_updatenode { my $cb=shift; my $rsp={}; $rsp->{data}->[0]= "Usage:"; - $rsp->{data}->[1]= " updatenode [posts]"; + $rsp->{data}->[1]= " updatenode [-s | -S] [posts]"; $rsp->{data}->[2]= " updatenode [-h|--help|-v|--version]"; $rsp->{data}->[3]= " noderange is a list of nodes or groups."; $rsp->{data}->[4]= " posts is a comma separated list of postscript names."; @@ -149,7 +152,9 @@ sub preprocess_updatenode { Getopt::Long::Configure("no_pass_through"); if(!GetOptions( 'h|help' => \$::HELP, - 'v|version' => \$::VERSION)) + 'v|version' => \$::VERSION, + 's' => \$::SYNCSN, + 'S' => \$::SKIPSYNCFILE )) { &updatenode_usage($callback); return \@requests;; @@ -198,6 +203,52 @@ sub preprocess_updatenode { # build an individual request for each service node my $sn = xCAT::Utils->get_ServiceNode(\@nodes, "xcat", "MN"); + # If -s argument specified, sync files to the service node firstly + if ($::SYNCSN) { + my @MNnodeinfo = xCAT::Utils->determinehostname; + my $MNnodename = pop @MNnodeinfo; # hostname + my @MNnodeipaddr = @MNnodeinfo; # ipaddresses + + my $node_syncfile = xCAT::Utils->getsynclistfile($nodes); + my %syncfile_sn = (); + foreach my $snkey (keys %$sn) + { + # exclude the Management node + if (grep(/$snkey/, @MNnodeipaddr)) { + next; + } + my @synclists = (); + # Figure out the synclist files for the service node + foreach my $node (@{$sn->{$snkey}}) { + my $synclist = $$node_syncfile{$node}; + + unless ($synclist) { + next; + } + if (! grep /\Q$synclist\E/, @synclists) { + push @synclists, $synclist; + push @{$syncfile_sn{$synclist}}, $node; + } + } + + # If there are multiple synclist files for certain SN, + # the synclist files maybe have conflicted content, so + # display an warning message + if ($#synclists > 0) { + my $rsp = {}; + my $files = join(',', @synclists); + $rsp->{data}->[0]= "Warning: The Service Node $snkey will be synced by following synclist files: $files"; + $callback->($rsp); + } + } + + foreach my $syncfile (keys %syncfile_sn) { + my $arg = ["-s", "-F", "$syncfile"]; + my $env = ["RSYNCSN=yes", "DSH_RSYNC_FILE=$syncfile"]; + $subreq->({command=>['xdcp'], node=>$syncfile_sn{$syncfile}, arg=>$arg, env=>$env}, $callback); + } + } + # build each request for each service node foreach my $snkey (keys %$sn) { @@ -227,11 +278,32 @@ sub preprocess_updatenode { sub updatenode { my $request = shift; my $callback = shift; + my $subreq = shift; my $postscripts=""; if (($request->{postscripts}) && ($request->{postscripts}->[0])) { $postscripts=$request->{postscripts}->[0];} my $nodes =$request->{node}; my $localhostname=hostname(); + # if not specifying -S, do the sync file operation + unless ($::SKIPSYNCFILE) { + my %syncfile_node = (); + my $node_syncfile = xCAT::Utils->getsynclistfile($nodes); + foreach my $node (@$nodes) { + my $synclist = $$node_syncfile{$node}; + + if ($synclist) { + push @{$syncfile_node{$synclist}}, $node; + next; + } + } + + foreach my $synclist (keys %syncfile_node) { + my $args = ["-F", "$synclist"]; + my $env = ["DSH_RSYNC_FILE=$synclist"]; + $subreq->({command=>['xdcp'], node=>$syncfile_node{$synclist}, arg=>$args, env=>$env}, $callback); + } + } + my $nodestring=join(',', @$nodes); #print "postscripts=$postscripts, nodestring=$nodestring\n"; diff --git a/xCAT-server/sbin/xcatd b/xCAT-server/sbin/xcatd index eb736d04a..8bbf727e9 100755 --- a/xCAT-server/sbin/xcatd +++ b/xCAT-server/sbin/xcatd @@ -257,6 +257,10 @@ if ($inet6support) { } print $conn "#END OF SCRIPT\n"; close($conn); + } elsif ($text =~ /^syncfiles/) { + plugin_command({command=>['syncfiles'],_xcat_clienthost=>[$node]},undef,\&build_response); + print $conn "syncfiles done\n"; + close($conn); } elsif ($text =~ /^rebootnodes/) { my @cmdargs = split(/\s+/,$text); my $rebootcmd = shift(@cmdargs); diff --git a/xCAT/postscripts/remoteshell b/xCAT/postscripts/remoteshell index cefc429e0..c04791199 100755 --- a/xCAT/postscripts/remoteshell +++ b/xCAT/postscripts/remoteshell @@ -143,4 +143,8 @@ fi if [ -r /root/.ssh/id_rsa ]; then ssh-keygen -y -f /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub fi + +# start up the sshd for syncfiles postscript to do the sync work +service sshd start + kill -9 $CREDPID diff --git a/xCAT/postscripts/startsyncfiles.awk b/xCAT/postscripts/startsyncfiles.awk new file mode 100755 index 000000000..e4e122473 --- /dev/null +++ b/xCAT/postscripts/startsyncfiles.awk @@ -0,0 +1,24 @@ +#!/usr/bin/awk -f +BEGIN { + if (ENVIRON["USEOPENSSLFORXCAT"]) { + server = "openssl s_client -quiet -connect " ENVIRON["XCATSERVER"] + } else { + server = "/inet/tcp/0/127.0.0.1/400" + } + + quit = "no" + + print "" |& server + print " syncfiles" |& server + print "" |& server + + while (server |& getline) { + if (match($0,"")) { + quit = "yes" + } + if (match($0,"") && match(quit,"yes")) { + close(server) + exit + } + } +} diff --git a/xCAT/postscripts/syncfiles b/xCAT/postscripts/syncfiles new file mode 100644 index 000000000..234e0a0f6 --- /dev/null +++ b/xCAT/postscripts/syncfiles @@ -0,0 +1,69 @@ +#!/usr/bin/perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +##################################################### +# +# xCAT post script for configuration files distribution +# +# It should be run after the remoteshell +# It is also run by the updatenode cmd +# +##################################################### + + +# do nothing when UPDATENODE=1 +if ($ENV{'UPDATENODE'} == 1 + || $ENV{'NODESETSTATE'} eq "netboot" + || $ENV{'NODESETSTATE'} eq "diskless") { + exit 0; +} + +`logger -t xCAT "Performing syncfiles postscript"`; + +# get platform +my $osname = `uname`; +chomp $osname; + +# run the xdcp on the MN/SN +my $xcatpostdir = "/xcatpost"; +my $startsync = ""; +if ($osname eq "Linux") { +`logger -t xCAT "run $xcatpostdir/startsyncfiles.awk"`; + $startsync = "$xcatpostdir/startsyncfiles.awk"; + `$startsync`; +} else { +`logger -t xCAT "run $xcatpostdir/startsyncfilesaix.awk"`; + &startsyncfilesaix(); +} + +exit 0; + + +sub startsyncfilesaix +{ + use IO::Socket; + + my $port = "3002"; + my $remote = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $ENV{'MASTER'}, PeerPort => $port, ); + unless ($remote) { + `logger -t xCAT "startsyncfiles: Cannot connect to host $ENV{'MASTER'}"`; + } + + $remote->autoflush(1); + + while (<$remote>) { + my $line = $_; + chomp($line); + + if ($line =~ /ready/) { + print $remote "syncfiles\n"; + } + + if ($line =~ /syncfiles done/) { + close $remote; + return 0; + } + } + + close $remote; + return 0; +} diff --git a/xCAT/postscripts/xcataixpost b/xCAT/postscripts/xcataixpost index 8031f2d72..52f8d1563 100755 --- a/xCAT/postscripts/xcataixpost +++ b/xCAT/postscripts/xcataixpost @@ -153,6 +153,13 @@ if (-f $scriptname) { my $nodesetstat="standalone"; if (-f $scriptname) { + # when called by the updatenode command, + #modify the UPDATENODE flag to 1 + if (@ARGV > 0) { + $TMP=`sed -e 's/UPDATENODE=0/UPDATENODE=1/g' $scriptname`; + `echo "$TMP" > $scriptname`; + } + if (@ARGV>1) { my $scripts=$ARGV[1]; my $POSTS=join('\n', split(',', $scripts)); diff --git a/xCAT/postscripts/xcatdsklspost b/xCAT/postscripts/xcatdsklspost index 680cc4384..7ab4bfe96 100755 --- a/xCAT/postscripts/xcatdsklspost +++ b/xCAT/postscripts/xcatdsklspost @@ -88,6 +88,14 @@ while [ -z "$MYCONT" ]; do MYCONT=`cat /tmp/mypostscript` # echo "MYCONT=$MYCONT" done + +# when called by the updatenode command, +#modify the UPDATENODE flag to 1 +if [ $# -gt 0 ]; then + TMP=`sed -e 's/UPDATENODE=0/UPDATENODE=1/g' /tmp/mypostscript`; + echo "$TMP" > /tmp/mypostscript; +fi + if [ $# -gt 1 ]; then POSTS=$2 #remove all the postscripts