From 6b4b8e4ca293462b3f4a3e17c6976a1efd852767 Mon Sep 17 00:00:00 2001 From: daniceexi Date: Sun, 21 Mar 2010 13:11:47 +0000 Subject: [PATCH] the code drop of updatenode --security git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@5539 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT/xCAT/Usage.pm | 29 ++ xCAT-client/bin/updatenode | 126 +++++ xCAT-rmc/plugin/rmcmon.pm | 2 +- .../lib/xcat/plugins/makeknownhosts.pm | 2 +- xCAT-server/lib/xcat/plugins/updatenode.pm | 446 ++++++++++++++---- xCAT/postscripts/servicenode | 32 ++ xCAT/postscripts/xcataixpost | 9 +- xCAT/postscripts/xcatdsklspost | 237 +++++----- 8 files changed, 677 insertions(+), 206 deletions(-) create mode 100755 xCAT-client/bin/updatenode diff --git a/perl-xCAT/xCAT/Usage.pm b/perl-xCAT/xCAT/Usage.pm index 2d1dfebd9..edeac1dd2 100644 --- a/perl-xCAT/xCAT/Usage.pm +++ b/perl-xCAT/xCAT/Usage.pm @@ -187,6 +187,35 @@ my %usage = ( renergy noderange [-V] { all | { [savingstatus] [dsavingstatus] [cappingstatus] [cappingmaxmin] [cappingvalue] [cappingsoftmin] [averageAC] [averageDC] [ambienttemp] [exhausttemp] [CPUspeed] [syssbpower] [sysIPLtime] } } renergy noderange [-V] { {savingstatus}={on | off} | {dsavingstatus}={on-norm | on-maxp | off} | {cappingstatus}={on | off} | {cappingwatt}=watt | {cappingperc}=percentage }", + "updatenode" => +"Usage: + updatenode [-h|--help|-v|--version] + or + updatenode [-V|--verbose] [--security] [-s|--sn] + or + updatenode [-V|--verbose] [--security] [--user] + [--devicetype] + or + updatenode [-V|--verbose] [-F|--sync] [-S|--sw] + [-P|--scripts [script1,script2,...]] [-s|--sn] [-c|--cmdlineonly] + [attr=val [attr=val...]] + or + updatenode [-V|--verbose] [script1,script2,...] + is a list of nodes or groups. + [--security] update the security keys and certificates for the target nodes + [--security] [--user] [--devicetype] update the ssh keys for specific device + [-F|--sync] Perform File Syncing. + [-S|--sw] Perform Software Maintenance. + [-P|--scripts] Execute postscripts listed in the postscripts table or + parameters. + [-c|--cmdlineonly] Only use AIX software maintenance information + provided on the command line. (AIX only) + [-s|--sn] Set the server information stored on the nodes. + [script1,script2,...] A comma separated list of postscript names. + If omitted, all the post scripts defined for the nodes will be run. + [attr=val [attr=val...]] Specifies one or more 'attribute equals value' + pairs, separated by spaces. (AIX only)", + ); my $vers = xCAT::Utils->Version(); my %version = ( diff --git a/xCAT-client/bin/updatenode b/xCAT-client/bin/updatenode new file mode 100755 index 000000000..0ea16835f --- /dev/null +++ b/xCAT-client/bin/updatenode @@ -0,0 +1,126 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; } + +use Getopt::Long; + +use lib "$::XCATROOT/lib/perl"; +use Cwd; +use File::Basename; +use xCAT::Client; +use xCAT::MsgUtils; +use xCAT::Usage; + +sub updatenode_usage +{ + my $usage_string = xCAT::Usage->getUsage("updatenode"); + print "$usage_string\n"; +} + +my $bname = basename($0); +my $cmdref; +$cmdref->{command}->[0] = $bname; +$cmdref->{cwd}->[0] = cwd(); + +if (-p STDIN) { + my $data; + while ( ) { $data.=$_; } + $cmdref->{stdin}->[0]=$data; +} + +my $arg=shift(@ARGV); + +# Set the noderange +if ($arg !~ /^-/) { + my @tempnr = (); + foreach my $nr (split(/,/, $arg)) { + if ($nr =~ /^\^(.*)$/) { + my $nrf = $1; + if ($nrf !~ /^\//) { #relative path + $nrf = Cwd::abs_path($nrf); + } + $nrf = "\^" . $nrf; + push @tempnr, $nrf; + } else { + push @tempnr, $nr; + } + } + $arg = join(',',@tempnr); + $cmdref->{noderange}->[0]=$arg; +} else { + push @{$cmdref->{arg}}, $arg; +} + +push (@{$cmdref->{arg}}, @ARGV); + +# if trying to update security, get the password +# to access the target node firstly +Getopt::Long::Configure("posix_default"); +Getopt::Long::Configure("no_gnu_compat"); +Getopt::Long::Configure("bundling"); +if ( + !GetOptions( + 'c|cmdlineonly' => \$::CMDLINE, + 'h|help' => \$::HELP, + 'v|version' => \$::VERSION, + 'V|verbose' => \$::VERBOSE, + 'F|sync' => \$::FILESYNC, + 'S|sw' => \$::SWMAINTENANCE, + 's|sn' => \$::SETSERVER, + 'P|scripts:s' => \$::RERUNPS, + 'security' => \$::SECURITY, + 'user=s' => \$::USER, + 'devicetype=s' => \$::DEVICETYPE, + ) + ) { + &updatenode_usage(); + exit 1; +} + +my $current_userid = getpwuid($>); +$ENV{DSH_FROM_USERID} = $current_userid; +my $to_userid; +if ($::USER) +{ + $to_userid = $::USER; +} +else +{ + $to_userid = $current_userid; +} +$ENV{DSH_TO_USERID} = $to_userid; + +if ($::SECURITY) { + my $msg; + if (!($ENV{'DSH_REMOTE_PASSWORD'})) + { # if not already set + # prompt for the password for the userid on the node that will be setup + my $userpw; + $msg = + "Enter the password for the userid: $to_userid on the node where the ssh keys \nwill be updated:\n"; + xCAT::MsgUtils->message("I", $msg); + system("stty -echo"); # turn off keyboard + chop($userpw = ); + system("stty echo"); # turn on keyboard + + if ($userpw eq "") + { # did not enter a password + $msg = "Did not enter a password will abort the security update."; + xCAT::MsgUtils->message("E", $msg); + exit 2; + } + else + { # password entered pass to the server + $ENV{DSH_REMOTE_PASSWORD} = $userpw; + + } + } +} + +foreach (keys %ENV) { + push @{$cmdref->{environment}}, "$_=$ENV{$_}"; +} + +xCAT::Client::submit_request($cmdref,\&xCAT::Client::handle_response); +exit $xCAT::Client::EXITCODE; diff --git a/xCAT-rmc/plugin/rmcmon.pm b/xCAT-rmc/plugin/rmcmon.pm index a2839c2ba..f0e949057 100644 --- a/xCAT-rmc/plugin/rmcmon.pm +++ b/xCAT-rmc/plugin/rmcmon.pm @@ -1182,7 +1182,7 @@ sub addNodes { my $nr = join(',', @{$servernodes{$snkey}}); my $cmd; if (xCAT::Utils->isLinux()) { - $cmd="XCATBYPASS=Y $fanout_string $::XCATROOT/bin/xdsh $nr -s -e /install/postscripts/xcatdsklspost -m $snkey configrmcnode 2>&1"; + $cmd="XCATBYPASS=Y $fanout_string $::XCATROOT/bin/xdsh $nr -s -e /install/postscripts/xcatdsklspost 2 -m $snkey configrmcnode 2>&1"; print "$cmd\n"; } else { diff --git a/xCAT-server/lib/xcat/plugins/makeknownhosts.pm b/xCAT-server/lib/xcat/plugins/makeknownhosts.pm index 11cfad232..50677fec8 100644 --- a/xCAT-server/lib/xcat/plugins/makeknownhosts.pm +++ b/xCAT-server/lib/xcat/plugins/makeknownhosts.pm @@ -405,6 +405,6 @@ sub remove_nodes_from_knownhosts return 1; } } - xCAT::Utils->runcmd("$::RM -f $file", -1); + xCAT::Utils->runcmd("rm -f $file", -1); return 0; } diff --git a/xCAT-server/lib/xcat/plugins/updatenode.pm b/xCAT-server/lib/xcat/plugins/updatenode.pm index 405f13351..97f723c08 100644 --- a/xCAT-server/lib/xcat/plugins/updatenode.pm +++ b/xCAT-server/lib/xcat/plugins/updatenode.pm @@ -155,24 +155,9 @@ sub preprocess_updatenode { my $cb = shift; my $rsp = {}; - $rsp->{data}->[0] = "Usage:"; - $rsp->{data}->[1] = " updatenode [-h|--help|-v|--version]"; - $rsp->{data}->[2] = "or"; - $rsp->{data}->[3] = - " updatenode [-V|--verbose] [-F|--sync] [-S|--sw] [-P|--scripts \n\t\t[-s|--sn] [script1,script2,...]] [-c|--cmdlineonly] \n\t\t[attr=val [attr=val...]]"; - $rsp->{data}->[4] = "or"; - $rsp->{data}->[5] = - " updatenode [-V|--verbose] [script1,script2,...]\n"; - $rsp->{data}->[6] = " is a list of nodes or groups."; - $rsp->{data}->[7] = " [-F|--sync] Perform File Syncing."; - $rsp->{data}->[8] = " [-S|--sw] Perform Software Maintenance."; - $rsp->{data}->[9] = - " [-P|--scripts] Execute postscripts listed in the postscripts table or \n\tparameters."; - $rsp->{data}->[10] = - " [-c|--cmdlineonly] Only use AIX software maintenance information provided \n\ton the command line. (AIX only)"; - $rsp->{data}->[11] = " [-s|--sn] Set the server information stored on the nodes."; - $rsp->{data}->[12] = " [script1,script2,...] A comma separated list of postscript names. \n\tIf omitted, all the postscripts defined for the nodes will be run."; - $rsp->{data}->[13] = " [attr=val [attr=val...]] Specifies one or more 'attribute equals value'\n\tpairs, separated by spaces. (AIX only)"; + my $usage_string = xCAT::Usage->getUsage("updatenode"); + push @{$rsp->{data}},$usage_string; + $cb->($rsp); } @@ -187,14 +172,17 @@ sub preprocess_updatenode Getopt::Long::Configure("no_pass_through"); if ( !GetOptions( - 'c|cmdlineonly' => \$::CMDLINE, - 'h|help' => \$::HELP, - 'v|version' => \$::VERSION, - 'V|verbose' => \$::VERBOSE, - 'F|sync' => \$::FILESYNC, - 'S|sw' => \$::SWMAINTENANCE, - 's|sn' => \$::SETSERVER, - 'P|scripts:s' => \$::RERUNPS + 'c|cmdlineonly' => \$::CMDLINE, + 'h|help' => \$::HELP, + 'v|version' => \$::VERSION, + 'V|verbose' => \$::VERBOSE, + 'F|sync' => \$::FILESYNC, + 'S|sw' => \$::SWMAINTENANCE, + 's|sn' => \$::SETSERVER, + 'P|scripts:s' => \$::RERUNPS, + 'security' => \$::SECURITY, + 'user=s' => \$::USER, + 'devicetype=s' => \$::DEVICETYPE, ) ) { @@ -218,6 +206,30 @@ sub preprocess_updatenode return \@requests; } + # -c must work with -S for AIX node + if ($::CMDLINE && !$::SWMAINTENANCE) { + &updatenode_usage($callback); + return \@requests; + } + + # -s must work with -P or -S or --security + if ($::SETSERVER && !($::SWMAINTENANCE || $::RERUNPS || $::SECURITY)) { + &updatenode_usage($callback); + return \@requests; + } + + # --user and --devicetype must work with --security + if (($::USER || $::DEVICETYPE) && !($::SECURITY && $::USER && $::DEVICETYPE)) { + &updatenode_usage($callback); + return \@requests; + } + + # --security cannot work with -S -P -F + if ($::SECURITY && ($::SWMAINTENANCE || $::RERUNPS || defined($::RERUNPS))) { + &updatenode_usage($callback); + return \@requests; + } + # the -P flag is omitted when only postscritps are specified, # so if there are parameters without any flags, it may mean # to re-run the postscripts. @@ -226,7 +238,7 @@ sub preprocess_updatenode # we have one or more operands on the cmd line if ($#ARGV == 0 - && !($::FILESYNC || $::SWMAINTENANCE || defined($::RERUNPS))) + && !($::FILESYNC || $::SWMAINTENANCE || defined($::RERUNPS) || $::SECURIT)) { # there is only one operand @@ -234,6 +246,7 @@ sub preprocess_updatenode if (!($ARGV[0] =~ /=/)) { $::RERUNPS = $ARGV[0]; + $ARGV[0] = ""; } } } @@ -241,7 +254,7 @@ sub preprocess_updatenode { # no flags and no operands - if (!($::FILESYNC || $::SWMAINTENANCE || defined($::RERUNPS))) + if (!($::FILESYNC || $::SWMAINTENANCE || defined($::RERUNPS) ||$::SECURITY)) { $::FILESYNC = 1; $::SWMAINTENANCE = 1; @@ -249,6 +262,10 @@ sub preprocess_updatenode } } + if ($::SECURITY && !($::USER || $::DEVICETYPE)) { + $::RERUNPS = "allkeys44444444security"; + } + my $nodes = $request->{node}; if (!$nodes) { @@ -257,39 +274,38 @@ sub preprocess_updatenode } # - # process @ARGV + # process @ARGV for the software maintenance of AIX node, it should + # be the list of attr=val, put attr=val operands in %attrvals hash # - # the first arg should be a noderange - the other should be attr=val - # - put attr=val operands in %attrvals hash my %attrvals; - while (my $a = shift(@ARGV)) - { - if ($a =~ /=/) + if ($::SWMAINTENANCE) { + while (my $a = shift(@ARGV)) { - - # if it has an "=" sign its an attr=val - we hope - my ($attr, $value) = $a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/; - - if (!defined($attr) || !defined($value)) + if ($a =~ /=/) { - my $rsp; - $rsp->{data}->[0] = "Incorrect \'attr=val\' pair - $a\n"; - xCAT::MsgUtils->message("E", $rsp, $::callback); - return 3; + + # if it has an "=" sign its an attr=val - we hope + my ($attr, $value) = $a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/; + + if (!defined($attr) || !defined($value)) + { + my $rsp; + $rsp->{data}->[0] = "Incorrect \'attr=val\' pair - $a\n"; + xCAT::MsgUtils->message("E", $rsp, $::callback); + return 3; + } + + # put attr=val in hash + $attrvals{$attr} = $value; } - - # put attr=val in hash - $attrvals{$attr} = $value; } } my @nodes = @$nodes; my $postscripts; - if (@nodes == 0) { return \@requests; } - - # handle the re-run postscripts option -P + # handle the validity of postscripts if (defined($::RERUNPS)) { if ($::RERUNPS eq "") @@ -299,7 +315,13 @@ sub preprocess_updatenode else { $postscripts = $::RERUNPS; - my @posts = split(',', $postscripts); + my @posts = (); + if ($postscripts eq "allkeys44444444security") { + @posts = ("remoteshell", "aixremoteshell", "servicenode", "xcatserver", "xcatclient"); + } else { + @posts = split(',', $postscripts); + } + foreach (@posts) { if (!-e "$installdir/postscripts/$_") @@ -315,8 +337,8 @@ sub preprocess_updatenode } # If -F option specified, sync files to the noderange. - # Note: This action only happens on MN, since xdcp handles the - # hierarchical scenario + # Note: This action only happens on MN, since xdcp, xdsh handles the + # hierarchical scenario inside if ($::FILESYNC) { my $reqcopy = {%$request}; @@ -324,10 +346,10 @@ sub preprocess_updatenode push @requests, $reqcopy; } - # when specified -S or -P + # when specified -S or -P or --security # find service nodes for requested nodes # build an individual request for each service node - unless (defined($::SWMAINTENANCE) || defined($::RERUNPS)) + unless (defined($::SWMAINTENANCE) || defined($::RERUNPS) || $::SECURITY) { return \@requests; } @@ -338,7 +360,6 @@ sub preprocess_updatenode xCAT::SvrUtils->getNodesetStates($nodes, \%insttype_node); - # figure out the diskless nodes list and non-diskless nodes foreach my $type (keys %insttype_node) { if ($type eq "netboot" || $type eq "diskless") { @@ -374,6 +395,7 @@ sub preprocess_updatenode } } + my $sn = xCAT::Utils->get_ServiceNode(\@nodes, "xcat", "MN"); if ($::ERROR_RC) { @@ -385,10 +407,97 @@ sub preprocess_updatenode # return undef; ??? } + + # for security update, we need to handle the service node first + my @good_sns = (); + my @MNip = xCAT::Utils->determinehostname; + my @sns = (); + foreach my $s (keys %$sn) { + if (!grep (/^$s$/, @MNip)) { + push @sns, $s; + } + } + if (scalar(@sns) && $::SECURITY) { + + $::CALLBACK = $callback; + $::NODEOUT = (); + + # setup the ssh keys + my $req_sshkey = {%$request}; + $req_sshkey->{node} = \@sns; + $req_sshkey->{security}->[0] = "yes"; + if ($::USER) { + $req_sshkey->{user}->[0] = $::USER; + } + if ($::DEVICETYPE) { + $req_sshkey->{devicetype}->[0] = $::DEVICETYPE; + } + + updatenode($req_sshkey, \&updatenode_cb, $subreq); + + # run the postscripts: remoteshell, servicenode, xcatserver, xcatclient + if ($postscripts eq "allkeys44444444security") { + my ($rc, $AIXnodes, $Linuxnodes) = xCAT::InstUtils->getOSnodes(\@sns); + + my $req_rs = {%$request}; + my $ps; + if (scalar(@{$AIXnodes})) { + $ps = "aixremoteshell,servicenode"; + $req_rs->{rerunps}->[0] = "yes"; + $req_rs->{rerunps4security}->[0] = "yes"; + $req_rs->{node} = $AIXnodes; + $req_rs->{postscripts} = [$ps]; + updatenode($req_rs, \&updatenode_cb, $subreq); + } + if (scalar(@{$Linuxnodes})) { + $ps = "remoteshell,servicenode,xcatserver,xcatclient"; + $req_rs->{rerunps}->[0] = "yes"; + $req_rs->{rerunps4security}->[0] = "yes"; + $req_rs->{node} = $Linuxnodes; + $req_rs->{postscripts} = [$ps]; + updatenode($req_rs, \&updatenode_cb, $subreq); + } + } + + # parse the output of update security for sns + foreach my $sn (keys %{$::NODEOUT}) { + if (!grep /^$sn$/, @sns) { + next; + } + if ( (grep /ps ok/, @{$::NODEOUT->{$sn}}) + && (grep /ssh ok/, @{$::NODEOUT->{$sn}}) ) { + push @good_sns, $sn; + } + } + + if ($::VERBOSE) { + my $rsp; + push @{$rsp->{data}}, "Update security for following service nodes: @sns."; + push @{$rsp->{data}}, " Following service nodes have been updated successfully: @good_sns"; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + # build each request for each service node foreach my $snkey (keys %$sn) { + if ($::SECURITY + && !(grep /^$snkey$/, @good_sns) + && !(grep /^$snkey$/, @MNip)) { + my $rsp; + push @{$rsp->{data}}, "The security update for service node $snkey encountered error, update security for following nodes will be skipped: @{$sn->{$snkey}}"; + xCAT::MsgUtils->message("E", $rsp, $callback); + next; + } + # remove the service node which have been handled before + if ($::SECURITY && (grep /^$snkey$/, @MNip)) { + delete @{$sn->{$snkey}}[@sns]; + if (scalar(@{$sn->{$snkey}}) == 0) { + next; + } + } + my $reqcopy = {%$request}; $reqcopy->{node} = $sn->{$snkey}; $reqcopy->{'_xcatdest'} = $snkey; @@ -425,6 +534,19 @@ sub preprocess_updatenode { $reqcopy->{rerunps}->[0] = "yes"; $reqcopy->{postscripts} = [$postscripts]; + if (defined($::SECURITY)) { + $reqcopy->{rerunps4security}->[0] = "yes"; + } + } + + if (defined($::SECURITY)) { + $reqcopy->{security}->[0] = "yes"; + if ($::USER) { + $reqcopy->{user}->[0] = $::USER; + } + if ($::DEVICETYPE) { + $reqcopy->{devicetype}->[0] = $::DEVICETYPE; + } } push @requests, $reqcopy; @@ -433,6 +555,40 @@ sub preprocess_updatenode return \@requests; } + +#-------------------------------------------------------------------------------- + +=head3 updatenode_cb + + A callback function which is used to handle the output of updatenode function + when run updatenode --secruity for service node inside + +=cut + +#----------------------------------------------------------------------------- +sub updatenode_cb +{ + my $resp = shift; + + # call the original callback function + $::CALLBACK->($resp); + + foreach my $line (@{$resp->{data}}) { + my $node; + my $msg; + if ($line =~ /(.*):(.*)/) { + $node = $1; + $msg = $2; + } + if ($msg =~ /Redeliver certificates has completed/) { + push @{$::NODEOUT->{$node}}, "ps ok"; + } elsif ($msg =~ /Setup ssh keys has completed/) { + push @{$::NODEOUT->{$node}}, "ssh ok"; + } + } +} + + #-------------------------------------------------------------------------------- =head3 updatenode @@ -574,7 +730,7 @@ sub updatenode { my $rsp = {}; $rsp->{data}->[0] = - " Internal call command: xdcp -F $synclist"; + " $localhostname: Internal call command: xdcp -F $synclist"; $callback->($rsp); } my $args = ["-F", "$synclist"]; @@ -640,25 +796,25 @@ sub updatenode my $cmd; if ($::SETSERVER) { $cmd = - "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost -M $snkey otherpkgs 2>&1"; + "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost 2 -M $snkey otherpkgs 2>&1"; } else { $cmd = - "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost -m $snkey otherpkgs 2>&1"; + "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost 2 -m $snkey otherpkgs 2>&1"; } if (defined($::VERBOSE)) { my $rsp = {}; - $rsp->{data}->[0] = " Internal call command: $cmd"; + $rsp->{data}->[0] = " $localhostname: Internal call command: $cmd"; $callback->($rsp); } if ($cmd && !open(CMD, "$cmd |")) { my $rsp = {}; - $rsp->{data}->[0] = "Cannot run command $cmd"; + $rsp->{data}->[0] = "$localhostname: Cannot run command $cmd"; $callback->($rsp); } else @@ -703,6 +859,80 @@ sub updatenode } } # end sw maint section + # + # handle of setting up ssh keys + # + + if ($request->{security} && $request->{security}->[0] eq "yes") { + + # generate the arguments + my @args = ("-K"); + if ($request->{user}->[0]) { + push @args, "--user"; + push @args, $request->{user}->[0]; + } + if ($request->{devicetype}->[0]) { + push @args, "--devicetype"; + push @args, $request->{devicetype}->[0]; + } + + # remove the host key from known_hosts + xCAT::Utils->runxcmd( { + command => ['makeknownhosts'], + node => \@$nodes, + arg => ['-r'], + }, $subreq, 0, 1); + + if (defined($::VERBOSE)) + { + my $rsp = {}; + $rsp->{data}->[0] = + " $localhostname: run makeknownhosts to clean known_hosts file for nodes: @$nodes"; + $callback->($rsp); + } + + # call the xdsh -K to set up the ssh keys + my @envs = @{$request->{environment}}; + my $res = xCAT::Utils->runxcmd( { + command => ['xdsh'], + node => \@$nodes, + arg => \@args, + env => \@envs, + }, $subreq, 0, 1); + + if (defined($::VERBOSE)) + { + my $rsp = {}; + $rsp->{data}->[0] = + " $localhostname: Internal call command: xdsh -K. nodes = @$nodes, arguments = @args, env = @envs"; + $rsp->{data}->[1] = + " $localhostname: return messages of last command: @$res"; + $callback->($rsp); + } + + # parse the output of xdsh -K + my @failednodes = @$nodes; + foreach my $line (@$res) { + chomp($line); + if ($line =~ /SSH setup failed for the following nodes: (.*)\./) { + @failednodes = split(/,/, $1); + } elsif ($line =~ /setup is complete/) { + @failednodes = (); + } + } + + + my $rsp = {}; + foreach my $node (@$nodes) { + if (grep /^$node$/, @failednodes) { + push @{$rsp->{data}}, "$node: Setup ssh keys failed."; + } else { + push @{$rsp->{data}}, "$node: Setup ssh keys has completed."; + } + } + $callback->($rsp); + } + # # handle the running of cust scripts # @@ -710,14 +940,22 @@ sub updatenode if ($request->{rerunps} && $request->{rerunps}->[0] eq "yes") { my $postscripts = ""; + my $orig_postscripts = ""; if (($request->{postscripts}) && ($request->{postscripts}->[0])) { - $postscripts = $request->{postscripts}->[0]; + $orig_postscripts = $request->{postscripts}->[0]; } if (scalar(@$Linuxnodes)) - { # we have Linux nodes - my $cmd; + { + if ($orig_postscripts eq "allkeys44444444security") { + $postscripts = "remoteshell,servicenode,xcatserver,xcatclient"; + } else { + $postscripts = $orig_postscripts; + } + + # we have Linux nodes + my $cmd; # get server names as known by the nodes my %servernodes = %{xCAT::InstUtils->get_server_nodes($callback, \@$Linuxnodes)}; # it's possible that the nodes could have diff server names @@ -725,35 +963,43 @@ sub updatenode foreach my $snkey (keys %servernodes) { my $nodestring = join(',', @{$servernodes{$snkey}}); my $cmd; + my $mode; + if ($request->{rerunps4security} && $request->{rerunps4security}->[0] eq "yes") { + # for updatenode --security + $mode = "5"; + } else { + # for updatenode -P + $mode = "1"; + } if ($::SETSERVER) { $cmd = - "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost -M $snkey $postscripts 2>&1"; + "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost $mode -M $snkey $postscripts 2>&1"; } else { $cmd = - "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost -m $snkey $postscripts 2>&1"; + "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcatdsklspost $mode -m $snkey $postscripts 2>&1"; } if (defined($::VERBOSE)) { my $rsp = {}; - $rsp->{data}->[0] = " Internal call command: $cmd"; + $rsp->{data}->[0] = " $localhostname: Internal call command: $cmd"; $callback->($rsp); } if (!open(CMD, "$cmd |")) { my $rsp = {}; - $rsp->{data}->[0] = "Cannot run command $cmd"; + $rsp->{data}->[0] = "$localhostname: Cannot run command $cmd"; $callback->($rsp); } else { + my $rsp = {}; while () { - my $rsp = {}; my $output = $_; chomp($output); $output =~ s/\\cM//; @@ -762,17 +1008,32 @@ sub updatenode $output =~ s/returned from postscript/Running of postscripts has completed./; } - $rsp->{data}->[0] = "$output"; - $callback->($rsp); + if ($request->{rerunps4security} && $request->{rerunps4security}->[0] eq "yes") { + if ($output =~ /Running of postscripts has completed/) { + $output =~ s/Running of postscripts has completed/Redeliver certificates has completed/; + push @{$rsp->{data}}, $output; + } elsif ($output !~ /Running postscript|Error loading module/) { + push @{$rsp->{data}}, "$output"; + } + } else { + push @{$rsp->{data}}, "$output"; + } } close(CMD); + $callback->($rsp); } } } if (scalar(@$AIXnodes)) - { # we have AIX nodes - + { + # we have AIX nodes + if ($orig_postscripts eq "allkeys44444444security") { + $postscripts = "aixremoteshell,servicenode"; + } else { + $postscripts = $orig_postscripts; + } + # need to pass the name of the server on the xcataixpost cmd line # get server names as known by the nodes @@ -782,30 +1043,39 @@ sub updatenode foreach my $snkey (keys %servernodes) { $nodestring = join(',', @{$servernodes{$snkey}}); my $cmd; + my $mode; + if ($request->{rerunps4security} && $request->{rerunps4security}->[0] eq "yes") { + # for updatenode --security + $mode = "5"; + } else { + # for updatenode -P + $mode = "1"; + } + if ($::SETSERVER) { - $cmd = "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcataixpost -M $snkey -c 1 $postscripts 2>&1"; + $cmd = "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcataixpost -M $snkey -c $mode $postscripts 2>&1"; } else { - $cmd = "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcataixpost -m $snkey -c 1 $postscripts 2>&1"; + $cmd = "XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e $installdir/postscripts/xcataixpost -m $snkey -c $mode $postscripts 2>&1"; } if (defined($::VERBOSE)) { my $rsp = {}; - $rsp->{data}->[0] = " Internal call command: $cmd"; + $rsp->{data}->[0] = " $localhostname: Internal call command: $cmd"; $callback->($rsp); } if (!open(CMD, "$cmd |")) { my $rsp = {}; - $rsp->{data}->[0] = "Cannot run command $cmd"; + $rsp->{data}->[0] = "$localhostname: Cannot run command $cmd"; $callback->($rsp); } else { + my $rsp = {}; while () { - my $rsp = {}; my $output = $_; chomp($output); $output =~ s/\\cM//; @@ -814,15 +1084,33 @@ sub updatenode $output =~ s/returned from postscript/Running of postscripts has completed./; } - $rsp->{data}->[0] = "$output"; - $callback->($rsp); + if ($request->{rerunps4security} && $request->{rerunps4security}->[0] eq "yes") { + if ($output =~ /Running of postscripts has completed/) { + $output =~ s/Running of postscripts has completed/Redeliver certificates has completed/; + push @{$rsp->{data}}, $output; + } elsif ($output !~ /Running postscript|Error loading module/) { + push @{$rsp->{data}}, $output; + } + } else { + push @{$rsp->{data}}, "$output"; + } } close(CMD); + $callback->($rsp); } } } + if ($request->{rerunps4security} && $request->{rerunps4security}->[0] eq "yes") { + # clean the know_hosts + xCAT::Utils->runxcmd( { + command => ['makeknownhosts'], + node => \@$nodes, + arg => ['-r'], + }, $subreq, 0, 1); + } } + return 0; } diff --git a/xCAT/postscripts/servicenode b/xCAT/postscripts/servicenode index 904f2fad6..7ea61a9b6 100755 --- a/xCAT/postscripts/servicenode +++ b/xCAT/postscripts/servicenode @@ -56,6 +56,38 @@ chomp $::sdate; $::hname = `hostname`; chomp $::hname; +# update security certificates keys for service node +if ($ENV{UPDATESECURITY} && $ENV{UPDATESECURITY} eq "1") { + $::servnode = $ENV{'MASTER'}; + + # only run for service node + if (! -f "/etc/xCATSN") { + exit 0; + } + + # copy the postscripts to /install/postscripts + if (&runcmd("mkdir -p /install/postscripts; cp -p -R /xcatpost/* /install/postscripts > /dev/null 2>&1") != 0 ) { + $msg = "$::sdate servicenode: Could not copy postscripts to /install/postscripts.\n"; + `logger -t xcat $msg`; + } + + # copy the certificates + if (&runcmd("/opt/xcat/sbin/copycerts") != 0) { + $msg = "$::sdate servicenode: Could not run copycerts.\n"; + `logger -t xcat $msg`; + } + + if ($::osname eq 'AIX') { + # get the xCAT credentials from the server + # the credenticals and certificates copy will be done in xcatclient and xcatserver postscripts + &getcreds; + } + + exit 0; +} + + + if ($::osname eq 'AIX') { # AIX service node setup diff --git a/xCAT/postscripts/xcataixpost b/xCAT/postscripts/xcataixpost index 6c97ec276..5c27f5cd1 100755 --- a/xCAT/postscripts/xcataixpost +++ b/xCAT/postscripts/xcataixpost @@ -224,8 +224,13 @@ 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[0] == 1 || $ARGV[0] == 2) { + $TMP=`sed -e 's/UPDATENODE=0/UPDATENODE=1/g' $scriptname`; + `echo "$TMP" > $scriptname`; + } elsif ($ARGV[0] == 5) { + $TMP=`sed -e 's/UPDATENODE=0/UPDATENODE=1\\\nUPDATESECURITY=1\\\nexport UPDATESECURITY/g' $scriptname`; + `echo "$TMP" > $scriptname`; + } } if (@ARGV>1) { diff --git a/xCAT/postscripts/xcatdsklspost b/xCAT/postscripts/xcatdsklspost index 65c4c99a1..7f48bdb14 100755 --- a/xCAT/postscripts/xcatdsklspost +++ b/xCAT/postscripts/xcatdsklspost @@ -4,11 +4,12 @@ # # Generic xCAT post script for diskless nodes # This script is called in the following different palces: -# updatenode -P ... --> xcatdsklspost 1 ... -# updatenode -S --> xcatdsklspost 2 otherpkgs +# updatenode -P ... --> xcatdsklspost 1 -m/-M ... +# updatenode -S --> xcatdsklspost 2 -m/-M otherpkgs # moncfg rmcmon --> xcatdsklspost 3 configrmcnodes # node deployment --> xcatdsklspost # statelite mode --> xcatdsklspost 4 +# update security --> xcatdsklspost 5 -m/-M ... # ##################################################### download_postscripts() @@ -40,7 +41,32 @@ download_postscripts() return $rc } -MODE=$1 +# parse the arguments +ARGNUM=$#; +if [ -z $1 ]; then + NODE_DEPLOYMENT=1 +else + case $1 in + 1|2|5) + MODE=$1 + if [ $ARGNUM -gt 1 ]; then + if [ $2 == "-m" ]; then + P_SIP=$3 + else + if [ $2 == "-M" ]; then + P_SIP=$3 + new_ms=$P_SIP + fi + fi + fi + if [ $ARGNUM -gt 3 ]; then + POSTSCRIPTS=$4 + fi + ;; + 3|4) MODE=$1;; + esac +fi + if [ ! `uname` == Linux ]; then MYDIR=`dirname $0` @@ -63,21 +89,8 @@ rm -R -f /tmp/postage/* #here we get all the postscripts. Please do not change this behaviour because some scripts depend on others cd /tmp/postage -argnum=$#; -if [ "$MODE" != "4" ]; then # not statelite mode - downloaded=0; - #open the xcatinfo file to look for the master if it is not set - if [ -f /opt/xcat/xcatinfo ]; then - SIP=`grep 'XCATSERVER' /opt/xcat/xcatinfo |cut -d= -f2` - if [ -n "$SIP" ]; then - download_postscripts $SIP - if [ $? -eq 0 ]; then - downloaded=1 - fi - fi - fi -else # for statelite mode +if [ "$MODE" == "4" ]; then # for statelite mode # We have written the xCATSERVER info into the kernel command line!! for i in `cat /proc/cmdline`; do KEY=`echo $i | awk -F= '{print $1}'` @@ -96,74 +109,73 @@ else # for statelite mode logger -t xCAT "xcatdsklspost:xCAT management server IP can't be determined.\nexiting..."; exit; fi -fi - -if [ "$MODE" != "4" ]; then # NOSTATELITE: NOT for statelite MODE - -#try the -m if it is specified, -m is passed in the updatenode command -if [ $downloaded -eq 0 ]; then - #get the -m - while [ $# -gt 0 ] - do - case "$1" in - -m) SIP="$2"; break;; - -M) SIP="$2"; new_ms=$SIP; break;; - esac - shift - done - if [ -n "$SIP" ]; then - download_postscripts $SIP - if [ $? -eq 0 ]; then - downloaded=1 - fi +else # for common mode + downloaded=0; + #open the xcatinfo file to look for the master if it is not set + if [ -f /opt/xcat/xcatinfo ]; then + SIP=`grep 'XCATSERVER' /opt/xcat/xcatinfo |cut -d= -f2` + if [ -n "$SIP" ]; then + download_postscripts $SIP + if [ $? -eq 0 ]; then + downloaded=1 + fi + fi fi -fi - -#try the dhcp server, this is used for initial boot for the node. -if [ $downloaded -eq 0 ]; then - #setup $OSVER ,for SLES11 - if [ -e '/etc/SuSE-release' ]; then - OSVER=`grep -h VERSION /etc/SuSE-release |awk '{print $3}'` - fi - SIPS=`grep -h dhcp-server-identifier /var/lib/dhclient/dhclient*.leases 2> /dev/null|awk '{print $3}'|sed -e 's/;//'` - if [ -z "$SIPS" ]; then - SIPS=`grep -h DHCPSID /var/lib/dhcpcd/*.info 2> /dev/null|awk -F= '{print $2}'|sed -e s/\'//g` - fi - SIP=`echo $SIPS|awk '{printf $NF}' | tail -n 1` #Pick one for wget - if [ -n "$SIP" ]; then - download_postscripts $SIP - if [ $? -eq 0 ]; then - downloaded=1 - fi - elif [ -x "/sbin/dhcpcd" ]; then - # New dhcpcd doesn't creates *.info files. - for lease in $(ls "/var/lib/dhcpcd/"); do - iface="$(echo "$lease" | sed -n -e 's/^dhcpcd-\(.*\)\.lease$/\1/p')" - if [ -n "$iface" ]; then - SIP="$(dhcpcd -q -T "$iface" | sed -n -e '/new_dhcp_server_identifier/ s/.*=//p')" - if [ -n "$SIP" ]; then - download_postscripts $SIP - if [ $? -eq 0 ]; then - downloaded=1 - break + #try the -m if it is specified, -m is passed in the updatenode command + if [ $downloaded -eq 0 ]; then + if [ "XX$P_SIP" != "XX" ]; then + $SIP=$P_SIP + download_postscripts $SIP + if [ $? -eq 0 ]; then + downloaded=1 + fi + fi + fi + + #try the dhcp server, this is used for initial boot for the node. + if [ $downloaded -eq 0 ]; then + #setup $OSVER ,for SLES11 + if [ -e '/etc/SuSE-release' ]; then + OSVER=`grep -h VERSION /etc/SuSE-release |awk '{print $3}'` + fi + SIPS=`grep -h dhcp-server-identifier /var/lib/dhclient/dhclient*.leases 2> /dev/null|awk '{print $3}'|sed -e 's/;//'` + if [ -z "$SIPS" ]; then + SIPS=`grep -h DHCPSID /var/lib/dhcpcd/*.info 2> /dev/null|awk -F= '{print $2}'|sed -e s/\'//g` + fi + SIP=`echo $SIPS|awk '{printf $NF}' | tail -n 1` #Pick one for wget + if [ -n "$SIP" ]; then + download_postscripts $SIP + if [ $? -eq 0 ]; then + downloaded=1 + fi + elif [ -x "/sbin/dhcpcd" ]; then + # New dhcpcd doesn't creates *.info files. + for lease in $(ls "/var/lib/dhcpcd/"); do + iface="$(echo "$lease" | sed -n -e 's/^dhcpcd-\(.*\)\.lease$/\1/p')" + if [ -n "$iface" ]; then + SIP="$(dhcpcd -q -T "$iface" | sed -n -e '/new_dhcp_server_identifier/ s/.*=//p')" + if [ -n "$SIP" ]; then + download_postscripts $SIP + if [ $? -eq 0 ]; then + downloaded=1 + break + fi fi fi - fi - done + done + fi + fi + + #no hope, now let's get out of here. + if [ $downloaded -eq 0 ]; then + hn=`hostname` + echo "Cannot download the postscripts from the xCAT server for node $hn" + logger -t xCAT "xcatdsklspost:Cannot download the postscripts from the xCAT server for node $hn" + exit fi -fi - -#no hope, now let's get out of here. -if [ $downloaded -eq 0 ]; then - hn=`hostname` - echo "Cannot download the postscripts from the xCAT server for node $hn" - logger -t xCAT "xcatdsklspost:Cannot download the postscripts from the xCAT server for node $hn" - exit -fi - -fi #END NOSTATELITE +fi # finish the postscripts download if grep 'rw /rw tmpfs ' /proc/mounts >& /dev/null; then touch /var/lock/subsys/xcatmounts @@ -174,15 +186,7 @@ if grep 'rw /rw tmpfs ' /proc/mounts >& /dev/null; then ln -sf /etc/rc6.d/K10xcatmounts /etc/rc0.d/K10xcatmounts fi - -if [ "$MODE" != "4" ]; then - - #wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -t 0 -T 60 ftp://$SIP/postscripts 2> /tmp/wget.log - - #mv $SIP/install/postscripts/* /xcatpost; - mv $SIP/postscripts/* /xcatpost; - rm -rf $SIP -else # for statelite mode +if [ "$MODE" == "4" ]; then MAX=10 TRIES=1 while ! mount $SIP:/install/postscripts /xcatpost -r -n -o nolock @@ -199,17 +203,18 @@ else # for statelite mode logger -t xCAT "xcatdsklspost:Can't mount $SIP:/install/postscripts... Sleeping $S seconds then trying again" sleep $S done - +else # for statelite mode + #wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -t 0 -T 60 ftp://$SIP/postscripts 2> /tmp/wget.log + + #mv $SIP/install/postscripts/* /xcatpost; + chmod +x /xcatpost/*; # no effect for statelite mode, since the directory are readonly + mv $SIP/postscripts/* /xcatpost; + rm -rf $SIP fi cd /xcatpost; PATH=/xcatpost:$PATH export PATH -if [ "$MODE" != "4" ]; then - chmod +x /xcatpost/*; # no effect for statelite mode, since the directory are readonly -fi -#echo "PATH=$PATH" - if [ -x /usr/bin/openssl ]; then XCATSERVER="$SIP:3001" @@ -218,7 +223,6 @@ if [ -x /usr/bin/openssl ]; then export USEOPENSSLFORXCAT fi - /xcatpost/getpostscript.awk | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' > /tmp/mypostscript; MYCONT=`grep MASTER /tmp/mypostscript` #echo "MYCONT=$MYCONT" @@ -236,33 +240,17 @@ while [ -z "$MYCONT" ]; do let SLI=$RANDOM%10 let SLI=10+$SLI sleep $SLI - if [ "$MODE" != "4" ]; then - for SIP in $SIPS; do #Attempt against several candidates - if [ -x /usr/bin/openssl ]; then - XCATSERVER="$SIP:3001" - export XCATSERVER - USEOPENSSLFORXCAT=1 #Though this is the only method going forward, flag to allow backward compatibility with 2.2 generated netboot images - export USEOPENSSLFORXCAT - fi - /xcatpost/getpostscript.awk | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' > /tmp/mypostscript; - MYCONT=`grep MASTER /tmp/mypostscript` - if [ ! -z "$MYCONT" ]; then - break; - fi - done - else # for statelite mode - /xcatpost/getpostscript.awk | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' > /tmp/mypostscript; - MYCONT=`grep MASTER /tmp/mypostscript` - if [ ! -z "$MYCONT" ]; then - break; - fi + + /xcatpost/getpostscript.awk | sed -e 's/<[^>]*>//g'|egrep -v '^ *$'|sed -e 's/^ *//' > /tmp/mypostscript; + MYCONT=`grep MASTER /tmp/mypostscript` + if [ ! -z "$MYCONT" ]; then + break; fi -# echo "MYCONT=$MYCONT" done #save the MASTER into the xcatinfo file for node deployment case, #for updatenode case, only save it when -M is specified -if [ $argnum -eq 0 ] || [ "$MODE" == "4" ]; then +if [ $NODE_DEPLOYMENT -eq 1 ] || [ "$MODE" == "4" ]; then new_ms=`grep '^MASTER' /tmp/mypostscript |cut -d= -f2` fi if [ -n "$new_ms" ]; then @@ -281,14 +269,17 @@ fi # when called by the updatenode command #modify the UPDATENODE flag to 1 -if [ $argnum -gt 0 ] && [ "$MODE" != "4" ]; then +if [ "$MODE" == "1" ] || [ "$MODE" == "2" ]; then TMP=`sed -e 's/UPDATENODE=0/UPDATENODE=1/g' /tmp/mypostscript`; echo "$TMP" > /tmp/mypostscript; fi +if [ "$MODE" == "5" ]; then + TMP=`sed -e 's/UPDATENODE=0/UPDATENODE=1\nUPDATESECURITY=1\nexport UPDATESECURITY/g' /tmp/mypostscript`; + echo "$TMP" > /tmp/mypostscript; +fi # postscript name is specified with the updatenode -if [ $argnum -gt 2 ]; then - POSTS=$3 +if [ "XX$POSTSCRIPTS" != "XX" ]; then #remove all the postbootscripts TMP=`sed "/postbootscripts-start-here/,/postbootscripts-end-here/ d" /tmp/mypostscript` echo "$TMP" > /tmp/mypostscript @@ -297,7 +288,7 @@ if [ $argnum -gt 2 ]; then echo "$TMP" > /tmp/mypostscript echo "# postscripts-start-here\n" >> /tmp/mypostscript #add requested postscripts in - echo "$POSTS" | tr "," "\n" >> /tmp/mypostscript + echo "$POSTSCRIPTS" | tr "," "\n" >> /tmp/mypostscript echo "# postscripts-end-here\n" >> /tmp/mypostscript fi @@ -332,7 +323,7 @@ echo "$TMP" >> /tmp/mypostscript TMP=`sed "/postbootscripts-start-here/,/postbootscripts-end-here/ s/\(.*\)/run_ps \1/;s/run_ps\s*#/#/;s/run_ps\s*$//" /tmp/mypostscript` echo "$TMP" > /tmp/mypostscript -if [ $argnum -eq 0 ] || [ "$MODE" == "4" ]; then +if [ $NODE_DEPLOYMENT -eq 1 ] || [ "$MODE" == "4" ]; then #notify the server that we are done with netbooting CNS=`grep NODESTATUS= /tmp/mypostscript |awk -F = '{print $2}'` if [ -z "$CNS" ] || [ "$CNS" != "'0'" -a "$CNS" != "'N'" -a "$CNS" != "'n'" ]; then @@ -355,7 +346,7 @@ if [ "$MODE" == "4" ]; then fi #tell user it is done when this is called by updatenode command -if [ $argnum -gt 0 ] && [ "$MODE" != "4" ]; then +if [ "$MODE" == "1" ] || [ "$MODE" == "2" ] || [ "$MODE" == "5" ]; then echo "returned from postscript" fi