perl - 我认为在 perl 中的 Telnet 输入缓冲区问题

标签 perl stdin telnet

所以在过去的一个月里,我一直在编写一个脚本来在 HP procurve 交换机上进行主清除。我与 HP 内部人员交谈过,他们使用的系统与我完全不同,所以他们没有帮助。我相信我已经弄明白了。这是我的脚本应该做的:

  1. 建立到交换机的 telnet 连接
  2. 通过 SNMP 陷阱重新启动交换机到连接的 APC
  3. 等待来自交换机的输入以识别它已准备好访问扩展引导 rom
  4. 访问扩展的 bootrom。
  5. 将目录更改为闪存卡
  6. 在交换机上运行列表命令并将其转储到数组
  7. 对数组中的每一项运行 foreach 以识别什么是固件、文件和文件夹 A)忽略固件 B)将每个文件添加到主删除数组 C) 对文件夹中的文件运行类似的 foreach,并将它们添加到主删除数组,然后添加到文件夹(用于删除目的)
  8. 运行foreach删除主删除数组中的所有项目以清除开关
  9. 重启并设置交换机的基本信息。

更新

好吧,我无法让 $telnet->buffer_empty; 在 100% 的时间内正常工作,所以我决定调用第二个列表命令并将其转储到垃圾箱文件。下面是我的脚本,到目前为止它在我测试过的 10 个开关上工作。我的夜类将打破开关并测试此重置脚本。

对于任何感兴趣的人,这个脚本正在 HP Procurve 交换机上使用,根据我的研究,它适用于大多数,但不是全部。

#!/usr/bin/perl
$| = 1;


use Net::Telnet;
use Net::SNMP;
use strict;
use CGI;

#variabls for power, connections and systemname
my $power_host     = ('Power-APC');
my $power_port     = ('Power-APC-Port');
my $system_name    = ('system-name');
my $console_server = ('Console-Server');
my $console_mgmtA  = ('Console-ManagementA');
my $match;
my ($garbage, $trash);
my $master_value;
my $telnet;
my @array;
my @master_array;


checkForNull("Console-Server",$console_server,1);
checkForNull("Console-ManagementA",$console_mgmtA,1);
checkForNull("Power_Host",$power_host,1);
checkForNull("Power_Port",$power_port,1);
checkForNull("System_Name", $system_name,1);


#Starting reset script
print("Please wait while $system_name resets.\n");
print("Please do not interact with any consoles open to this device\n");
print("The reset will take approximitly 5 minutes\n");

#establishing Telnet connection
$telnet = new Net::Telnet (Timeout=>120, Errmode=>'return', Port => $console_mgmtA);

$telnet->open($console_server);
sleep(1);

#executing reboot via SNMP
print("Deleting configuration files.\n");

   my ($snmp, $error) = Net::SNMP->session(
      -hostname  => shift || "$power_host",
      -community => shift || 'private',
      -port      => shift || 161
   );
   if (!defined($snmp)) {
      printf("ERROR: %s.\n", $error);
      exit 1;
   }
   my $sysx = ".1.3.6.1.4.1.318.1.1.12.3.3.1.1.4.$power_port";
   my $result = $snmp->set_request(
      -varbindlist => [$sysx, INTEGER, '3']
   );
   $snmp->close;




$telnet->waitfor(match=> '/Profiles/');
$telnet->cmd(string => '0', prompt => '/=>/');
#shift to compact flash card
$telnet->cmd (string=> 'cd cfa0', prompt => '/=>/');
my $garbage_output = $telnet -> cmd (string => 'ls', prompt => '/=>/');
$telnet->buffer_empty;


#propigates primary array with file list
undef @array;
@array = $telnet->cmd(string => 'ls', prompt => '/=>/');


#determines what should be deleted
foreach my $item (@array) {
    #cleans up the files for use in the if statement
   chomp ($item);
   #determines if it's a folder, passes folder name to sub
   if ($item=~ /\//) {
       subfolders ($item);
       #adds folder AFTER files in dir to ensure deletion
       push(@master_array, "rmdir $item");
   }
   #finds and ignores the primary and secondary firmware

   elsif ($item =~ /btm.swi|secondary.swi/) {
   }
   else {
    #adds all files to the master deletion list
    push(@master_array,"rm $item");
   }



#deletes all files listed in the master array
foreach $master_value (@master_array){
$telnet -> print ("$master_value");
}


#reboot switch
$telnet->print('boot');
$telnet->put(chr(13));
sleep(120);


#looking for ready screen
$telnet->waitfor(match=> '/continue/');
sleep (1);
$telnet->put(chr(13));
sleep (1);
$telnet->put(chr(13));
$telnet->waitfor(match=> '/continue/');
$telnet->put(chr(13));
$telnet->print('config');
$telnet->put(chr(13));
$telnet->print("hostname $system_name\n");
$telnet->print('lldp run');
$telnet->put(chr(13));
$telnet->print('wr mem');
$telnet->put(chr(13));
$telnet->print('boot');
$telnet->put(chr(13));
$telnet->print('y');


print("$system_name has been reset to factory settings.\n");
}


#add all files in folders to master deletion list
sub subfolders {
 my @subfolder_contents;
 my $subfolder = $_[0];
 my $file;

 @subfolder_contents = $telnet ->cmd(string => "ls $subfolder", prompt => '/=>/');
 foreach $file (@subfolder_contents){
  chomp ($file);
    push(@master_array, "rm $subfolder$file");
 }
};


sub checkForNull {
    my $name = $_[0];
    my $param = $_[1];
    my $required = $_[2];

    if($param eq "") {
        if ($required == 1) {
            print("\nSorry, no '$name' specified for this device, cannot continue.\n");
            exit 1;
        }
    }
# else {
 #       print("\n$name: $param\n");
  #  }
}

exit;

最佳答案

有一个 $telnet->buffer_empty 可以满足您的要求,但我认为这不是您的问题(尽管尝试一下)。

您确定您的提示没有匹配得太快吗?换句话说,是否有一些命令输出恰好也包含'=>'?最好的调试方法是通过 $telnet->dump_log('/tmp/some_file'),它会为您提供进出连接的所有内容的十六进制转储(更重要的是,确切的Net::Telnet 的读取和写入顺序,这样您就可以判断它是否以及在何处过早匹配)。

如果您过早地使用“=>”提示进行匹配,只需尝试使正则表达式更严格一些。添加 '\z' 以检查字符串的结尾将是一个好的开始,但如果 '=>' 之后有空格(例如 '/=> ?\z/'),请小心。 (但是,当然,'\z' 并不是真正的“结尾”,而是 Net::Telnet 到目前为止收集的任何内容。因此,如果输出中间的一个不幸数据包恰好以 '=> ' 结尾,那么它也会打破更严格的正则表达式)

此外,您的一长串“打印”看起来很可疑,因为打印在返回之前不会等待提示。更好的做法是始终设置 Net::Telnet 对象的“提示”字段,然后使用 ->cmd,它会在返回前等待提示。

关于perl - 我认为在 perl 中的 Telnet 输入缓冲区问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10389195/

相关文章:

python 通过 telnet session 在行尾不断报告 "invalid syntax"

perl - Perl代码段上的问题

c - 使用freopen读取文件

python - 如何在Python 2.7中写入正在运行的程序的另一个终端?

delphi - 如何通过Delphi 7窥视STDIN?

c - 通过半双工通信链路的 Telnet - 协商参数

javascript - 重试时客户端连接未正确关闭

perl - 什么时候在某种外部使用飞船运算符(operator)?

python - Perl 代码序列化和反序列化变量,如 python pickle

regex - 是否可以使用正则表达式来驼峰化/下划线字符串?