對于運維來說,同時管理多台機器是很辛苦的事情,特别是CDN運維需要同時重新啟動1000台機器的apache的話或者擷取所有機器的狀态,靠人工一個個上遠端機器上去執行非常費勁,為此我寫了一個在一台機器上批量在多台機器上執行shell指令的小程式。
這個程式是順序在各個遠端機器上執行指令,并且把遠端執行的輸出列印出來。
雖然scp指令也可以執行遠端指令,但是這個程式還有一個好處就是有逾時時間(30秒),當某條指令執行超過30秒後,這個程式會繼續執行下一台機器,而遠端的機器上的指令還會繼續執行完畢。直接使用scp執行遠端指令的話必須等指令執行完畢才能退出。
其中用到了expect:
Expect在這個程式裡就是用來幫助自動輸入scp的密碼,Expect主要用于把需要人工互動的程式變為程式自動化完成,這個對于運維批量部署系統,批量無人值守安裝,批量執行指令,批量上傳下載下傳
現代的Shell對程式提供了最小限度的控制(開始,停止,等等),而把互動的特性留給了使用者。 這意味着有些程式,你不能非互動的運作,比如說passwd。 有一些程式可以非互動的運作,但在很大程度上喪失了靈活性,比如說fsck。這表明Unix的工具構造邏輯開始出現問題。Expect恰恰填補了其中的一些裂痕,解決了在Unix環境中長期存在着的一些問題。
Expect使用Tcl作為語言核心。不僅如此,不管程式是互動和還是非互動的,Expect都能運用。
1.multi_scp_shell.sh
#!/bin/bash
#author: yifangyou
#create time:2011-05-17
#用來通過scp在目标機器批量執行指令
#配置檔案格式:
#ssh_hosts=("1.1.1.1" "2.2.2.2")
#ssh_ports=("22" "22") 這個可以預設,預設值為22,或者個數比ssh_hosts少時,使用預設值
#ssh_users=("root" "root") 這個可以預設,預設值為root,,或者個數比ssh_hosts少時,使用預設值
#ssh_passwords=("323" "222") 這個可以預設,預設的話需要從指令行輸入,或者個數比ssh_hosts少時,使用指令行輸入
#執行:sh multi_scp_shell.sh conf_file_path 'cmd'
if [ -z "$2" ]
then
echo "sh multi_scp_shell.sh conf_file_path 'cmd'";
exit;
fi
default_ssh_user="root"
default_ssh_port="22";
#upload shell script file path
scp_upload=scp_upload.sh
#configure file path
conf_file=$1
#shell command
scp_cmd=$2
#判斷conf_file配置檔案是存在
if [ ! -e "$conf_file" ]
echo "$conf_file is not exists";
#read configure file
source $conf_file
#若是沒有在配置檔案裡提供密碼,則在指令行輸入
if [ "${#ssh_passwords[@]}" = "0" ] || [ "${#ssh_passwords[@]}" -lt "${#ssh_hosts[@]}" ]
read -p "please input password:" -s default_ssh_password
success_hosts="";
fail_hosts="";
for((i=0;i<${#ssh_hosts[@]};i++))
do
#remote ssh host
ssh_host=${ssh_hosts[$i]};
if [ "$ssh_host" != "" ]
#remote ssh port
ssh_port=${ssh_ports[$i]};
if [ "$ssh_port" = "" ]
ssh_port=$default_ssh_port; #use default value
#remote ssh user
ssh_user=${ssh_users[$i]};
if [ "$ssh_user" = "" ]
ssh_user=$default_ssh_user; #use default value
#remote ssh password
ssh_password=${ssh_passwords[$i]};
if [ "$ssh_password" = "" ]
ssh_password=$default_ssh_password; #use default value
echo "["`date +"%F %T"`"] (scp -r $ssh_user@$ssh_host:$ssh_port exe '$scp_cmd') start"
#scp file or dir
echo "######################################$ssh_host output start############################################################"
/usr/bin/expect scp_shell.sh "$ssh_host" "$ssh_port" "$ssh_user" "$ssh_password" "$scp_cmd"
if [ "$?" -eq "0" ]
success_hosts="$success_hosts,$ssh_host"
else
fail_hosts="$fail_hosts,$ssh_host"
echo "######################################$ssh_host output end############################################################"
echo "["`date +"%F %T"`"] (scp -r $ssh_user@$ssh_host:$ssh_port exe '$scp_cmd') end"
echo ""
echo "ssh_host[$i]=null"
done
echo "success_hosts=[$success_hosts]"
echo "fail_hosts=[$fail_hosts]"
2.scp_shell.sh的源代碼
#!/usr/bin/expect
set scphost "[lindex $argv 0]"
set port "[lindex $argv 1]"
set scpuser "[lindex $argv 2]"
set scppw "[lindex $argv 3]"
#要執行的shell指令
set cmd "[lindex $argv 4]"
spawn ssh -p $port $scpuser@$scphost "$cmd"
set timeout 30
expect {
#respose: "[email protected]'s password:"
"*password*" {
send "$scppw\r"
}
#the first connect will respose "Are you sure you want to continue connecting (yes/no)? yes"
"*yes*" {
send "yes\r"
expect "*password*"
busy {send_user "\n<error:busy>";exit 1;}
failed {send_user "\n<error:failed>";exit 2;}
timeout {send_user "\n<error:timeout>";exit 3;}
#Permission denied not try again
"*denied*" {
send_user "\n<error:Permission denied>"
exit 4
busy {send_user "\n<error:busy>";exit 5;}
failed {send_user "\n<error:failed>";exit 6;}
timeout {send_user "\n<error:timeout>";exit 7;}
exit 0
3.配置檔案格式scp.conf
#ssh_ports=("22" "22") #wheen port_num < host_num use default=22,or ssh_ports is undefined use 22 as default value
#ssh_users=("root" "root") #wheen user_num < host_num use default=root,or ssh_users is undefined use root as default value
#ssh_passwords=("323" "222") #wheen password_num < host_num use default=input password,or ssh_users is undefined use input password
4.運作代碼
找一台機器可以和要執行指令的機器聯通,安裝好expect(可以用expect指令測試是否已經安裝過了)
把scp_shell.sh,multi_scp_shell.sh,scp.conf放到同一個目錄下,運作multi_scp_shell.sh即可
5.運作效果
<a href="http://blog.51cto.com/attachment/201107/191455154.jpg" target="_blank"></a>
本文轉自yifangyou 51CTO部落格,原文連結:http://blog.51cto.com/yifangyou/610307,如需轉載請自行聯系原作者