3

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

  1. 建立 telnet 连接到交换机
  2. 通过 SNMP 陷阱重新启动交换机到连接的 APC
  3. 等待来自交换机的输入以识别它已准备好访问扩展引导 ROM
  4. 访问扩展 bootrom。
  5. 将目录更改为紧凑型闪存卡
  6. 在交换机上运行 list 命令并将其转储到数组
  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;
4

1 回答 1

2

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

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

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

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

于 2012-05-01T05:04:43.330 回答