案例十六:自动化运维 - 批量关Tomcat服务
生产环境中往往在多台机器上运行同一个服务(Tomcat),本案例的需求是批量地关闭这多台机器上的Tomcat服务。假设如下场景:
1)提供一个机器IP和tomcat用户的密码列表(/data/ip-passwd.txt),格式如下
10.111.22.101 passwd1
10.111.22.102 passwd2
10.111.22.103 passwd3
......
2)tomcat所在路径在/opt/tomcat/
3)关闭tomcat服务的命令是/opt/tomcat/bin/shutdown.sh
4)远程机器上只有tomcat一个java应用,即进程java只是关于tomcat的
知识点一:expect脚本登录远程机器
Expect是Unix/Linux系统中用来进行自动化控制和测试的软件工具,它是Tcl脚本语言的一个扩展,应用在交互式软件中如telnet,ftp,ssh,rsync等。下面是一个用expect脚本登录远程机器的示例:
#!/usr/bin/expect
#定义变量
set passwd "123abc321"
#执行命令
spawn ssh root@192.168.10.11
#与远程机器交互 截取特定信息 发送变量
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$passwd\r" }
}
interact
说明:sed为设置变量的指令,passwd为变量名,后面是变量的值。spawn后面为要执行的shell命令(比如ssh、rsync等)。expect{ }里为交互过程,首次ssh登录一台机器时,会问我们是否继续登录,如下:
# ssh 192.168.1.157
The authenticity of host '192.168.1.157 (192.168.18.157)' can't be established.
ECDSA key fingerprint is SHA256:TDkNTP33twBxKTYTh8Fi3EmAvufH/rhFwmH4/0+DoG0.
ECDSA key fingerprint is MD5:2c:60:df:bb:71:50:a1:57:68:c4:fb:73:52:cf:df:c7.
Are you sure you want to continue connecting (yes/no)?
此时,expect会传递一个yes指令,并且回车(\r),之后再一次交互(exp_continue),然后就会提示要我们输入该主机的密码,如下:
Warning: Permanently added '192.168.1.157' (ECDSA) to the list of known hosts.
root@192.168.1.157's password:
expect把$passwd传递给它,然后就能正常登录该主机了。expect { }里面,我们只需要写局部关键词即可,例如本例中我们只写了"password:"。最后面那一行interact的作用是,登录主机后停留在远程的主机上,而不退出。
知识点二:expect脚本登录远程机器并执行命令
登录机器后,还可以在远程的机器上执行命令,示例如下:
#!/usr/bin/expect
set host "192.168.80.102"
set passwd "aaa123bbb"
spawn ssh user1@$host
expect {
"yes/no" {send "yes\r";exp_continue}
"password:" {send "$passwd\r"}
}
expect "]*"
send "touch /tmp/test.aa\r"
expect "]*"
send "echo 111 >/tmp/test.aa\r"
expect "]*"
send "exit\r"
说明:这里的']*'包含了']#'或者']$',这样不管是root用户还是普通用户,都可以匹配到了。
知识点三:给expect脚本传递参数
Expect脚本可以像shell脚本那样接收外部传递的参数,在shell中用$1表示第一个参数,$2表示第二个参数,依此类推。但在expect脚本中,有所不同,示例如下:
#!/usr/bin/expect
set host [lindex $argv 0]
set passwd [lindex $argv 1]
spawn ssh root@$host
expect {
"yes/no" {send "yes\r"}
"password:" {send "$passwd\r"}
}
interact
说明:expect脚本的第一个参数用[lindex $argv 0]表示,第二个参数用[lindex $argv 1]表示,依此类推。
本案例参考脚本
#!/bin/bash
#批量关闭远程机器上的Tomcat服务
#作者:阿铭
#日期:2018-10-29
ipfile=/data/ip-passwd.txt
cat >> kill_tomcat.exp <<EOF
#!/usr/bin/expect
set passwd [lindex \$argv 0]
set host [lindex \$argv 1]
spawn ssh tomcat@\$host
expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "\$passwd\r" }
}
expect "]*"
send "/opt/tomcat/bin/shutdown.sh\r"
expect "]*"
send "if ps aux |grep -q tomcat; then killall -9 java; fi"
expect "]*"
send "exit\r"
EOF
chmod a+x kill_tomcat.exp
cat $ipfile | while read line
do
ip=`echo $line|awk '{print $1}'`
pw=`echo $line|awk '{print $2}'`
./kill_tomcat.exp $pw $ip
done