Expect 在网络管理中发挥着重要作用

原贴:http://www.ibm.com/developerworks/cn/aix/library/au-expect/index.html

Expect 在网络管理中发挥着重要作用

实现所有命令行操作自动化的脚本编写工具

developerWorks
文档选项
将此页作为电子邮件发送

将此页作为电子邮件发送


级别: 中级

Cameron Laird (claird@phaseit.net), 副总裁, Phaseit, Inc.

2007 年 9 月 13 日

Expect 是进行高效的系统和网络管理工作不可或缺的一种工具,不过很多人对它存在着一定的误解。在本文中,将通过一些常见的用例来介绍 Expect 所提供的优点。

如果您从事系统和网络管理工作,那么您将需要 Expect。

更准确地说,您为什么不使用 Expect 呢?对于一些常见的任务,它可以节省大量的时间。尽管您现在可能已经在使用 Expect,但是您可能并不是很清楚下面所描述的一些功能。

Expect 可以实现命令行交互的自动化

要从 Expect 中获益,您并不需要掌握有关它的所有内容;让我们从一个具体的示例开始,研究 Expect 如何在 AIX® 或者其他操作系统中简化您的工作:

假设您在一些 UNIX® 或者类 UNIX 主机上具有登录帐号,并且您需要更改这些帐号的密码,但是并没有使用网络信息服务(Network Information Service,NIS)、轻量级目录访问协议(Lightweight Directory Access Protocol,LDAP)或者能够在每台计算机上识别出您是相同的登录用户的一些其他机制对这些帐号进行同步。在大多数情况下,登录到一台特定的主机,并运行合适的 passwd 命令并不会花费很长的时间,可能只需要一分钟而已。但是因为无法将您的密码编写在脚本中,所以您必须 进行“手动”登录,是这样吗?

其实并不是这样的。事实上,标准 Expect 分发版(完整的分发版)中包括一种命令行工具(以及描述其使用的手册页面!),该工具恰好可以负责完成这项烦琐的工作。passmass(请参见参考资料)是使用 Expect 编写的一个简短的脚本,它可以使得在二十台计算机上进行密码更改的工作就像在一台计算机上进行密码更改那样简单。不需要反复地输入相同的密码,您可以只启动一次 passmass,并允许您的桌面计算机负责更新每个单独的主机。您节省了大量时间并可以稍事休息,同时对于已经输入过的内容,极大地降低了错误输入的可能性。

Expect 的限制

这个 passmass 应用程序是一个非常优秀的模型,它说明了 Expect 的许多常规特性:

  • 这个工具值得我们去使用和研究:这个实用工具已经编写完成,并且可以免费地下载,它易于安装和使用,可以节省大量的时间和精力。
  • 从某种意义而言,它的作用是“无关紧要的”。如果任何操作都“按照既定的规则”进行(如果您使用了 NIS 或者一些其他的域身份验证或单点登录系统),或者可以通过编写脚本进行登录,那么就不需要使用 passmass 了。但实际情况并不总是这样的,而 Expect 非常适合于处理各种各样现有的问题。也许 Expect 能够帮助您节省更多的时间,以便您能够使您的配置更加合理化,这样一来您就不再需要 Expect 了。在此期间,您可以充分地利用它。
  • 对于分布式的环境,passmass 仅使用 telnetrlogin 或者 slogin 进行登录。我希望当前所有的 developerWorks 读者都不再使用这些协议,而是使用 sshpassmasss没有 对 ssh 提供全面的支持。
  • 另一方面,几乎所有与 Expect 有关的内容都编写得非常清楚,并且可以免费获得。只需要使用三行简单的内容(至多)就可以对 passmass 进行增强,以支持 ssh 和其他选项。

 

您可能已经了解了足够多的内容,完全可以开始编写或者修改您自己的 Expect 工具。当然,实际上 passmass 分发版中包含了以 ssh 方式进行登录的代码,但是省略了相应的命令行解析以到达这部分代码。本文介绍了一种方法,您可以修改分发版源代码,对 sshtelnet 以及其他协议进行同样的处理:
清单 1. 经过修改的、接受 -ssh 参数的 passmass 片段

                    

            ...
         } "-rlogin" {
            set login "rlogin"
            continue
        } "-slogin" {
            set login "slogin"
            continue
        } "-ssh" {
            set login "ssh"
            continue
        } "-telnet" {
            set login "telnet"
            continue
           ...
      

在我自己的代码中,我实际上从这个“样本”中提出了更多的内容。现在,passmass 第 100 行附近的这一连串测试,非常好地说明了 Expect 的可读性。这里并没有涉及到很深的编程技术,不需要面向对象、单体应用程序、协同例程,或者其他巧妙的技术。您只是请求计算机负责您通常进行的输入工作。恰好,这个简单的操作步骤可以节省大量时间和精力。

什么是 Expect?

Expect 究竟 什么,您应该如何使用它呢?

“Expect”涉及到一些独特的概念,许多经常使用 Expect 的用户对这些概念并不是十分清楚:

  • Expect 是一种特定的、高级的和通用的编程语言,其语法与 Tcl 相同,并增加了 Tcl 中所没有的一些特殊用途的命令。
  • Expect 是一种可执行程序,从它正确地处理用 Expect 语言编写的输入的角度来看,它实现了这种语言。
  • expect 命令是其中的一个命令,Expect 以此对 Tcl 进行了扩展。
  • Expect 是一个 Tcl 包。一般说来,这意味着任何 Tcl 应用程序都可以在运行时加载 Expect 功能。
  • Expect 是一个基于 C 源代码的库,而这些 C 源代码则深入到 Expect 可加载的包和 Expect 可执行程序。
  • Expect 是某种工具的抽象概念,该工具:
    • 实现终端交互的自动化,甚至在涉及到密码或者其他特殊项目的情况下
    • 实现了一种“对话”模型,通过它对消息和响应的简单规律进行编码
    在这种抽象中,不存在特定于 Tcl 的内容,实际上,现在有几种使用其他语言(如 Python、Perl,等等)的 Expect 模型的独立实现。尽管本文中的示例都采用基于 Tcl 的 Expect 进行表述,但是可以使用其他语言来编写所有这些示例。没有理由因为您熟悉或者不熟悉 Tcl,而限制您对 Expect 的使用。
请注意,考虑到一些技术细节超出了本文的关注重点,在前面的描述中,我稍微有些歪曲事实;例如,常规的 Expect 可执行程序不仅扩展了 Tcl 命令集,它还可以识别启动时的一些额外的命令行参数。尽管这些内容并不是专门针对主要的主题:一个简短的 Expect 程序所能够为系统管理员完成的工作,超出了大多数人的预期。

 

在了解了这个背景信息之后,“passmass 是一个 Expect 应用程序”表示:

  • passmass 是一个以 Expect 语言编写的文本文件。
  • 如果您在正确地安装了 Expect 和 passmass 的主机上执行 expect passmass ...,那么您将得到正确的 passmass 功能。
请注意,具体的执行方法可能有一些变种:可以在一个 Tcl 解释器中以交互的方式加载 Expect、运行 passmass、创建 passmass 作为一个独立的可执行程序,等等。同样地,这些替代方法超出了本文所关注的重点。

 

网络管理示例

让我们考虑一项更大的挑战,网络操作中心的日常操作中一项更典型的操作:检索一组托管的 Cisco 交换机的当前配置信息。尽管有些站点使用 SNMP 或者 HTTP 来进行这些操作,但是更常见的是使用控制台或者频内 telnet 会话来获取该信息。许多管理员认为,完成这项工作唯一可行的方法是输入与清单 2 中所示类似的命令。
清单 2. 典型的“手工”配置自检

                    

        telnet $MY_ROUTER
        [User: admin]
        [password: ...]
        CCNA01# show running-config
        [... Current configuration:
         ... version 12.0 ...
         FIFTY LINES MORE OF CONFIGURATION DETAIL
         ...
         End]

    

其实并不是这样的;实际上,通过在 cron、回复邮件(mailback)服务器,或者类似的作业控制机制(请参见清单 3)中进行调用,这项工作完全可以实现自动化。
清单 3. 配置自检的自动化

                    
      #!/usr/bin/expect

      # initialize host, password, ...

      package require Expect
      set prompt {[00m# }
      spawn telnet $host
      expect {User: }
      send admin/r
      expect password:
      send $password/r
      expect -exact $prompt
      send "show running-config/r"
      expect -exact $prompt
      send exit/r
  

这个脚本可以自动地检索路由器的配置信息,即在正确地编写了脚本之后,对其进行监视时不再需要输入密码或者进行干预。

一些常见的混淆

这个示例是典型的 Expect 使用情况,其中有几点值得注意。首先,不存在任何适用于各种情况的解决方案。许多管理员在获得 Expect 时都认为它是一个单独使用的工具,以解决他们当前所碰到的问题。那不是 Expect。Expect 与电子铁钉寻找器 (electronic stud finder) 不同,后者可以不依靠任何其他工具、独立地查找铁钉。Expect 更像是一个手钻:您必须将其与合适的钻头,或者转换接头、孔锯,或者其他附件进行组合,才能真正实现它的用途。

同样地,Expect 至少需要进行一些自定义工作。当然,我通常使用 Expect 来解决一些其他工具所无法轻松解决的问题。running-config 的案例说明了,只需要几行内容,Expect 就可以自动地获得大量的信息。即使是这个简单的示例,也呈现出 Expect 所带来的一些问题。例如,这种特定的自动化,需要将管理密码以明文的形式嵌入到 Expect 脚本中;您需要判断,它是否适合于您的具体环境。

这个案例至少在一些更多的方面是非常典型的。$prompt 让我感到有些奇怪。屏幕上所显示的是 CCNA01# ;对于许多设备来说,这是非常典型的,这个提示符实际上嵌入了一些不可见的控制字符。幸运的是,Expect 提供了各种有价值的调试开关,以报告其交互过程;这正是我确定 CCNA01 所生成的各种字符的方法。

另外,如前所述,清单 3 返回了整个会话,包括我所需要的配置报告,还加上登录和退出作为其开始和结束。隐含在一般请求中的另一个有关 Expect 的常见误解是“检索一个命令的值”。Expect 并没有提供这些语义。当您坐在键盘前并输入一个命令时,您将它的操作认为是在下一个提示符之前所看到的相关显示。对于网络互连协议(如 telnet),在结果和提示符之间实际上并没有什么区别;您可以作为一个观察者对这些内容的含义进行分析。

与这种网络通信模型完全一致,Expect 并不直接区分结果和提示符。所有的 Expect 都称为对话,即它通过 send 发送的字符序列,以及它所期望(expect)的内容。因此在实际中,我使用一个正则表达式解析来为我提供所需要的细节信息。Expect 的扩展正则表达式功能非常强大,并且很容易通过代码确定格式。现在,让我们重点关注通常无法通过脚本实现自动化的广泛主题。

并发

请记住,Expect 是一种功能强大的、通用的语言。实际的 Expect 应用程序通常用于解析命令行参数、将结果显示在分栏的表格中、从数据库中检索历史数据、显示图形用户界面 (GUI),以及更多的用途。所有这些都是常规的计算工作,本文中的示例并没有展示这些方面的内容。文本的重点是正确地理解 Expect 独特的价值。

使用与清单 3 中所示类似的解决方案,网络管理员通常会考虑下一步的“水平方向的”增强:从大量类似的计算机检索这类报告。Expect 提供了循环构造 foreachwhile 等等,从而使得这样的工作变得更加简单。

它也可能很快地变得无法接受。假设您负责上百台 LAN 主机,这是一个比较常见的情况。您使用一个 Expect 脚本自动地依次登录到这些计算机,并检索重要的数据。现在,您对该脚本稍微进行一下抽象,以便对整个集合进行遍历。

问题是,运行所得到的脚本可能会花费很长的时间。它登录到一台主机,请求结果,接收结果,注销,然后转向下一台主机,请求一个新的结果,等等。这个过程中的延迟使得人们希望能够使用某种方法一次性地请求所有的结果,并按照结果到达的顺序对其进行收集,导致这些结果不同顺序的原因包括网络滞后、不同的负载,以及其他延迟。

有一种方法可以实现这种操作。实际上,Expect 提供了一些非常好的功能来同时管理多个对话。本文提供了一个程序的示例,该程序多次进行登录,在每个登录上执行一些长时间运行的命令,然后根据结果到达的顺序进行接收;对这个案例进行了整理,以便这些结果返回的顺序与其启动顺序相反(请参见清单 4)。
清单 4. 并发检索来自多个登录的报告

                    
       #!/home/claird/local/ActiveTcl/bin/tclsh 
       
       package require Expect
       
       log_user 0
       
       # Initialize user, passphrase, ... here.
       
           # Sequentially login and issue time-consuming commands to all
           # hosts.
       for {set i 0; set delay 8} {$delay > 0} {incr i; incr delay -1} {
           spawn ssh $user@$host
           set sid($i) $spawn_id
           expect rsa':
           send $passphrase
           expect "Last login"
           expect -ex $prompt
           set active($sid($i)) $i
           send -i $sid($i) "echo `date`; sleep $delay; echo `date`; echo /
           '$delay done on $i.'/r"
       }
       
       while {[llength [array names active]]} {
           expect -i [array names active] -ex $prompt {
                puts "RECEIVED:  $::expect_out(buffer)"
                send -i $expect_out(spawn_id) exit/r
                expect -i $expect_out(spawn_id) eof
                unset active($expect_out(spawn_id))
           }
       }
  

当您运行这个脚本时,将看到与清单 5 所示类似的结果。
清单 5. 运行清单 4 所得到的结果
                    
       RECEIVED:  echo `date`; sleep 1; echo `date`; echo '1 done on 7.'
       Mon Apr 23 22:15:15 UTC 2007
       Mon Apr 23 22:15:16 UTC 2007
       1 done on 7.
       RECEIVED:  echo `date`; sleep 2; echo `date`; echo '2 done on 6.'
       Mon Apr 23 22:15:15 UTC 2007
       Mon Apr 23 22:15:17 UTC 2007
       2 done on 6.
       RECEIVED:  echo `date`; sleep 3; echo `date`; echo '3 done on 5.'
       Mon Apr 23 22:15:15 UTC 2007
       Mon Apr 23 22:15:18 UTC 2007
       3 done on 5.
          ...
       RECEIVED:  echo `date`; sleep 8; echo `date`; echo '8 done on 0.'
       Mon Apr 23 22:15:14 UTC 2007
       Mon Apr 23 22:15:22 UTC 2007
       8 done on 0.
     

在编程的层次上,请注意,所有这些登录都是通过基于密码的 ssh 登录到相同的主机,并使用相同的用户和密码凭据。在一个更实际的示例中,可以通过更多行的代码来管理各个不同的主机,对每个主机使用不同的帐号和登录协议。尽管对于那些对网络管理员非常 价值的命令,sleep 是一个很好的模型;但是没有理由先睡眠数秒钟,然后再返回。

即使这个示例,也无法尽述 Expect 的所有功能。Expect 还提供了使用一个内置的套接字编程接口,直接管理 TCP/IP 对话的功能,并且它可以实现半自动化,在两种不同的模式之间来回切换,用户在其中一种模式中输入部分对话,而 Expect 在另一种模式中实现所有操作的自动化。

我们将在以后的文章中介绍这些主题。本文的目标是,展示 Expect 中包含了大多数管理员并不知道的许多内容,具体来说是了解了该工具后,马上就能够解决网络管理工作中各种常见的问题。在脚本中使用密码和密码条目,以及并发地控制多个连接,这些功能都是非常强大的。

总结

Expect 可以完成所有看起来无法实现自动化的工作:在脚本中使用密码条目、登录到远程用户的会话和返回对他或者她的控制,以及更多的工作。尽管它已经得到了广泛使用,但是 Expect 却常常被人们所误解。正确地理解有关 Expect 的一些基本知识(如何调用它、它的对话模型、它的编程辅助,等等),以便在系统和网络管理工作中更充分地发挥它的作用。

共享本文……

digg 请 Digg 这个故事
del.icio.u 发布到 del.icio.u
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值