From a7b74a09bee2a55fdb905c49accedbaf333f4373 Mon Sep 17 00:00:00 2001 From: lissav Date: Thu, 20 Dec 2007 19:02:45 +0000 Subject: [PATCH] Add support to update ssh keys git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@199 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT-2.0/xCAT/Utils.pm | 451 ++++++++++++++++++++++++++++++------ 1 file changed, 381 insertions(+), 70 deletions(-) diff --git a/perl-xCAT-2.0/xCAT/Utils.pm b/perl-xCAT-2.0/xCAT/Utils.pm index f6f19a08c..2fd2eb214 100644 --- a/perl-xCAT-2.0/xCAT/Utils.pm +++ b/perl-xCAT-2.0/xCAT/Utils.pm @@ -7,6 +7,7 @@ use Data::Dumper; use xCAT::NodeRange; #-------------------------------------------------------------------------------- + =head1 xCAT::Utils =head2 Package Description @@ -14,7 +15,9 @@ use xCAT::NodeRange; This program module file, is a set of utilities used by xCAT commands. =cut + #-------------------------------------------------------------------------------- + =head3 quote Quote a string, taking into account embedded quotes. This function is most @@ -35,6 +38,7 @@ This program module file, is a set of utilities used by xCAT commands. Comments: none =cut + #-------------------------------------------------------------------------------- sub quote { @@ -65,6 +69,7 @@ sub quote } #------------------------------------------------------------------------------- + =head3 isAIX returns 1 if localHost is AIX Arguments: @@ -90,6 +95,7 @@ sub isAIX } #------------------------------------------------------------------------------- + =head3 isLinux returns 1 if localHost is Linux Arguments: @@ -106,6 +112,7 @@ sub isAIX Comments: none =cut + #------------------------------------------------------------------------------- sub isLinux { @@ -390,10 +397,8 @@ sub get_site_attribute return $values; } - - - #----------------------------------------------------------------------- + =head3 add_cron_job This function adds a new cron job. @@ -411,37 +416,47 @@ sub get_site_attribute none =cut + #------------------------------------------------------------------------ -sub add_cron_job { - $newentry = shift; - if ($newentry =~ /xCAT::Utils/) { - $newentry=shift; - } - #read the cron tab entries - my @tabs=`/usr/bin/crontab -l 2>/dev/null`; - my @newtabs=(); - foreach(@tabs) { - chomp($_); - # stop adding if it's already there - if ($_ eq $newentry) { return (0, "started"); } - #skip headers for Linux - next if $_ =~ m/^\#.+(DO NOT EDIT THIS FILE|\(.+ installed on |Cron version )/; - push(@newtabs, $_); - } +sub add_cron_job +{ + $newentry = shift; + if ($newentry =~ /xCAT::Utils/) + { + $newentry = shift; + } - #add new entries to the cron tab - push(@newtabs, $newentry); - my $tabname=""; - if (xCAT::Utils::isLinux) { $tabname="-";} - open(CRONTAB, "|/usr/bin/crontab $tabname") or return (1, "cannot open crontab."); - foreach (@newtabs) { print CRONTAB $_."\n"; } - close(CRONTAB); + #read the cron tab entries + my @tabs = `/usr/bin/crontab -l 2>/dev/null`; + my @newtabs = (); + foreach (@tabs) + { + chomp($_); - return (0, ""); + # stop adding if it's already there + if ($_ eq $newentry) { return (0, "started"); } + + #skip headers for Linux + next + if $_ =~ + m/^\#.+(DO NOT EDIT THIS FILE|\(.+ installed on |Cron version )/; + push(@newtabs, $_); + } + + #add new entries to the cron tab + push(@newtabs, $newentry); + my $tabname = ""; + if (xCAT::Utils::isLinux) { $tabname = "-"; } + open(CRONTAB, "|/usr/bin/crontab $tabname") + or return (1, "cannot open crontab."); + foreach (@newtabs) { print CRONTAB $_ . "\n"; } + close(CRONTAB); + + return (0, ""); } - #----------------------------------------------------------------------- + =head3 remove_cron_job This function removes a new cron job. @@ -461,36 +476,44 @@ sub add_cron_job { none =cut + #------------------------------------------------------------------------ -sub remove_cron_job { - $job = shift; - if ($job =~ /xCAT::Utils/) { - $job=shift; - } +sub remove_cron_job +{ + $job = shift; + if ($job =~ /xCAT::Utils/) + { + $job = shift; + } - #read the cron tab entries and remove the one that contains $job - my @tabs=`/usr/bin/crontab -l 2>/dev/null`; - my @newtabs=(); - foreach(@tabs) { - chomp($_); - # stop adding if it's already there - next if index($_, $job, 0) >= 0; - #skip headers for Linux - next if $_ =~ m/^\#.+(DO NOT EDIT THIS FILE|\(.+ installed on |Cron version )/; - push(@newtabs, $_); - } - - #refresh the cron - my $tabname=""; - if (xCAT::Utils::isLinux) { $tabname="-";} - open(CRONTAB, "|/usr/bin/crontab $tabname") or return (1, "cannot open crontab."); - foreach (@newtabs) { print CRONTAB $_."\n"; } - close(CRONTAB); + #read the cron tab entries and remove the one that contains $job + my @tabs = `/usr/bin/crontab -l 2>/dev/null`; + my @newtabs = (); + foreach (@tabs) + { + chomp($_); - return (0, ""); + # stop adding if it's already there + next if index($_, $job, 0) >= 0; + + #skip headers for Linux + next + if $_ =~ + m/^\#.+(DO NOT EDIT THIS FILE|\(.+ installed on |Cron version )/; + push(@newtabs, $_); + } + + #refresh the cron + my $tabname = ""; + if (xCAT::Utils::isLinux) { $tabname = "-"; } + open(CRONTAB, "|/usr/bin/crontab $tabname") + or return (1, "cannot open crontab."); + foreach (@newtabs) { print CRONTAB $_ . "\n"; } + close(CRONTAB); + + return (0, ""); } - #------------------------------------------------------------------------------- =head3 runcmd @@ -503,7 +526,7 @@ sub remove_cron_job { Returns: see below Globals: - $::RUNCMD_RC + $::RUNCMD_RC , $::CALLBACK Error: Normally, if there is an error running the cmd,it will display the error and exit with the cmds exit code, unless exitcode @@ -537,11 +560,9 @@ sub runcmd { if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; } - } - if (!$xCAT::Utils::NO_MESSAGES) - { - xCAT::MsgUtils->message("V", "Running Command: $cmd\n"); - + } + if ($::VERBOSE) { + xCAT::MsgUtils->message("I", "Running Command: $cmd\n"); } my $outref = []; @$outref = `$cmd`; @@ -579,7 +600,15 @@ sub runcmd chomp $errmsg; } - if (!$xCAT::Utils::NO_MESSAGES) + if ($::CALLBACK) + { + my %rsp; + $rsp->{data}->[0] = + "Command failed: $cmd. Error message: $errmsg.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + + } + else { xCAT::MsgUtils->message("E", "Command failed: $cmd. Error message: $errmsg.\n"); @@ -605,14 +634,296 @@ sub runcmd } } + +#-------------------------------------------------------------------------------- + +=head3 getHomeDir + + Get the path the user home directory from /etc/passwd. + + Arguments: + none + Returns: + path to user home directory. + Globals: + none + Error: + none + Example: + $myHome = xCAT::Utils->getHomeDir(); + Comments: + none + +=cut + +#-------------------------------------------------------------------------------- + +sub getHomeDir +{ + my ($class, $username) = @_; + my @user = split ':', (`/bin/grep ^$username /etc/passwd 2>&1`); + my $home = $user[5]; + return $home; +} + +#-------------------------------------------------------------------------------- + +=head3 setupSSH + + Transfers the ssh keys to setup ssh to the input nodes. + + Arguments: + Array of nodes + Returns: + + Globals: + $::XCATROOT , $::CALLBACK + Error: + 0=good, 1=error + Example: + xCAT::Utils->setupSSH(@target_nodes); + Comments: + Does not setup known_hosts. Assumes automatically + setup by SSH ( ssh config option StrictHostKeyChecking no should + be set in the ssh config file). + +=cut + +#-------------------------------------------------------------------------------- +sub setupSSH +{ + my ($class, $ref_nodes) = @_; + my @nodes = $ref_nodes; + my @badnodes = (); + my $n_str = join ',', @nodes; + my $SSHdir = "/install/postscripts/.ssh"; + if ($::XCATROOT) + { + $::REMOTESHELL_EXPECT = "$::XCATROOT/sbin/remoteshell.expect"; + } + else + { + $::REMOTESHELL_EXPECT = "/opt/xcat/sbin/remoteshell.expect"; + } + $::REMOTE_SHELL = "/bin/ssh"; + + # make the directory to hold keys to transfer to the nodes + if (!-d $SSHdir) + { + mkdir("/install", 0755); + mkdir("/install/postscripts", 0755); + mkdir("/install/postscripts/.ssh", 0755); + } + + # Generate the keys + xCAT::Utils->runcmd("$::REMOTESHELL_EXPECT -k", 0); + if ($::RUNCMD_RC != 0) + { # error + my %rsp; + $rsp->{data}->[0] = "remoteshell.expect failed generating keys.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + + } + + # Copy the keys to the directory + my $rc = xCAT::Utils->cpSSHFiles($SSHdir); + if ($rc != 0) + { # error + my %rsp; + $rsp->{data}->[0] = "Error running cpSSHFiles.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + return 1; + + } + + open(FILE, ">$SSHdir/copy.perl") + or die "cannot open file $SSHdir/copy.perl\n"; + + # build the perl copy script in $SSHdir/copy.perl + print FILE "#!/usr/bin/perl +my (\$name,\$passwd,\$uid,\$gid,\$quota,\$comment,\$gcos,\$dir,\$shell,\$expire) = getpwnam(\"root\"); +my \$home = \$dir; +umask(0077); +\$dest_dir = \"\$home/.ssh/\"; +if (! -d \"\$dest_dir\" ) { + # create a local directory + \$cmd = \"mkdir -p \$dest_dir\"; + system(\"\$cmd\"); + chmod 0700, \$dest_dir; +} +`cat /tmp/.ssh/authorized_keys >> \$home/.ssh/authorized_keys 2>&1`; +`cat /tmp/.ssh/authorized_keys2 >> \$home/.ssh/authorized_keys2 2>&1`; +`rm -f /tmp/.ssh/authorized_keys 2>&1`; +`rm -f /tmp/.ssh/authorized_keys2 2>&1`; +`rm -f /tmp/.ssh/copy.perl 2>&1`; +rmdir(\"/tmp/.ssh\");"; + close FILE; + chmod 0744, "$SSHdir/copy.perl"; + + # end build Perl code + + #set an ENV var if more than 10 nodes for remoteshell.expect + my $num_nodes = scalar(@nodes); + if ($num_nodes > 10) + { + $ENV{'XCAT_UPD_MULTNODES'} = 1; + } + + # send the keys to the nodes + # + my $cmd = "$::REMOTESHELL_EXPECT -s $n_str"; + my $rc = system("$cmd") >> 8; + if ($rc) + { + my %rsp; + $rsp->{data}->[0] = "remoteshell.expect failed sending keys.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + + } + + # must always check to see if worked, run test + foreach my $n (@nodes) + { + my $cmd = "$::REMOTESHELL_EXPECT -t $::REMOTE_SHELL $n "; + my @cmdout = `$cmd 2>&1`; + chomp(@cmdout); # take the newline off + my $rc = $? >> 8; + if ($rc) + { + push @badnodes, $n; + } + } + + xCAT::Utils->runcmd("/bin/stty echo", 0); + delete $ENV{'XCAT_UPD_MULTNODES'}; + + if (@badnodes) + { + my $nstring = join ',', @badnodes; + my %rsp; + $rsp->{data}->[0] = + "SSH setup failed for the following nodes: $nstring.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + return @badnodes; + } + else + { + my %rsp; + $rsp->{data}->[0] = "$::REMOTE_SHELL setup is complete.\n"; + xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); + return 0; + } +} + +#-------------------------------------------------------------------------------- + +=head3 cpSSHFiles + + Copies the ssh keyfiles and the copy perl script into + /install/postscripts/.ssh. + + Arguments: + directory path + Returns: + + Globals: + $::CALLBACK + Error: + + Example: + xCAT::Utils->cpSSHFiles; + + Comments: + none + +=cut + +#-------------------------------------------------------------------------------- + +sub cpSSHFiles +{ + my ($class, $SSHdir) = @_; + my ($cmd, $rc); + if ($::VERBOSE) + { + my %rsp; + $rsp->{data}->[0] = "Copying SSH Keys"; + xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); + } + my $home = xCAT::Utils->getHomeDir("root"); + + my $authorized_keys = "$SSHdir/authorized_keys"; + my $authorized_keys2 = "$SSHdir/authorized_keys2"; + if ( !(-e "$home/.ssh/identity.pub") + || !(-e "$home/.ssh/id_rsa.pub") + || !(-e "$home/.ssh/id_dsa.pub")) + { + return 1; + } + $cmd = " cp $home/.ssh/identity.pub $authorized_keys"; + xCAT::Utils->runcmd($cmd, 0); + if ($::RUNCMD_RC != 0) + { + my %rsp; + $rsp->{data}->[0] = "$cmd failed.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + return (1); + + } + else + { + if ($::VERBOSE) + { + my %rsp; + $rsp->{data}->[0] = "$cmd succeeded.\n"; + xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); + } + } + + $cmd = "cp $home/.ssh/id_rsa.pub $authorized_keys2"; + xCAT::Utils->runcmd($cmd, 0); + if ($::RUNCMD_RC != 0) + { + my %rsp; + $rsp->{data}->[0] = "$cmd failed.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + return (1); + + } + else + { + if ($::VERBOSE) + { + my %rsp; + $rsp->{data}->[0] = "$cmd succeeded.\n"; + xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); + } + } + + $cmd = "cat $home/.ssh/id_dsa.pub >> $authorized_keys2"; + xCAT::Utils->runcmd($cmd, 0); + if ($::RUNCMD_RC != 0) + { + my %rsp; + $rsp->{data}->[0] = "$cmd failed.\n"; + xCAT::MsgUtils->message("E", $rsp, $::CALLBACK); + return (1); + + } + else + { + if ($::VERBOSE) + { + my %rsp; + $rsp->{data}->[0] = "$cmd succeeded.\n"; + xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); + } + } + + if (!(-e "$authorized_keys") || !(-e "$authorized_keys2")) + { + return 1; + } + return (0); +} 1; - - - - - - - - - -