From 92414fbcd190c6ea835749990081fbfb64bb724d Mon Sep 17 00:00:00 2001 From: linggao Date: Tue, 13 Nov 2012 22:03:57 +0000 Subject: [PATCH] added support for xdsh to ethernet switches git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@14318 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT/xCAT/DSHCLI.pm | 39 ++++- xCAT-server/lib/perl/xCAT/RShellAPI.pm | 181 +++++++++++++++++++++++ xCAT-server/lib/perl/xCAT/SSHInteract.pm | 73 ++++----- xCAT-server/sbin/rshell_api | 33 +++++ xCAT-server/share/xcat/EthSwitch/config | 5 + xCAT-server/xCAT-server.spec | 3 + 6 files changed, 297 insertions(+), 37 deletions(-) create mode 100644 xCAT-server/lib/perl/xCAT/RShellAPI.pm create mode 100755 xCAT-server/sbin/rshell_api create mode 100644 xCAT-server/share/xcat/EthSwitch/config diff --git a/perl-xCAT/xCAT/DSHCLI.pm b/perl-xCAT/xCAT/DSHCLI.pm index d8c99d3c0..341271896 100644 --- a/perl-xCAT/xCAT/DSHCLI.pm +++ b/perl-xCAT/xCAT/DSHCLI.pm @@ -2,6 +2,11 @@ # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT::DSHCLI; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl"; use File::Basename; @@ -662,7 +667,7 @@ sub _execute_dsh if !$signal_interrupt_flag; } - elsif (!defined($target_rc) && !$dsh_cmd_background && ($::DSH_MELLANOX_SWITCH==0)) + elsif (!defined($target_rc) && !$dsh_cmd_background && ($::DSH_MELLANOX_SWITCH==0) && ($$options{'devicetype'}!~ /EthSwitch/)) { # report error status --nodestatus # Note the message below for node status must @@ -976,6 +981,32 @@ sub fork_fanout_dsh ) = @_; + #get username and passeword for ether net switches (EthSwitch type) + if ($$options{'devicetype'} =~ /EthSwitch/) { + if (@$targets_waiting > 0) { + if ($ENV{'DSH_REMOTE_PASSWORD'}) { + foreach my $t (keys(%$resolved_targets)) { + $resolved_targets->{$t}->{'password'}=$ENV{'DSH_REMOTE_PASSWORD'}; + $resolved_targets->{$t}->{'user'}=$$options{'user'}; + } + } else { + #get user name and password from the switches table + my $switchestab=xCAT::Table->new('switches',-create=>0); + + my $switchents = $switchestab->getNodesAttribs($targets_waiting,[qw/switch sshusername sshpassword/]); + foreach my $entry (values %$switchents) { + my $switch=$entry->[0]->{switch}; + if (defined($entry->[0]->{sshusername})) { + $resolved_targets->{$switch}->{'user'}=$entry->[0]->{sshusername}; + } + if (defined($entry->[0]->{sshpassword})) { + $resolved_targets->{$switch}->{'password'}=$entry->[0]->{sshpassword}; + } + } + } + } + } + while (@$targets_waiting && (keys(%$targets_active) < $$options{'fanout'})) { @@ -1041,6 +1072,12 @@ sub fork_fanout_dsh || $$options{'node-rsh-defaults'}{$context}; ($remote_shell =~ /\/ssh$/) && ($rsh_extension = 'SSH'); + if ($$options{'devicetype'} =~ /EthSwitch/) { + $remote_shell = "$::XCATROOT/sbin/rshell_api"; + $rsh_extension='RShellAPI'; + $rsh_config{'password'}=$$target_properties{'password'}; + } + # will not set -n for any command, causing problems # with running xdsh to install rpms and start xcatd on AIX # if IB switch device, do not set -n, causes no returncode diff --git a/xCAT-server/lib/perl/xCAT/RShellAPI.pm b/xCAT-server/lib/perl/xCAT/RShellAPI.pm new file mode 100644 index 000000000..08a61e67a --- /dev/null +++ b/xCAT-server/lib/perl/xCAT/RShellAPI.pm @@ -0,0 +1,181 @@ +#!/usr/bin/perl +# IBM(c) 2012 EPL license http://www.eclipse.org/legal/epl-v10.html +package xCAT::RShellAPI; + +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl"; +use xCAT::MsgUtils; + +####################################################### +=head3 + remote_shell_command + + This routine constructs an remote shell command using the + given arguments + Arguments: + $class - Calling module name (discarded) + $config - Reference to remote shell command configuration hash table + $exec_path - Path to ssh executable + Returns: + A command array for the ssh command with the appropriate + arguments as defined in the $config hash table +=cut +##################################################### +sub remote_shell_command { + my ( $class, $config, $exec_path ) = @_; + + my @command = (); + + push @command, $exec_path; + + if ( $$config{'options'} ) { + my @options = split ' ', $$config{'options'}; + push @command, @options; + } + + my @tmp; + if ($$config{'user'} && ($$config{'user'} !~ /^none$/i)) { + @tmp=split(' ', "-l $$config{'user'}"); + push @command, @tmp; + } + if ($$config{'password'} && ($$config{'password'} !~ /^none$/i)) { + @tmp=split(' ', "-p $$config{'password'}"); + push @command, @tmp; + } + push @command, "$$config{'hostname'}"; + push @command, $$config{'command'}; + + return @command; +} + +sub run_remote_shell_api { + require xCAT::SSHInteract; + my $node=shift; + my $user=shift; + my $passwd=shift; + my $args = join(" ", @_); + my $t; + + if(0) { + print "start SSH session...\n"; + $t = new xCAT::SSHInteract( + -username=>$user, + -password=>$passwd, + -host=>$node, + -nokeycheck=>1, + -output_record_separator=>"\r", + Timeout=>5, + Errmode=>'return', + Prompt=>'/.*[\>\#]$/', + ); + }; + my $errmsg=$@; + $errmsg =~ s/ at (.*) line (\d)+//g; + print "$errmsg\n"; + + my $rc=1; + if (not $t) {#ssh failed.. fallback to a telnet attempt + print "start Telnet session...\n"; + require Net::Telnet; + $t = new Net::Telnet( + Timeout=>5, + Errmode=>'return', + Prompt=>'/.*[\>\#]$/', + ); + $rc = $t->open($node); + if ($rc) { + my $pw_tried=0; + my ($prematch, $match)= $t->waitfor(Match => '/login[: ]*$/i', + Match => '/username[: ]*$/i', + Match => '/password[: ]*$/i', + Errmode => "return"); + if (($match =~ /username[: ]*$/i) || ($match =~ /login[: ]*$/i )) { + # user name + if ($user) { + if (! $t->put(String => "$user\n", + Errmode => "return")) { + print "login disconnected\n"; + return [1, "login disconnected"]; + } + } else { + print "Username is required.\n"; + return [1, "Username is required."]; + } + } elsif ($match =~ /password[: ]*$/i) { + if ($passwd) { + $pw_tried=1; + if (! $t->put(String => "$passwd\n", + Errmode => "return")) { + print "login disconnected\n"; + return [1, "login disconnected"]; + } + } else { + print "password is required.\n"; + return [1, "Passwordis required."]; + } + } + + ($prematch, $match)= $t->waitfor(Match => '/login[: ]*$/i', + Match => '/username[: ]*$/i', + Match => '/password[: ]*$/i', + Errmode => "return"); + + if (($match =~ /username[: ]*$/i) || ($match =~ /login[: ]*$/i )) { + print "Incorrect username.\n"; + return [1, "Incorrect username."]; + } elsif ($match =~ /password[: ]*$/i) { + if ($pw_tried) { + print "Incorrect password.\n"; + return [1, "Incorrect password."]; + } + if ($passwd) { + if (! $t->put(String => "$passwd\n", + Errmode => "return")) { + print "login disconnected\n"; + return [1, "login disconnected"]; + } + } else { + print "password is required.\n"; + return [1, "Passwordis required."]; + } + } + + + #Wait for command prompt + ($prematch, $match) = $t->waitfor(Match => '/login[: ]*$/i', + Match => '/username[: ]*$/i', + Match => '/password[: ]*$/i', + Match => '/\>/', + Errmode => "return"); + + #print "prematch=$prematch, match=$match\n"; + if ($match =~ /login[: ]*$/i or $match =~ /username[: ]*$/i or $match =~ /password[: ]*$/i) { + print "login failed: bad login name or password\n"; + return [1, "login failed: bad login name or password"]; + } + } + } + if (!$rc) { + print "Error: " . $t->errmsg . "\n"; + return([1, $t->errmsg]); + } + + $rc = 0; + my $output; + my @cmd_array=split(';', $args); + foreach my $cmd (@cmd_array) { + #my @data = $t->cmd($cmd); + my @data= $t->cmd(String =>$cmd); + $output .= "command:$cmd\n@data\n"; + print "command:$cmd\n@data\n"; + } + $t->close(); + return [0, $output]; +} + + + +1; diff --git a/xCAT-server/lib/perl/xCAT/SSHInteract.pm b/xCAT-server/lib/perl/xCAT/SSHInteract.pm index f8fb56be6..be26fb5e2 100644 --- a/xCAT-server/lib/perl/xCAT/SSHInteract.pm +++ b/xCAT-server/lib/perl/xCAT/SSHInteract.pm @@ -39,47 +39,48 @@ sub _startssh { } sub new { - my $class = shift; - my %args = @_; - my $pty = IO::Pty->new or die "Unable to perform ssh: $!"; - $args{"-fhopen"} = $pty; - $args{"-telnetmode"} = 0; - $args{"-telnetmode"} = 0; - $args{"-cmd_remove_mode"} = 1; - my $username = $args{"-username"}; - my $host = $args{"-host"}; - my $password = $args{"-password"}; - delete $args{"-host"}; - delete $args{"-username"}; - delete $args{"-password"}; - my $nokeycheck = $args{"-nokeycheck"}; - delete $args{"-nokeycheck"}; - my $self = $class->Net::Telnet::new(%args); - _startssh($self,$pty,$username,$host,"-nokeycheck"=>$nokeycheck); - my $promptex = $args{Prompt}; - $promptex =~ s!^/!!; - $promptex =~ s!/\z!!; + my $class = shift; + my %args = @_; + my $pty = IO::Pty->new or die "Unable to perform ssh: $!"; + $args{"-fhopen"} = $pty; + $args{"-telnetmode"} = 0; + $args{"-telnetmode"} = 0; + $args{"-cmd_remove_mode"} = 1; + my $username = $args{"-username"}; + my $host = $args{"-host"}; + my $password = $args{"-password"}; + delete $args{"-host"}; + delete $args{"-username"}; + delete $args{"-password"}; + my $nokeycheck = $args{"-nokeycheck"}; + delete $args{"-nokeycheck"}; + my $self = $class->Net::Telnet::new(%args); + _startssh($self,$pty,$username,$host,"-nokeycheck"=>$nokeycheck); + my $promptex = $args{Prompt}; + $promptex =~ s!^/!!; + $promptex =~ s!/\z!!; my ($prematch,$match) = $self->waitfor(Match => $args{Prompt},Match=>'/password:/i',Match=>'/REMOTE HOST IDENTIFICATION HAS CHANGED/') or die "Login Failed:", $self->lastline; + #print "prematch=$prematch, match=$match\n"; if ($match =~ /password:/i) { - #$self->waitfor("-match" => '/password:/i', -errmode => "return") or die "Unable to reach host ",$self->lastline; - $self->print($password); - my $nextline = $self->getline(); - chomp($nextline); - while ($nextline =~ /^\s*$/) { - $nextline = $self->get(); - chomp($nextline); - } - if ($nextline =~ /^password:/ or $nextline =~ /Permission denied, please try again/) { - die "Incorrect Password"; - } elsif ($nextline =~ /$promptex/) { - *$self->{_xcatsshinteract}->{_atprompt}=1; - } + #$self->waitfor("-match" => '/password:/i', -errmode => "return") or die "Unable to reach host ",$self->lastline; + $self->print($password); + my $nextline = $self->getline(); + chomp($nextline); + while ($nextline =~ /^\s*$/) { + $nextline = $self->get(); + chomp($nextline); + } + if ($nextline =~ /password:/i or $nextline =~ /Permission denied, please try again/ or $nextline =~ /disconnect from/) { + die "Incorrect Password"; + } elsif ($nextline =~ /$promptex/) { + *$self->{_xcatsshinteract}->{_atprompt}=1; + } } elsif ($match =~ /$promptex/) { *$self->{_xcatsshinteract}->{_atprompt}=1; } elsif ($match =~ /REMOTE HOST IDENTIFICATION HAS CHANGED/){ - die "Known_hosts issue"; - } - return bless($self,$class); + die "Known_hosts issue"; + } + return bless($self,$class); } sub atprompt { my $self=shift; diff --git a/xCAT-server/sbin/rshell_api b/xCAT-server/sbin/rshell_api new file mode 100755 index 000000000..5e7c0f9fe --- /dev/null +++ b/xCAT-server/sbin/rshell_api @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +# IBM(c) 2012 EPL license http://www.eclipse.org/legal/epl-v10.html + +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +use lib "$::XCATROOT/lib/perl"; +use Getopt::Long; +use xCAT::RShellAPI; + +Getopt::Long::Configure("require_order"); +Getopt::Long::Configure("no_pass_through"); + +my $username; +my $passwd; +my $help; + +if (!GetOptions( + 'l|loginname=s' => \$username, + 'p|password=s' => \$passwd, + 'h|help' => \$help, + ) || $help || scalar(@ARGV)<2 ) { + print "Usage: rshell_api [-l ] [-p ] \n"; + exit; +} + +my $node = $ARGV[0]; + +xCAT::RShellAPI::run_remote_shell_api($node, $username, $passwd, @ARGV[1 .. $#ARGV]); + +exit 0; diff --git a/xCAT-server/share/xcat/EthSwitch/config b/xCAT-server/share/xcat/EthSwitch/config new file mode 100644 index 000000000..4aee5250b --- /dev/null +++ b/xCAT-server/share/xcat/EthSwitch/config @@ -0,0 +1,5 @@ +[main] +ssh-setup-command= +[xdsh] +pre-command=NULL +post-command=NULL diff --git a/xCAT-server/xCAT-server.spec b/xCAT-server/xCAT-server.spec index d43a5ad29..3094267f1 100644 --- a/xCAT-server/xCAT-server.spec +++ b/xCAT-server/xCAT-server.spec @@ -80,6 +80,7 @@ mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/netboot/sles mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/netboot/rh mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/scripts/Mellanox mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/scripts/QLogic +mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/EthSwitch mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_plugin mkdir -p $RPM_BUILD_ROOT/%{prefix}/xdsh/Context mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_monitoring/samples @@ -122,6 +123,8 @@ cp share/xcat/cons/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/cons cp -r share/xcat/ib/scripts/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/scripts cp share/xcat/ib/netboot/sles/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/netboot/sles cp share/xcat/ib/netboot/rh/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/netboot/rh +cp share/xcat/EthSwitch/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/EthSwitch + chmod 755 $RPM_BUILD_ROOT/%{prefix}/share/xcat/cons/* chmod 755 $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/scripts/* chmod 755 $RPM_BUILD_ROOT/%{prefix}/share/xcat/ib/netboot/sles/*