From 6ff1602d8e216a3fac2eb287897695364aa5ccd3 Mon Sep 17 00:00:00 2001 From: linggao Date: Mon, 8 Sep 2008 18:54:30 +0000 Subject: [PATCH] added feature to install extra 3rd party rpms during cluster install process or after the fact (usning updatenode command). git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@2099 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT/xCAT/Postage.pm | 67 ++++- xCAT-server/lib/xcat/plugins/updatenode.pm | 323 +++++++++++++++++++++ xCAT/postscripts/otherrpms | 70 +++++ xCAT/postscripts/xcatdsklspost | 32 +- 4 files changed, 489 insertions(+), 3 deletions(-) create mode 100644 xCAT-server/lib/xcat/plugins/updatenode.pm create mode 100755 xCAT/postscripts/otherrpms diff --git a/perl-xCAT/xCAT/Postage.pm b/perl-xCAT/xCAT/Postage.pm index 257d7de80..ae24d267b 100644 --- a/perl-xCAT/xCAT/Postage.pm +++ b/perl-xCAT/xCAT/Postage.pm @@ -5,6 +5,12 @@ use xCAT::MsgUtils; use xCAT::NodeRange; use Data::Dumper; use strict; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; +} +use lib "$::XCATROOT/lib/perl"; + #------------------------------------------------------------------------------- =head1 Postage @@ -158,15 +164,22 @@ sub makescript { return undef; } } + + my $os; + my $profile; + my $arch; if ($et->{'os'}) { + $os=$et->{'os'}; push @scriptd, "OSVER=".$et->{'os'}."\n"; push @scriptd, "export OSVER\n"; } if ($et->{'arch'}) { + $arch=$et->{'arch'}; push @scriptd, "ARCH=".$et->{'arch'}."\n"; push @scriptd, "export ARCH\n"; } if ($et->{'profile'}) { + $profile=$et->{'profile'}; push @scriptd, "PROFILE=".$et->{'profile'}."\n"; push @scriptd, "export PROFILE\n"; } @@ -198,12 +211,58 @@ sub makescript { push @scriptd, "export $_\n"; } + #get packge names for extra rpms + if ($profile) { + my $platform="rh"; + 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 $stat="install"; + if (($nodesetstate) && ($nodesetstate eq "netboot")) { $stat="netboot";} + my $pathtofiles="$::XCATROOT/share/xcat/$stat/$platform"; + my $pkglist; + if (-r "$pathtofiles/$profile.$os.$arch.otherrpms.pkglist") { + $pkglist = "$pathtofiles/$profile.$os.$arch.otherrpms.pkglist"; + } elsif (-r "$pathtofiles/$profile.$arch.otherrpms.pkglist") { + $pkglist = "$pathtofiles/$profile.$arch.otherrpms.pkglist"; + } elsif (-r "$pathtofiles/$profile.$os.otherrpms.pkglist") { + $pkglist = "$pathtofiles/$profile.$os.otherrpms.pkglist"; + } elsif (-r "$pathtofiles/$profile.otherrpms.pkglist") { + $pkglist = "$pathtofiles/$profile.otherrpms.pkglist"; + } + + if ($pkglist) { + my @otherrpms=(); + if (open(FILE1, "<$pkglist")) { + while (readline(FILE1)) { + chomp($_); + push(@otherrpms,$_); + } + close(FILE1); + } + if ( @otherrpms > 0) { + push @scriptd, "OTHERRPMS=". join(',',@otherrpms) . " \n"; + push @scriptd, "export OTHERRPMS\n"; + } + } + } + + + ###Please do not remove or modify this line of code!!! xcatdsklspost depends on it + push @scriptd, "# postscripts-start-here\n"; + + my $hasotherrpms=0; # get the xcatdefaults entry in the postscripts table my $et = $posttab->getAttribs({node=>"xcatdefaults"},'postscripts'); my $defscripts = $et->{'postscripts'}; if ($defscripts) { foreach my $n (split(/,/, $defscripts)) { - push @scriptd, $n."\n"; + if ((!$hasotherrpms) && ($n eq "otherrpms")) { $hasotherrpms =1;} + push @scriptd, $n."\n"; } } @@ -212,10 +271,16 @@ sub makescript { $ps = $et->{'postscripts'}; if ($ps) { foreach my $n (split(/,/, $ps)) { + if ((!$hasotherrpms) && ($n eq "otherrpms")) { $hasotherrpms =1;} push @scriptd, $n."\n"; } } + if (!$hasotherrpms) { push @scriptd, "otherrpms\n";} + + ###Please do not remove or modify this line of code!!! xcatdsklspost depends on it + push @scriptd, "# postscripts-end-here\n"; + return @scriptd; } diff --git a/xCAT-server/lib/xcat/plugins/updatenode.pm b/xCAT-server/lib/xcat/plugins/updatenode.pm new file mode 100644 index 000000000..6e2ec3cd3 --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/updatenode.pm @@ -0,0 +1,323 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +package xCAT_plugin::updatenode; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl"; + +use strict; +use warnings; +use xCAT::Table; +use xCAT::Schema; +use Data::Dumper; +use xCAT::NodeRange; +use xCAT::Utils; +use Getopt::Long; +use xCAT::GlobalDef; +use Sys::Hostname; + +1; + + +#------------------------------------------------------------------------------- +=head1 xCAT_plugin:updatenode +=head2 Package Description + xCAT plug-in module. It handles the updatenode command. +=cut +#------------------------------------------------------------------------------ + +#-------------------------------------------------------------------------------- +=head3 handled_commands + It returns a list of commands handled by this plugin. + Arguments: + none + Returns: + a list of commands. +=cut +#-------------------------------------------------------------------------------- +sub handled_commands +{ + return { + updatenode => "updatenode"}; +} + + +#------------------------------------------------------- +=head3 preprocess_request + Check and setup for hierarchy +=cut +#------------------------------------------------------- +sub preprocess_request +{ + my $request = shift; + my $callback = 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); + } + else { + my $rsp={}; + $rsp->{data}->[0]= "unsupported command: $command."; + $callback->($rsp); + return \@requests; + } +} + +#-------------------------------------------------------------------------------- +=head3 process_request + It processes the monitoring control commands. + Arguments: + request -- a hash table which contains the command name and the arguments. + callback -- a callback pointer to return the response to. + Returns: + 0 for success. The output is returned through the callback pointer. + 1. for unsuccess. The error messages are returns through the callback pointer. +=cut +#-------------------------------------------------------------------------------- +sub process_request +{ + my $request = shift; + my $callback = shift; + my $command = $request->{command}->[0]; + my $localhostname=hostname(); + + if ($command eq "updatenode") + { + return updatenode($request, $callback); + } + else { + my $rsp={}; + $rsp->{data}->[0]= "$localhostname: unsupported command: $command."; + $callback->($rsp); + return 1; + } +} + + +#-------------------------------------------------------------------------------- +=head3 preprocess_updatenode + This function checks for the syntax of the updatenode command + and distribute the command to the right server. + Arguments: + request - the request. The request->{arg} is of the format: + [-h|--help|-v|--version] or + [noderange [postscripts]] + callback - the pointer to the callback function. + Returns: + A pointer to an array of requests. +=cut +#-------------------------------------------------------------------------------- +sub preprocess_updatenode { + my $request = shift; + my $callback = shift; + my $args=$request->{arg}; + my @requests=(); + + # subroutine to display the usage + sub updatenode_usage + { + my $cb=shift; + my $rsp={}; + $rsp->{data}->[0]= "Usage:"; + $rsp->{data}->[1]= " updaenode [noderange [posts]]"; + $rsp->{data}->[2]= " updaenode [-h|--help|-v|--version]"; + $rsp->{data}->[3]= " noderange is a list of nodes or groups. '\\\*' for all."; + $rsp->{data}->[4]= " posts is a groups of postscript names separated by comma."; + $rsp->{data}->[5]= " if omitted, all the postscripts will be run."; + $cb->($rsp); + } + + @ARGV=(); + if ($args) { + @ARGV=@{$args}; + } + + + # parse the options + Getopt::Long::Configure("bundling"); + Getopt::Long::Configure("no_pass_through"); + if(!GetOptions( + 'h|help' => \$::HELP, + 'v|version' => \$::VERSION)) + { + &updatenode_usage($callback); + return \@requests;; + } + + # display the usage if -h or --help is specified + if ($::HELP) { + &updatenode_usage($callback); + return \@requests;; + } + + # display the version statement if -v or --verison is specified + if ($::VERSION) + { + my $rsp={}; + $rsp->{data}->[0]= xCAT::Utils->Version(); + $callback->($rsp); + return \@requests; + } + + my @nodes; + my $postscripts; + my $bGetAll=0; + if (@ARGV > 0) { + my $noderange=$ARGV[0]; + if ($noderange eq '*') { $bGetAll=1;} + else { + @nodes = noderange($noderange); + if (nodesmissed) { + my $rsp={}; + $rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed); + $callback->($rsp); + return \@requests; + } + } + } else { #get all nodes + $bGetAll=1; + } + + if ($bGetAll) { + @nodes=getAllNodes($callback); + } + + + if (@nodes == 0) { return \@requests; } + + if (@ARGV > 1) { + $postscripts=$ARGV[1]; + my @posts=split(',',$postscripts); + foreach (@posts) { + if ( ! -e "/install/postscripts/$_") { + my $rsp={}; + $rsp->{data}->[0]= "The postcript /install/postscripts/$_ does not exist."; + $callback->($rsp); + return \@requests; + } + } + } + + if (@nodes>0) { + # find service nodes for requested nodes + # build an individual request for each service node + my $sn = xCAT::Utils->get_ServiceNode(\@nodes, "xcat", "MN"); + + # build each request for each service node + foreach my $snkey (keys %$sn) + { + my $reqcopy = {%$request}; + $reqcopy->{nodes} = $sn->{$snkey}; + $reqcopy->{'_xcatdest'} = $snkey; + $reqcopy->{postscripts} = [$postscripts]; + push @requests, $reqcopy; + } + return \@requests; + } + return \@requests; +} + + + +#-------------------------------------------------------------------------------- +=head3 updatenode + This function implements the updatenode command. + Arguments: + request - the request. + callback - the pointer to the callback function. + Returns: + 0 for success. The output is returned through the callback pointer. + 1. for unsuccess. The error messages are returns through the callback pointer. +=cut +#-------------------------------------------------------------------------------- +sub updatenode { + my $request = shift; + my $callback = shift; + my $postscripts=""; + if (($request->{postscripts}) && ($request->{postscripts}->[0])) { $postscripts=$request->{postscripts}->[0];} + my $nodes =$request->{nodes}; + my $localhostname=hostname(); + + my $nodestring=join(',', @$nodes); + #print "postscripts=$postscripts\n"; + + if ($nodestring) { + my $output=`XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -e /install/postscripts/xcatdsklspost $postscripts`; + my $rsp={}; + $rsp->{data}->[0]= "$output\n"; + $callback->($rsp); + } + + return 0; + +} + +#-------------------------------------------------------------------------------- +=head3 getAllNodes + This function gets all the nodes that has 'OSI' has nodetype. + Arguments: + callback + Returns: + an array of nodes +=cut +#-------------------------------------------------------------------------------- +sub getAllNodes +{ + my $callback =shift; + + my @nodes=(); + + my $table=xCAT::Table->new("nodelist", -create =>0); + if (!$table) { + my $rsp={}; + $rsp->{data}->[0]= "Cannot open the nodelist table."; + $callback->($rsp); + return @nodes; + } + my @tmp1=$table->getAllAttribs(('node')); + + my $table3=xCAT::Table->new("nodetype", -create =>0); + if (!$table3) { + my $rsp={}; + $rsp->{data}->[0]= "Cannot open the nodetype table."; + $callback->($rsp); + return @nodes; + } + + my @tmp3=$table3->getAllNodeAttribs(['node','nodetype']); + my %temp_hash3=(); + foreach (@tmp3) { + $temp_hash3{$_->{node}}=$_; + } + + if (@tmp1 > 0) { + foreach(@tmp1) { + my $node=$_->{node}; + my $row3=$temp_hash3{$node}; + my $nodetype=""; #default + if (defined($row3) && ($row3)) { + if ($row3->{nodetype}) { $nodetype=$row3->{nodetype}; } + } + + #only handle the OSI nodetype + if (($nodetype) && ($nodetype =~ /$::NODETYPE_OSI/)) { + push(@nodes, $node); + } + } + } + $table->close(); + $table3->close(); + + return @nodes; +} + + + + diff --git a/xCAT/postscripts/otherrpms b/xCAT/postscripts/otherrpms new file mode 100755 index 000000000..4a9e7843d --- /dev/null +++ b/xCAT/postscripts/otherrpms @@ -0,0 +1,70 @@ +#!/bin/sh +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +#------------------------------------------------------------------------------- +#=head1 otherrpms +#=head2 It gets the extra rpms and install/update them. +# The environment variable OTHERRPMS contains the rpms to be installed/updated. +# On MN, You need to: +# 1. put rpms under /install/post/otherrpms/os/arch directory where 'os' and 'arch' +# can be found in the nodetype table. +# 2. put the name of the packages to /opt/xcat/share/xcat/netboot(install)/platform +# directory. The file name is one of the following: +# profile.os.arch.otherrpms.pkglist +# profile.os.otherrpms.pkglist +# profile.arch.otherrpms.pkglist +# profile.otherrpms.pkglist +# The install/deployment process will pick up the rpms and install them on the nodes. +# However, if the nodes have already installed and up and running, you can run the following +# command to have the extra rpms installed: +# updatenode noderange otherrpms +# +#=cut +#------------------------------------------------------------------------------- + +#echo "OTHERRPMS=$OTHERRPMS" +if [[ -z "$OTHERRPMS" ]]; then + echo "$0: no extra rpms to install" + exit 0 +fi + +SIP=`grep -h dhcp-server-identifier /var/lib/dhclient/dhclient-*.leases|tail -n 1|awk '{print $3}'|sed -e 's/;//'` +if [ -z "$SIP" ]; then + SIP=`grep -h DHCPSID /var/lib/dhcpcd/*.info|awk -F= '{print $2}'|tail -n 1` +fi +mkdir -p /xcatpost/post/otherrpms; +mkdir -p /tmp/postage/ +rm -f -R /xcatpost/post/otherrpms/* +rm -f -R /tmp/postage/* +cd /tmp/postage + +for x in `echo "$OTHERRPMS" | tr "," "\n"` +do + wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -t 0 -T 60 ftp://$SIP/post/otherrpms/$OSVER/$ARCH/$x-* 2> /tmp/wget.log +done + +mv $SIP/post/otherrpms/* /xcatpost/post/otherrpms; +rm -rf $SIP + +cd /xcatpost/post/otherrpms/$OSVER/$ARCH +rpm -Uvh * + +exit 0 + + + + + + + + + + + + + + + + + + diff --git a/xCAT/postscripts/xcatdsklspost b/xCAT/postscripts/xcatdsklspost index 6ff047eef..2afef953d 100755 --- a/xCAT/postscripts/xcatdsklspost +++ b/xCAT/postscripts/xcatdsklspost @@ -19,6 +19,7 @@ if [ -z "$SIP" ]; then SIP=`grep -h DHCPSID /var/lib/dhcpcd/*.info|awk -F= '{print $2}'|tail -n 1` fi +#echo "SIP=$SIP" if grep 'rw /rw tmpfs ' /proc/mounts >& /dev/null; then touch /var/lock/subsys/xcatmounts @@ -36,6 +37,7 @@ cat > /etc/stunnel/stunnel.conf << EOF client=yes foreground=no output=/dev/null +#output=/var/log/stunnel.log verify=0 [xcatd] accept=400 @@ -44,7 +46,10 @@ echo "connect=$SIP:3001" >> /etc/stunnel/stunnel.conf stunnel; sleep 1; mkdir -p /xcatpost; -mkdir /tmp/postage +mkdir -p /tmp/postage +rm -R -f /xcatpost/* +rm -R -f /tmp/postage/* + cd /tmp/postage #wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -t 0 -T 60 ftp://$SIP/install/postscripts 2> /tmp/wget.log wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -t 0 -T 60 ftp://$SIP/postscripts 2> /tmp/wget.log @@ -54,16 +59,30 @@ rm -rf $SIP cd /xcatpost; PATH=/xcatpost:$PATH export PATH -chmod +x /xcatpost/*; +chmod +x /xcatpost/*; +echo "PATH=$PATH" /xcatpost/getpostscript.awk | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' > /tmp/mypostscript; MYCONT=`cat /tmp/mypostscript` +#echo "MYCONT=$MYCONT" while [ -z "$MYCONT" ]; do let SLI=$RANDOM%10 let SLI=10+$SLI sleep $SLI /xcatpost/getpostscript.awk | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' > /tmp/mypostscript; MYCONT=`cat /tmp/mypostscript` +# echo "MYCONT=$MYCONT" done +if [ $# -gt 0 ]; then + POSTS=$1 + #remove all the postscripts + TMP=`sed "/postscripts-start-here/,/postscripts-end-here/ d" /tmp/mypostscript` + echo "$TMP" > /tmp/mypostscript + #add requested postscripts in + echo "$POSTS" | tr "," "\n" >> /tmp/mypostscript +fi +#MYCONT=`cat /tmp/mypostscript` +#echo "$MYCONT" + chmod +x /tmp/mypostscript if [ -x /tmp/mypostscript ];then /tmp/mypostscript @@ -71,3 +90,12 @@ fi rm -f /tmp/mypostscript killall stunnel rm -rf /etc/stunnel + + + + + + + + +