0

我目前有一个使用pexpect python 模块的实现,它与 Juniper、Cisco 路由器交互。它生成一个子应用程序并运行“显示版本”之类的命令并记录输出。

我正在寻找一种更好的方法来执行这个过程,因为如果交换机端发生了一些变化(操作系统升级后提示中的空格或冒号),那么程序将无法运行。我认为瞻博网络有执行此类操作的 API,但我认为思科没有。我还需要将此扩展到其他交换机,例如 HP 等。

有没有一种通用的方法可以解决这个问题?

如果需要,如果存在比 pexpect 更标准的方法,我也不介意为不同的设备编写不同的代码。

谢谢

4

2 回答 2

2

使用某些版本的期望是这样做的公认方式。已经有一个成熟的 OSS 脚本用于与大多数供应商的大多数网络设备进行终端交互。存在同样的问题,但是当供应商更改提示时,更多的眼球正在关注它并更新内容。

查看RANCID

这是我基于 RANCID 编写的脚本的一个快速示例,用于收集 ASA 上的 ACL 命中计数:

#!/usr/bin/perl

use strict;
use Getopt::Std;

my $usage = "Usage: gethitcnt.pl -c configfile -o outputdir\n\n";
my %opts;

getopts('hc:o:', \%opts);

my $login = sprintf "~%s\/bin\/clogin.in", $ENV{'HOME'};
my $loginrc = sprintf "~%s\/.cloginrc", $ENV{'HOME'};
my $cmdfile = sprintf "~%s\/cmd", $ENV('HOME');
my $date = getdate;
my ($config,$outdir);

unless (-e $login) {
 die "Cannot find $login\n\n";
}

unless (-e $loginrc) {
 die "Cannot find $loginrc\n\n";
}

if ($opts{h} or !$opts{c}) {
 die $usage;
}

if ($opts{o}) {
 $outdir = $opts{o};
} else {
 $outdir = $ENV{'PWD'};
}

if (-e $opts{c}) {
 $config = getconfig($opts{c});
} else {
 die "Cannot open config file $opts{c}\n\n";
}

foreach my $firewall (keys %$config) {
 foreach my $acl (@{$config->{$firewall}}) {
  open (CMD,>$cmdfile);
  print CMD "show access-list $acl\n";
  print CMD "clear access-list $acl counters\n";
  close (CMD);
  my $command = ($login,"-x",$cmdfile,$firewall)
  open (TMP,"$command |");
  my $outfile = sprintf "%s\/%s-%s-%s.txt", $outdir, $firewall, $acl, $date;
  open (OUTFILE,>$outfile);
  foreach my $line (<TMP>) {
   if ($line =~ /\s*(access-list.*\(hitcnt=\d+\))/) {
    print OUTFILE "$1\n";
   }
  }
  system ("rm",$cmdfile);
 }
}

sub getconfig {
 my $configfile = shift;
 open(CONFIG,$configfile);
 my $out;
 foreach (<CONFIG>) {
  chomp;
  my @$elements = split(/,/);
  my $host = shift(@$elements);
  $out->{$host} = $elements;
 }
 close(CONFIG);
 return($out);
}

sub getdate {
 my @time = localtime;
 my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
 my $month = $abbr[$time[4]];
 my $out = sprintf "%s-%d", $month, $time[3];
 return($out);
}
于 2011-09-30T14:15:05.663 回答
2

在理想情况下,NETCONF 将是解决方案。它基本上是一组(一组)有线协议和一些 XML 编码,用于针对网络设备的 get/set/exec 请求。

看:

除了较旧的专有接口外,现代版本的 JunOS 还支持此功能:

http://www.juniper.net/support/products/junoscript/

一些 Cisco 硬件/软件组合支持它 - 例如,NETCONF 存在于 6500 sup720/sup2T 上的 12.2(33)SXI 和 12.2SY/15.0SY 序列中。我相信所有版本的 NX-OS (Cisco Nexus) 都支持 NETCONF。

我不知道惠普。我知道 Extreme XOS 除了 Extreme 自己的 XML API 之外,在以后的版本中还支持 NETCONF。

但是 - NETCONF 在以下几个方面存在问题:

  1. 尽管协议是标准化的,但支持的数据模型却不是。因此,您最终会得到来自不同设备的非常不同的 XML;您仍然需要特定于设备的代码。但至少您不必进行屏幕抓取和滥用预期,并且您将拥有更可靠的错误检测

  2. 某些设备(例如 Cisco IOS)在底层并不是真正的 XML。XML 是使用一组基于规则的解析器(屏幕抓取器)生成的,在我的测试中,这些通常不完整或有问题。例如,与 Cisco 声称的相反,“show run | format”不会“在本地生成 XML”。它将 Cisco 基于线路的配置转换为 XML,它打破了我们使用的许多配置结构(例如 BGP 路由器配置的地址族子节)。我们最终没有将 XML 用于数据并坚持基于行的 Cisco 命令/配置 - 您仍然需要解析它,但至少您可以从 NETCONF 命令框架和错误代码中受益。

  3. 尽管您可以通过 SSH 运行 NETCONF,但许多设备仍然不会执行基于 SSH 密钥的登录(Cisco IOS),这意味着您仍然必须摆弄硬编码密码。

于 2011-10-19T17:24:19.070 回答