more on xdsh to ethernet switches

git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@14356 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
linggao 2012-11-16 17:21:35 +00:00
parent 8d9f8e6608
commit d3a3b4d526
8 changed files with 239 additions and 87 deletions

View File

@ -1228,6 +1228,7 @@ sub fork_fanout_dsh
# execute and remove the /tmp file build which is a copy of the
# input -E file
#print "Command=@dsh_command\n";
@process_info = xCAT::DSHCore->fork_output($user_target, @dsh_command);
if ($process_info[0] == -2)
@ -1876,10 +1877,10 @@ sub stream_error
xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
}
# my $rsp = {};
# $rsp->{error}->[0] =
# "$user_target remote command had return code $$target_properties{'target-rc'}";
# xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
#my $rsp = {};
#$rsp->{error}->[0] =
# "$user_target remote command had return code $$target_properties{'target-rc'}";
#xCAT::MsgUtils->message("E", $rsp, $::CALLBACK);
my $rsp = {};
$rsp->{error}->[0] =
@ -2248,40 +2249,42 @@ sub config_dsh
if ($$options{'devicetype'})
{
$ENV{'DEVICETYPE'} = $$options{'devicetype'};
my $devicepath = $$options{'devicetype'};
$devicepath =~ s/::/\//g;
my $devicename = $$options{'devicetype'};
$devicename =~ s/::/\//g;
my $rsp = {};
$rsp->{data}->[0] = "Processing $devicepath device type";
$rsp->{data}->[0] = "Processing $devicename device type";
$dsh_trace && xCAT::MsgUtils->message("I", $rsp, $::CALLBACK);
# process the config file
$devicepath = "/var/opt/xcat/" . $devicepath . "/config";
# Get configuration from $::XCATDEVCFGDIR
# used for QLogic and Mellanox
if (-e $devicepath)
{
my $deviceconf = get_config($devicepath);
# Get all dsh section configuration
foreach my $entry (keys %{$$deviceconf{'xdsh'}})
{
# process the config file. check /var/opt/xcat/... first, if the config
# file is not found, goto /opt/xcat/share/devicetype
my $devicepath = "/var/opt/xcat/" . $devicename . "/config";
if (! -e $devicepath) {
$devicepath="$::XCATROOT/share/xcat/devicetype/" . $devicename . "/config";
}
# Get configuration from $::XCATDEVCFGDIR
# used for QLogic and Mellanox
if (-e $devicepath)
{
my $deviceconf = get_config($devicepath);
# Get all dsh section configuration
foreach my $entry (keys %{$$deviceconf{'xdsh'}})
{
my $value = $$deviceconf{'xdsh'}{$entry};
if ($value)
{
$$options{$entry} = $value;
}
}
}
else
{
}
}
else
{
my $rsp = {};
$rsp->{error}->[0] = "EMsgMISSING_DEV_CFG";
xCAT::MsgUtils->message('E', $rsp, $::CALLBACK);
}
}
}
!$$options{'node-rsh'}
@ -4080,10 +4083,15 @@ sub parse_and_run_dsh
if (defined $options{'devicetype'})
{
$ENV{'DEVICETYPE'} = $options{'devicetype'};
my $devicepath = $options{'devicetype'};
$devicepath =~ s/::/\//g;
$devicepath = "/var/opt/xcat/" . $devicepath . "/config";
if (-e $devicepath)
my $devicename = $options{'devicetype'};
$devicename =~ s/::/\//g;
my $devicepath = "/var/opt/xcat/" . $devicename . "/config";
# go to backup directory if the config file
# cannot be found under /var/opt/xcat/...
if (! -e $devicepath) {
$devicepath="$::XCATROOT/share/xcat/devicetype/" . $devicename . "/config";
}
if (-e $devicepath)
{
my $deviceconf = get_config($devicepath);

View File

@ -23,7 +23,7 @@ use xCAT::MsgUtils;
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 ) = @_;
@ -51,6 +51,23 @@ sub remote_shell_command {
return @command;
}
##################################################################
=head3
run_remote_shell_api
This routine tried ssh then telnet to logon to a node and
run a sequence of commands.
Arguments:
$node - node name
$user - user login name
$passed - user login password
$cmds - a list of commands seperated by semicolon.
Returns:
[error code, output]
error code: 0 sucess
non-zero: failed. the output contains the error message.
=cut
#########################################################################
sub run_remote_shell_api {
require xCAT::SSHInteract;
my $node=shift;
@ -58,9 +75,13 @@ sub run_remote_shell_api {
my $passwd=shift;
my $args = join(" ", @_);
my $t;
my $prompt='.*[\>\#\$]$';
my $more_prompt='(.*key to continue.*|--More--\s*$)';
my $verbose=0;
my $output;
if(0) {
print "start SSH session...\n";
eval {
$output="start SSH session...\n";
$t = new xCAT::SSHInteract(
-username=>$user,
-password=>$passwd,
@ -69,108 +90,206 @@ sub run_remote_shell_api {
-output_record_separator=>"\r",
Timeout=>5,
Errmode=>'return',
Prompt=>'/.*[\>\#]$/',
Prompt=>"/$prompt/",
);
};
my $errmsg=$@;
$errmsg =~ s/ at (.*) line (\d)+//g;
print "$errmsg\n";
$output.="$errmsg\n";
my $rc=1;
if (not $t) {#ssh failed.. fallback to a telnet attempt
print "start Telnet session...\n";
$output.="start Telnet session...\n";
require Net::Telnet;
$t = new Net::Telnet(
Timeout=>5,
Errmode=>'return',
Prompt=>'/.*[\>\#]$/',
Prompt=>"/$prompt/",
);
$rc = $t->open($node);
if ($rc) {
my $pw_tried=0;
my $login_done=0;
my ($prematch, $match)= $t->waitfor(Match => '/login[: ]*$/i',
Match => '/username[: ]*$/i',
Match => '/password[: ]*$/i',
Match => "/$prompt/",
Errmode => "return");
if (($match =~ /username[: ]*$/i) || ($match =~ /login[: ]*$/i )) {
if ($verbose) {
print "1. prematch=$prematch\n match=$match\n";
}
if ($match =~ /$prompt/) {
$login_done=1;
} elsif (($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"];
$output.="login disconnected\n";
return [1, $output];
}
} else {
print "Username is required.\n";
return [1, "Username is required."];
$output.="Username is required.\n";
return [1, $output];
}
} 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"];
$output.="Login disconnected\n";
return [1, $output];
}
} else {
print "password is required.\n";
return [1, "Passwordis required."];
$output.="Password is required.\n";
return [1, $output];
}
}
($prematch, $match)= $t->waitfor(Match => '/login[: ]*$/i',
if (!$login_done) {
($prematch, $match)= $t->waitfor(Match => '/login[: ]*$/i',
Match => '/username[: ]*$/i',
Match => '/password[: ]*$/i',
Match => "/$prompt/",
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 ($verbose) {
print "2. prematch=$prematch\n match=$match\n";
}
if ($passwd) {
if (! $t->put(String => "$passwd\n",
Errmode => "return")) {
print "login disconnected\n";
return [1, "login disconnected"];
if ($match =~ /$prompt/) {
$login_done=1;
} elsif (($match =~ /username[: ]*$/i) || ($match =~ /login[: ]*$/i )) {
$output.="Incorrect username.\n";
return [1, $output];
} elsif ($match =~ /password[: ]*$/i) {
if ($pw_tried) {
$output.="Incorrect password.\n";
return [1, $output];
}
if ($passwd) {
if (! $t->put(String => "$passwd\n",
Errmode => "return")) {
$output.="Login disconnected\n";
return [1, $output];
}
} else {
$output.="Password is required.\n";
return [1, $output];
}
}
if (!login_done) {
#Wait for command prompt
($prematch, $match) = $t->waitfor(Match => '/login[: ]*$/i',
Match => '/username[: ]*$/i',
Match => '/password[: ]*$/i',
Match => "/$prompt/",
Errmode => "return");
if ($verbose) {
print "3. prematch=$prematch\n match=$match\n";
}
if ($match =~ /$prompt/) {
$login_done=1;
} elsif ($match =~ /login[: ]*$/i or $match =~ /username[: ]*$/i or $match =~ /password[: ]*$/i) {
$output.="Login failed: bad login name or password\n";
return [1, $output];
} else {
if ($t->errmsg) {
$output.= $t->errmsg . "\n";
return [1, $output];
}
}
} 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]);
$output.=$t->errmsg . "\n";
return [1, $output];
}
$rc = 0;
my $output;
my $try_more=0;
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";
if ($verbose) {
print "command:$cmd\n";
}
while (1) {
if ($try_more) {
#This is for second and consequent pages.
#if the user disables the paging, then this code will never run.
#To disable paging (which is recommended),
#they need to add a command before any other commands
#For Cisco switch: terminal length 0
#For BNT switch: terminal-length 0
#For example:
# xdsh <swname> --type EthSwitch "terminal length 0;show vlan"
if (! $t->put(String => " ",
Errmode => "return")) {
$output.="Command $cmd failed: " . $t->errmsg() . "\n";
return [1, $output];
}
if ($verbose) {
my $lastline=$t->lastline();
print "---lastline=$lastline\n";
}
($prematch, $match) = $t->waitfor(Match => "/$more_prompt/",
Match => "/$prompt/",
Errmode => "return",
Timeout=>3);
} else {
# for the first page which may contian all
if (! $t->put(String => "$cmd\n",
Errmode => "return")) {
$output.="Command $cmd failed." . $t->errmsg() . "\n";
return [1, $output];
}
if ($verbose) {
my $lastline=$t->lastline();
print "lastline=$lastline\n";
}
($prematch, $match) = $t->waitfor(Match => "/$more_prompt/",
Match => "/$prompt/",
Match => '/password:\s*$/i',
Errmode => "return",
Timeout=>3);
}
if ($verbose) {
print "-----prematch=$prematch\nmatch=$match\n";
}
my $error=$t->errmsg();
if ($error) {
$output.="Command $cmd failed: $error\n";
return [1, $output];
}
# remove the first line
if ($try_more) {
my @data=split("\n", $prematch);
shift @data;
#shift @data;
#shift @data;
$prematch=join("\n", @data);
#add a newline at the end if not there
my $lastchar=substr($prematch, -1, 1);
if ($lastchar ne "\n") {
$prematch .= "\n";
}
}
$output .= $prematch;
if ($match =~ /$more_prompt/i) {
$try_more=1;
} else {
last;
}
}
}
$t->close();
return [0, $output];
@ -178,4 +297,6 @@ sub run_remote_shell_api {
1;

View File

@ -28,6 +28,13 @@ if (!GetOptions(
my $node = $ARGV[0];
xCAT::RShellAPI::run_remote_shell_api($node, $username, $passwd, @ARGV[1 .. $#ARGV]);
my $output =xCAT::RShellAPI::run_remote_shell_api($node, $username, $passwd, @ARGV[1 .. $#ARGV]);
my $rc=0;
my $data;
if ($output && (@$output > 1)) {
$rc=$output->[0];
$data=$output->[1];
}
exit 0;
print "$data";
exit $rc;

View File

@ -1,5 +1,5 @@
[main]
ssh-setup-command=
[xdsh]
pre-command=NULL
pre-command=terminal-length 0;
post-command=NULL

View File

@ -0,0 +1,5 @@
[main]
ssh-setup-command=
[xdsh]
pre-command=terminal length 0;
post-command=NULL

View File

@ -0,0 +1,11 @@
#This is a configuration file for running xdsh again ethernet switches.
#If the switch type is not defined, you can create a subdirctory for that
#type of switch. For example, for cisco swith, create a subdirectory
# called "Cisco" under EthSwitch. copy this config file there. And
#put the command that disables the paging in pre-command
#pre-command=terminal lenth 0;
[main]
ssh-setup-command=
[xdsh]
pre-command=NULL
post-command=NULL