在网络设备上执行远程命令的更好方法,比期望模块更好

发布于 2024-12-02 15:14:36 字数 371 浏览 5 评论 0 原文

我目前有一个使用 pexpect python 模块的实现,它与 Juniper、Cisco 路由器交互。它生成一个子应用程序并运行像 'show version' 这样的命令并记录输出。

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

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

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

谢谢

I currently have an implementation using the pexpect python module, which interacts with Juniper, Cisco routers. It spawns a child application and runs command like 'show version' and logs the output.

I am looking for a better way to carry out this process, since if something changes on the switch end (a space or a colon in the prompt after an OS upgrade), then the program will not work. I think Juniper has an API to carry out such operations, but I don't think Cisco has one. I also need to extend this to other switches like HP etc.

Is there a generalized way I can approach this?

I also don't mind writing different code for different devices if required, if a more standard approach than pexpect exists.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忘你却要生生世世 2024-12-09 15:14:36

使用某些版本的expect 是执行此操作的公认方法。大多数供应商已经有一个成熟的 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);
}

Using some version of expect is the accepted way of doing this. There's already a mature piece of OSS scripts for doing terminal interaction with most networking devices form most vendors. The same problem exists, but a lot more eyeballs are looking at it and updating things when vendors change prompts.

Check out RANCID.

Here's a quick example of a script I wrote based on RANCID to harvest ACL hit counts on ASAs:

#!/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);
}
心是晴朗的。 2024-12-09 15:14:36

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

请参阅:

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

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

一些 Cisco 硬件/软件组合支持它 - 例如,NETCONF 存在于 12.2(33)SXI 和 12.2 中SY/15.0SY 在 6500 sep720/sup2T 上进行训练。我相信所有版本的 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),这意味着您仍然需要摆弄硬编码的密码。

In an ideal world, NETCONF would be the solution. It's basically a (set of) wire protocol(s) and some XML encoding for get/set/exec requests against network devices.

See:

Modern versions of JunOS support this, in addition to their older, proprietary interface:

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

Some Cisco hardware/software combinations support it - for example, NETCONF is present in the 12.2(33)SXI and 12.2SY/15.0SY trains on the 6500 sup720/sup2T. I believe all versions of NX-OS (Cisco Nexus) support NETCONF.

I don't know about HP. I do know Extreme XOS supports NETCONF in later versions in addition to Extreme's own XML API.

However - NETCONF is problematic in a few ways:

  1. Although the protocol is standardised, the supported data models aren't. So, you end up with very different XML from the different devices; you'll still need device-specific code. But at least you won't have to screen-scrape and abuse expect, and you'll have much more reliable error detection

  2. Some devices - for example, Cisco IOS - are not really XML under the hood. The XML is generated using a set of rule-based parsers (screen scrapers) and, in my testing, these are often incomplete or buggy. For example, contrary to what Cisco claims, "show run | format" does not "generate XML natively". It turns the Cisco line-based config into XML, and it breaks on a number of config constructs we use (e.g. address-family sub-stanzas of BGP router configs). We ended up not using XML for data and sticking to line-based Cisco commands/config - you still have to parse this, but at least you benefit from the NETCONF command framing and error codes.

  3. Although you can run NETCONF over SSH, many devices still won't perform SSH key-based login (Cisco IOS) meaning you still have to fiddle with hard-coded passwords.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文