mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			413 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			413 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/perl
 | |
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| #(C)IBM Corp
 | |
| 
 | |
| #
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| =head1   aixremoteshell 
 | |
| 
 | |
|    This sets up the remote shell for root on the AIX node,such that root can
 | |
|    login with no password. The default is /bin/rsh and
 | |
|    /bin/rcp but can be overriden by setting the useSSHonAIX attribute in the 
 | |
|    site table to yes, in which case we will use ssh/scp.
 | |
|    The aixremoteshell postscripts will be called from remoteshell postscript
 | |
|    when on an AIX node.  It will input a -d ( for do)  flag, to indicate to run
 | |
|    If the flag is not input, the routine will do nothing.  This is to have only
 | |
|    remoteshell in the postscripts table whether supporting AIX or Linux,
 | |
|    and better support mixed clusters.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| #
 | |
| #  If USESSHONAIX does not exist or is no or 0 then
 | |
| #     setup .rhosts on the node
 | |
| #  else (ssh)
 | |
| #     setup the ssh keys on the node
 | |
| #  end
 | |
| 
 | |
| # MAIN
 | |
| use strict;
 | |
| use IO::Socket;
 | |
| my $useSocketSSL = eval { require IO::Socket::SSL; };
 | |
| if ($useSocketSSL) {
 | |
|     require IO::Socket::SSL;
 | |
| }
 | |
| use Getopt::Long;
 | |
| my $rc = 0;
 | |
| 
 | |
| # Override from site table
 | |
| my $usesshonaix           = $ENV{'USESSHONAIX'};
 | |
| my $master                = $ENV{'MASTER'};
 | |
| my $node                  = $ENV{'NODE'};
 | |
| my $nodetype              = $ENV{'NTYPE'};
 | |
| my $enablesshbetweennodes = $ENV{'ENABLESSHBETWEENNODES'};
 | |
| my $msg;
 | |
| my $home;
 | |
| my $cmd;
 | |
| my $runscript;
 | |
| my $username = "root";
 | |
| Getopt::Long::Configure("bundling");
 | |
| Getopt::Long::Configure("pass_through");
 | |
| GetOptions(
 | |
|     'd|do' => \$runscript
 | |
| );
 | |
| 
 | |
| #  the postscript only runs if called with -d flag from remoteshell
 | |
| unless ($runscript) {
 | |
|     my $msg = "aixremoteshell called without -d flag, do nothing.";
 | |
|     `logger -t xcat -p local4.err $msg`;
 | |
|     exit 0;
 | |
| }
 | |
| 
 | |
| my @root = split ':', (`/bin/grep ^$username /etc/passwd 2>&1`);
 | |
| $home = $root[5];
 | |
| 
 | |
| #  root home directory must be root system
 | |
| $rc = &runcmd("chown root $home");
 | |
| if ($rc != 0)
 | |
| {
 | |
|     my $msg = "It fails to chown root $home";
 | |
|     `logger -t xcat -p local4.err $msg`;
 | |
|     exit 1;
 | |
| }
 | |
| $rc = &runcmd("chgrp system $home");
 | |
| if ($rc != 0)
 | |
| {
 | |
|     my $msg = "It fails to chgrp system $home";
 | |
|     `logger -t xcat  -p local4.err $msg`;
 | |
|     exit 1;
 | |
| }
 | |
| 
 | |
| $usesshonaix =~ tr/a-z/A-Z/;    # convert to upper
 | |
| if ((!defined($usesshonaix)) || ($usesshonaix eq "0") || ($usesshonaix eq "NO"))
 | |
| {                               # setting up rsh
 | |
|                                 # setup .rhosts if not already setup
 | |
|     $cmd = "/bin/grep \"^$master root\" /.rhosts";
 | |
|     `$cmd 2>&1`;
 | |
|     my $rc = $? >> 8;
 | |
|     if ($rc)
 | |
|     {                           # if not found, then add entry in .rhosts
 | |
|         &runcmd("/bin/echo $master root >> /.rhosts");
 | |
|         chmod 0600, "/.rhosts";
 | |
|     }
 | |
| 
 | |
| }
 | |
| else
 | |
| {
 | |
|     # setting up ssh
 | |
|     if (&setupSSH != 0) {
 | |
|         my $msg = "Failed to setup ssh on $node.\n";
 | |
|         `logger -t xcat  -p local4.err  $msg`;
 | |
| 
 | |
|         #	print $msg;
 | |
|         exit 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| exit 0;
 | |
| 
 | |
| #
 | |
| # Subroutines
 | |
| #
 | |
| 
 | |
| sub setupSSH
 | |
| {
 | |
|     my $sshdconfig = "/etc/ssh/sshd_config";
 | |
|     my $sshconfig  = "/etc/ssh/ssh_config";
 | |
| 
 | |
|     if (-e $sshdconfig)
 | |
|     {    # ssh installed
 | |
|         my $tmp = "$sshdconfig.ORIG";
 | |
|         if (!(-e "$sshdconfig.ORIG"))
 | |
|         {
 | |
|             &runcmd("cp $sshdconfig $sshdconfig.ORIG");
 | |
|         }
 | |
|         &runcmd("echo \"KeyRegenerationInterval 0\" >>$sshdconfig");
 | |
|         &runcmd("echo \"X11Forwarding yes\" >>$sshdconfig");
 | |
|         &runcmd("echo \"MaxStartups 1024\" >>$sshdconfig");
 | |
|         &runcmd("echo \"ListenAddress ::\" >>$sshdconfig");
 | |
|         &runcmd("echo \"ListenAddress 0.0.0.0\" >>$sshdconfig");
 | |
| 
 | |
|         #&runcmd("echo \"PasswordAuthentication no\" >>$sshdconfig");
 | |
|         if (!(-e "$sshconfig.ORIG"))
 | |
|         {
 | |
|             &runcmd("cp $sshconfig $sshconfig.ORIG");
 | |
|         }
 | |
|         &runcmd("echo \"StrictHostKeyChecking no\" >>$sshconfig");
 | |
|     }
 | |
|     else
 | |
|     {    # ssh not installed
 | |
|         my $msg = "Failed to setup ssh on $node, ssh not installed. \n";
 | |
|         `logger -t xcat -p local4.err  $msg`;
 | |
|         exit 0;
 | |
|     }
 | |
| 
 | |
|     if (-e "/xcatpost/_ssh")
 | |
|     {    # ssh public key available
 | |
|         $rc = &runcmd("mkdir -p /.ssh");
 | |
|         if ($rc == 0)
 | |
|         {
 | |
|             $rc = &runcmd("cp -fp /xcatpost/_ssh/* /.ssh");
 | |
|             if ($rc == 0)
 | |
|             {
 | |
|                 $rc = &runcmd("chmod 0700 /.ssh");
 | |
|                 $rc = &runcmd("chmod 0600 /.ssh/*");
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {    # ssh keys not available
 | |
|         my $msg = "Failed to setup ssh on $node, ssh keys not available. \n";
 | |
|         `logger -t xcat  -p local4.err $msg`;
 | |
|         exit 0;
 | |
|     }
 | |
| 
 | |
|     #  get the name of my service node/NIM master from /etc/xcatinfo
 | |
|     #  ! use value of MASTER env variable instead
 | |
|     $::servnode = $master;
 | |
| 
 | |
|     my $response = &getresponse("ssh_dsa_hostkey");
 | |
|     if (defined($response)) {
 | |
|         my $fd;
 | |
|         my $filename = "/etc/ssh/ssh_host_dsa_key";
 | |
|         &runcmd("mkdir -p /etc/ssh");
 | |
|         open($fd, '>', $filename);
 | |
|         print $fd $response;
 | |
|         close($fd);
 | |
| 
 | |
|         # set the permissions
 | |
|         my $cmd = "chmod 600 $filename > /dev/null 2>&1";
 | |
|         &runcmd($cmd);
 | |
|     }
 | |
|     else {
 | |
|         $msg = "aixremoteshell: Could not get ssh_host_dsa_key file.\n";
 | |
|         `logger -t xcat  -p local4.err  $msg`;
 | |
|     }
 | |
| 
 | |
|     my $response = &getresponse("ssh_rsa_hostkey");
 | |
|     if (defined($response)) {
 | |
|         my $fd;
 | |
|         my $filename = "/etc/ssh/ssh_host_rsa_key";
 | |
|         &runcmd("mkdir -p /etc/ssh");
 | |
|         open($fd, '>', $filename);
 | |
|         print $fd $response;
 | |
|         close($fd);
 | |
| 
 | |
|         # set the permissions
 | |
|         my $cmd = "chmod 600 $filename > /dev/null 2>&1";
 | |
|         &runcmd($cmd);
 | |
|     }
 | |
|     else {
 | |
|         $msg = "aixremoteshell: Could not get ssh_host_rsa_key file.\n";
 | |
|         `logger -t xcat  -p local4.err $msg`;
 | |
|     }
 | |
| 
 | |
|     # is there is a ecdsa host key on the node, then get the one from the MN/SN
 | |
|     my $filename = "/etc/ssh/ssh_host_ecdsa_key";
 | |
|     if (-e $filename) {
 | |
|         my $response = &getresponse("ssh_ecdsa_hostkey");
 | |
|         if (defined($response)) {
 | |
|             my $fd;
 | |
|             &runcmd("mkdir -p /etc/ssh");
 | |
|             open($fd, '>', $filename);
 | |
|             print $fd $response;
 | |
|             close($fd);
 | |
| 
 | |
|             # set the permissions
 | |
|             my $cmd = "chmod 600 $filename > /dev/null 2>&1";
 | |
|             &runcmd($cmd);
 | |
|         }
 | |
|         else {
 | |
|             $msg = "aixremoteshell: Could not get ssh_host_ecdsa_key file.\n";
 | |
|             `logger -t xcat  -p local4.err $msg`;
 | |
|         }
 | |
|     }
 | |
|     if ($nodetype eq "service") {
 | |
|         &runcmd("mkdir -p /etc/xcat/hostkeys; cp /etc/ssh/ssh* /etc/xcat/hostkeys/. > /dev/null 2>&1");
 | |
|     }
 | |
| 
 | |
|     # Decide whether to enable passwordless ssh between the nodes
 | |
|     if ($enablesshbetweennodes eq "YES") {
 | |
|         my $response = &getresponse("ssh_root_key");
 | |
|         if (defined($response)) {
 | |
|             my $fd;
 | |
|             my $filename = "/.ssh/id_rsa";
 | |
|             &runcmd("mkdir -p /.ssh");
 | |
|             open($fd, '>', $filename);
 | |
|             print $fd $response;
 | |
|             close($fd);
 | |
| 
 | |
|             # set the permissions
 | |
|             my $cmd = "chmod 600 $filename > /dev/null 2>&1";
 | |
|             &runcmd($cmd);
 | |
| 
 | |
|             if (-f "/.ssh/id_rsa") {
 | |
|                 &runcmd("ssh-keygen -y -f /.ssh/id_rsa > /.ssh/id_rsa.pub");
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             $msg = "aixremoteshell: Could not get id_rsa file.\n";
 | |
|             `logger -t xcat  -p local4.err  $msg`;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #####################################################
 | |
| #
 | |
| #  getresponse
 | |
| #       Request info from xcatd on the management node
 | |
| #
 | |
| #	- uses SSL socket on port 3001 to connect to MN xcatd
 | |
| #		to make the request for info
 | |
| #
 | |
| #####################################################
 | |
| sub getresponse
 | |
| {
 | |
|     my ($req) = @_;
 | |
| 
 | |
|     my $port = "3001";
 | |
| 
 | |
|     # open listener connection to wait for check from management node
 | |
|     my $lpid = &openlistener();
 | |
| 
 | |
|     # open a socket to request credentials
 | |
|     my $sock = IO::Socket::SSL->new(
 | |
|         PeerAddr => $::servnode,
 | |
|         PeerPort => $port,
 | |
|         Proto    => 'tcp',
 | |
|     );
 | |
| 
 | |
|     unless ($sock) {
 | |
|         my $msg = "aixremoteshell: Cannot connect to host \'$::servnode\'\n";
 | |
|         `logger -t xcat  -p local4.err  $msg`;
 | |
| 
 | |
|         #print $msg;
 | |
|         kill 2, $lpid;
 | |
|         return undef;
 | |
|     }
 | |
| 
 | |
|     # request must be in XML format
 | |
|     print $sock "<xcatrequest>\n";
 | |
|     print $sock "   <command>getcredentials</command>\n";
 | |
|     print $sock "   <arg>$req</arg>\n";
 | |
|     print $sock "   <callback_port>300</callback_port>\n";
 | |
|     print $sock "</xcatrequest>\n";
 | |
| 
 | |
|     #TODO - do we have to try again after waiting for a bit????
 | |
|     my $response = '';
 | |
|     my $line;
 | |
|     while (defined($line = <$sock>)) {
 | |
| 
 | |
|         # skip xml tags
 | |
|         next if ($line =~ /^\s*</);
 | |
| 
 | |
|         # once we get to serverdone we have the whole response
 | |
|         if ($line =~ m/<\/serverdone>/) {
 | |
|           last:
 | |
|         }
 | |
|         $response .= $line;
 | |
|     }
 | |
| 
 | |
|     close($sock);
 | |
| 
 | |
|     kill 2, $lpid;
 | |
|     if ($response) {
 | |
|         return $response;
 | |
|     }
 | |
|     return undef;
 | |
| }
 | |
| 
 | |
| #####################################################
 | |
| #
 | |
| #  openlistener
 | |
| #   - fork a child process to respond to a check from the MN
 | |
| #
 | |
| #####################################################
 | |
| sub openlistener
 | |
| {
 | |
|     my $node = $ENV{'NODE'};
 | |
| 
 | |
|     # fork a child process to open a socket to listen for communication
 | |
|     #	from the server
 | |
|     my $pid = fork;
 | |
|     unless (defined $pid) {
 | |
| 
 | |
|         # fork failed
 | |
|         $msg = "aixremoteshell: Could not fork process.\n";
 | |
|         `logger -t xcat  -p local4.err  $msg`;
 | |
|         print $msg;
 | |
|         return undef;
 | |
|     }
 | |
| 
 | |
|     if ($pid != 0) {
 | |
| 
 | |
|         # This is the parent process, just return
 | |
|         return $pid;
 | |
|     }
 | |
| 
 | |
|     my $listener = IO::Socket::INET->new(
 | |
|         LocalPort => '300',
 | |
|         Proto     => 'tcp',
 | |
|         Listen    => '64',
 | |
|         Reuse     => 1
 | |
|     );
 | |
| 
 | |
|     unless ($listener) {
 | |
|         my $msg = "aixremoteshell: Cannot open socket on \'$node\'\n";
 | |
|         `logger -t xcat  -p local4.err $msg`;
 | |
|         print $msg;
 | |
|         exit 1;
 | |
|     }
 | |
| 
 | |
|     #	xcatd sends a quick req to see if we are really asking
 | |
|     #  	for info - this listener checks for the req and says ok
 | |
|     my $client;
 | |
|     while ($client = $listener->accept()) {
 | |
| 
 | |
|         # $client is the new connection
 | |
|         my $text = <$client>;
 | |
| 
 | |
|         #  see if we got "CREDOKBYYOU?"
 | |
|         if ($text =~ /CREDOKBYYOU?/) {
 | |
|             print $client "CREDOKBYME";
 | |
|             close($client);
 | |
|             close($listener);
 | |
|             exit 0;
 | |
|         }
 | |
|         close($client);
 | |
|     }
 | |
|     close($client);
 | |
|     close($listener);
 | |
|     exit 0;
 | |
| }
 | |
| 
 | |
| #
 | |
| # run the command
 | |
| #
 | |
| sub runcmd
 | |
| {
 | |
|     my ($cmd) = @_;
 | |
|     my $rc = 0;
 | |
|     $cmd .= ' 2>&1';
 | |
|     $::outref = `$cmd`;
 | |
|     if ($?)
 | |
|     {
 | |
|         $rc = $? >> 8;
 | |
|         if ($rc > 0)
 | |
|         {
 | |
|             my $msg = "$cmd returned rc=$rc @$::outref\n";
 | |
|             `logger -t xcat  -p local4.info $msg`;
 | |
| 
 | |
|             #			print $msg;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 |