随笔-150  评论-223  文章-30  trackbacks-0
脚本概述
   当需要在很多(比如几十至几百)台机器上编译同一程序时,如果一个个地手工拷贝源码、再编译,那么效率就很低,为了能大量节省手工、并行地编译,因此写了一个脚本,该脚本基于自动化脚本语言expect(expect基于tcl)实现,基本原理是针对每个远程主机,创建一个子进程,在该子进程内先调用scp拷贝源码到远程主机,再用ssh登录到远程主机、发送cd、configure和make命令,交互期间的命令输出多用正则分析,最终的编译输出保存到当前目录output子目录下。其命令行参数说明如下:
    第1参数为远程主机配置文件:一个多行文本文件,每行格式为IP 用户名 密码,空格符分隔,支持#注释。
    第2参数为本地主机源码目录:要求该目录存在Makefile和configure文件。
    第3参数为远程主机目标目录:用于存放源码的位置。

脚本实现
   拷贝源码
 1proc copy_file {host user srcdir dstdir passwd {to 10} } {
 2    if [catch "spawn scp -rq $srcdir $user@$host:$dstdir" msg] {
 3        send_error "failed to spawn scp: $msg\n"
 4        exit 1
 5    }
 6    
 7    set timeout $to
 8    expect_after eof { 
 9        send_error "$host scp died unexpectedly\n"
10        exit 1
11    }
12    expect {
13        "(yes/no)?" { send "yes\r"; exp_continue }
14        -re "(?:P|p)assword:" { send "$passwd\r" }
15        timeout { do_timeout "$host scp" }
16    }
17
18    expect {
19        full_buffer { exp_continue }
20        timeout { exp_continue }
21        eof 
22    }
23}
   第2行调用spawn命令执行scp命令,并用catch捕捉错误;当执行成功后,第12行用expect等待远端输出(超时默认为10秒),第13、14行自动输入用户名和密码,当过程中网络连接断开时,会匹配到第8行的eof;当输出完成连接关闭时,会匹配到第21行的eof;如果输出太多超过expect内部的buffer时,会匹配到第19行的full_buffer,这里由于为了提高效率,使用了静默方式的scp,因些实际会匹配到第20行的timeout,不管匹配到哪种情况,都要继续直到eof。
 
   执行编译
 1proc do_make {host user passwd subdir {to 10} } {
 2    if [catch {spawn ssh $user@$host} msg ] {
 3        send_error "failed to spawn ssh: $msg\n"
 4        exit 1
 5    }
 6    
 7    set timeout $to
 8    expect_after eof { 
 9        send_error "$host ssh died unexpectedly\n"
10        exit 1
11    }
12    
13    expect {  
14        "*yes/no" { send "yes\r"; exp_continue }
15        -re "(?:P|p)assword:" { send "$passwd\r" }  
16        timeout { do_timeout "$host ssh" }
17    }  
18    wait_cmd $spawn_id passwd
19
20    send "cd $subdir\r"  
21    wait_cmd $spawn_id cd
22    
23    send "source configure\r"
24    wait_cmd $spawn_id configure
25
26    send "make\r"  
27    wait_cmd $spawn_id make
28
29    send "exit\r"  
30    expect eof  
31}
   关于spawn和expect的解释与上节拷贝源码相同,不同的是依次发送命令cd、source configure、make,每个命令须等到命令提示符后(调用自定义函数wait_cmd)再发下一个,最后发送exit退出ssh、导致连接关闭,匹配到最后一行的eof。对于有的项目源码,可能没有或不用配置,那么configure文件可以不存在或内容为空,如果不存在导致报错也没关系,不影响make;如果configure出错,那么make也会出错。这里使用source是为了使配置在当前shell中生效。
   
   主循环
 1set f [open $file r]
 2set curtime [clock seconds]
 3
 4log_user 0
 5set s {[:blank:]}
 6set pattern "^(\[^#$s]+)\[$s]+(\[^$s]+)\[$s]+(\[^$s]+)"
 7
 8while { [gets $f line] != -1 } {
 9    if { ![regexp $pattern [string trimleft $line] ? host user passwd] } {
10        continue
11    }
12    send_user "$host $user $passwd\n"
13    if { ![fork] } {
14        
15        set filename output/${host}_[clock format $curtime -format %y.%m.%d_%H.%M.%S].log
16        log_file -noappend -a $filename
17
18        copy_file $host $user $srcdir $dstdir $passwd 30
19        do_make $host $user $passwd $subdir 30
20
21        send_user "$host finish\n"
22        exit
23    }
24}
   打开远程主机配置文件,读取每一行直到文件尾,忽略注释行,用正则提取IP、用户名和密码,创建子进程,按IP和当前时间命名log文件(由于前面调用log_user 0关闭了控制台输出,因此为了能记录输出到日志文件,一定要加-a选项),最后调用函数copy_file和do_make。
   
   完整脚本下载:autobuild.zip
posted on 2016-09-28 11:04 春秋十二月 阅读(3746) 评论(0)  编辑 收藏 引用 所属分类: System

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理