Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4218482
  • 博文数量: 291
  • 博客积分: 8003
  • 博客等级: 大校
  • 技术积分: 4275
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-30 18:28
文章分类

全部博文(291)

文章存档

2017年(1)

2013年(47)

2012年(115)

2011年(121)

2010年(7)

分类: LINUX

2011-05-17 22:56:25

对于运维来说,同时管理多台机器是很辛苦的事情,特别是CDN运维需要同时重新启动1000台机器的apache的话或者获取所有机器的状态,靠人工一个个上远程机器上去执行非常费劲,为此我写了一个在一台机器上批量在多台机器上执行shell命令的小程序。

这个程序是顺序在各个远程机器上执行命令,并且把远程执行的输出打印出来。

虽然scp命令也可以执行远程命令,但是这个程序还有一个好处就是有超时时间(30秒),当某条命令执行超过30秒后,这个程序会继续执行下一台机器,而远程的机器上的命令还会继续执行完毕。直接使用scp执行远程命令的话必须等命令执行完毕才能退出。

其中用到了expect:
  Expect在这个程序里就是用来帮助自动输入scp的密码,Expect主要用于把需要人工交互的程序变为程序自动化完成,这个对于运维批量部署系统,批量无人值守安装,批量执行命令,批量上传下载
 现代的Shell对程序提供了最小限度的控制(开始,停止,等等),而把交互的特性留给了用户。 这意味着有些程序,你不能非交互的运行,比如说passwd。 有一些程序可以非交互的运行,但在很大程度上丧失了灵活性,比如说fsck。这表明Unix的工具构造逻辑开始出现问题。Expect恰恰填补了其中的一些裂痕,解决了在Unix环境中长期存在着的一些问题。

  Expect使用Tcl作为语言核心。不仅如此,不管程序是交互和还是非交互的,Expect都能运用。

注意:这个小工具一次只能执行一行shell语句,若是要执行多行语句的话,先把这些语句写到一个文件里(例如exe.sh),用我之前写的批量上传工具把exe.sh上传到指定目录(例如/tmp),然后再用这个工具执行"sh /tmp/exe.sh",即可
1.multi_scp_shell.sh
      #!/bin/bash
      #author: yifangyou
      #create time:2011-05-17
    1. #用来通过scp在目标机器批量执行命令
    2. #配置文件格式:
    3. #ssh_hosts=("1.1.1.1" "2.2.2.2")
    4. #ssh_ports=("22" "22") 这个可以缺省,缺省值为22,或者个数比ssh_hosts少时,使用缺省值
    5. #ssh_users=("root" "root") 这个可以缺省,缺省值为root,,或者个数比ssh_hosts少时,使用缺省值
    6. #ssh_passwords=("323" "222") 这个可以缺省,缺省的话需要从命令行输入,或者个数比ssh_hosts少时,使用命令行输入
    7. #执行:sh multi_scp_shell.sh conf_file_path 'cmd'
    8. if [ -z "$2" ]
    9. then
    10. echo "sh multi_scp_shell.sh conf_file_path 'cmd'";
    11. exit;
    12. fi
    13. default_ssh_user="root"
    14. default_ssh_port="22";
    15. #upload shell script file path
    16. scp_upload=scp_upload.sh
    17. #configure file path
    18. conf_file=$1
    19. #shell command
    20. scp_cmd=$2
    21. #判断conf_file配置文件是存在
    22. if [ ! -e "$conf_file" ]
    23. then
    24. echo "$conf_file is not exists";
    25. exit;
    26. fi
    27. #read configure file
    28. source $conf_file
    29. #若是没有在配置文件里提供密码,则在命令行输入
    30. if [ "${#ssh_passwords[@]}" = "0" ] || [ "${#ssh_passwords[@]}" -lt "${#ssh_hosts[@]}" ]
    31. then
    32. read -p "please input password:" -s default_ssh_password
    33. fi
    34. success_hosts="";
    35. fail_hosts="";
    36. for((i=0;i<${#ssh_hosts[@]};i++))
    37. do
    38. #remote ssh host
    39. ssh_host=${ssh_hosts[$i]};
    40. if [ "$ssh_host" != "" ]
    41. then
    42. #remote ssh port
    43. ssh_port=${ssh_ports[$i]};
    44. if [ "$ssh_port" = "" ]
    45. then
    46. ssh_port=$default_ssh_port; #use default value
    47. fi
    48. #remote ssh user
    49. ssh_user=${ssh_users[$i]};
    50. if [ "$ssh_user" = "" ]
    51. then
    52. ssh_user=$default_ssh_user; #use default value
    53. fi
    54. #remote ssh password
    55. ssh_password=${ssh_passwords[$i]};
    56. if [ "$ssh_password" = "" ]
    57. then
    58. ssh_password=$default_ssh_password; #use default value
    59. fi
    60. echo "["`date +"%F %T"`"] (scp -r $ssh_user@$ssh_host:$ssh_port exe '$scp_cmd') start"
    61. #scp file or dir
    62. echo "######################################$ssh_host output start############################################################"
    63. /usr/bin/expect scp_shell.sh "$ssh_host" "$ssh_port" "$ssh_user" "$ssh_password" "$scp_cmd"
    64. if [ "$?" -eq "0" ]
    65. then
    66. success_hosts="$success_hosts,$ssh_host"
    67. else
    68. fail_hosts="$fail_hosts,$ssh_host"
    69. fi
    70. echo "######################################$ssh_host output end############################################################"
    71. echo "["`date +"%F %T"`"] (scp -r $ssh_user@$ssh_host:$ssh_port exe '$scp_cmd') end"
    72. echo ""
    73. else
    74. echo "ssh_host[$i]=null"
    75. fi
    76. done
    77. echo "success_hosts=[$success_hosts]"
    78. echo "fail_hosts=[$fail_hosts]"
    2.scp_shell.sh的源代码
    1. #!/usr/bin/expect
    2. #author: yifangyou
    3. #create time:2011-05-17
    4. set scphost "[lindex $argv 0]"
    5. set port "[lindex $argv 1]"
    6. set scpuser "[lindex $argv 2]"
    7. set scppw "[lindex $argv 3]"
    8. #要执行的shell命令
    9. set cmd "[lindex $argv 4]"
    10. spawn ssh -p $port $scpuser@$scphost "$cmd"
    11. set timeout 30
    12. expect {
    13. #respose: "root@1.2.3.4's password:"
    14. "*password*" {
    15. set timeout 30
    16. send "$scppw\r"
    17. }
    18. #the first connect will respose "Are you sure you want to continue connecting (yes/no)? yes"
    19. "*yes*" {
    20. set timeout 30
    21. send "yes\r"
    22. set timeout 30
    23. expect "*password*"
    24. set timeout 30
    25. send "$scppw\r"
    26. }
    27. busy {send_user "\n";exit 1;}
    28. failed {send_user "\n";exit 2;}
    29. timeout {send_user "\n";exit 3;}
    30. }
    31. #Permission denied not try again
    32. expect {
    33. "*denied*" {
    34. send_user "\n"
    35. exit 4
    36. }
    37. busy {send_user "\n";exit 5;}
    38. failed {send_user "\n";exit 6;}
    39. timeout {send_user "\n";exit 7;}
    40. }
    41. exit 0
    3.配置文件格式scp.conf
    1. #ssh_hosts=("1.1.1.1" "2.2.2.2")
    2. #ssh_ports=("22" "22") #wheen port_num < host_num use default=22,or ssh_ports is undefined use 22 as default value
    3. #ssh_users=("root" "root") #wheen user_num < host_num use default=root,or ssh_users is undefined use root as default value
    4. #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.运行效果

    end
    阅读(11544) | 评论(0) | 转发(5) |
    给主人留下些什么吧!~~