所以在过去的一个月里,我一直在编写一个脚本来在 HP procurve 交换机上进行主清除。我与 HP 内部人员交谈过,他们使用的系统与我完全不同,所以他们没有帮助。我相信我已经弄明白了。这是我的脚本应该做的:
- 建立到交换机的 telnet 连接
- 通过 SNMP 陷阱重新启动交换机到连接的 APC
- 等待来自交换机的输入以识别它已准备好访问扩展引导 rom
- 访问扩展的 bootrom。
- 将目录更改为闪存卡
- 在交换机上运行列表命令并将其转储到数组
- 对数组中的每一项运行 foreach 以识别什么是固件、文件和文件夹 A)忽略固件 B)将每个文件添加到主删除数组 C) 对文件夹中的文件运行类似的 foreach,并将它们添加到主删除数组,然后添加到文件夹(用于删除目的)
- 运行foreach删除主删除数组中的所有项目以清除开关
- 重启并设置交换机的基本信息。
更新
好吧,我无法让 $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/