Monday, January 19, 2009

[Python]一个用ssh来远程登录多台机器并执行命令的脚本

功能类似于multissh。事实上我也抄了这个名字//grin。
要求安装了pexpect这个包先。
用法见usage:
Usage: ./multissh.py -f cmdfile -l username -c cmd -n nodesfile -v -r
execut cmd on remote hosts (all hosts in ./hosts.txt by default)
-v verbose
-r recording hosts on which mission succeeded and failed
-l username
-c cmd to be executed remotely
-n file containing the nodes
-f file conaining the cmd
-h show the usage
就是指定一个文件比如nodes.txt以及命令以后,它可以自动登录到nodes.txt包含的节点里执行命令。可以在源文件里替换进你自己的密码,也可以使用公钥密钥登录不需输入密码。指定了v选项的话得到在远端每台主机上的详细输出。指定了r选项的话记录下那些节点成功那些节点失败。
我前面的帖子里有关于ansi_color的一个脚本,拿过来可以配合使用得到彩色输出

使用前可能要根据情况修改prompt变量的定义. 这个变量是关于登录后提示符的正则表达.我根据我自己的几台机器随便写了两个.未必符合你的情况.
#!/usr/bin/python
import sys
import os
import getopt
import pexpect
import re
try:
    from ansi_color import *
except ImportError:
    def color_str(s, *args):
        return s
    fg_green = None
    fg_red = None
    fg_blue = None

prompt = "^.*\(.*\):|\[.*@.*\]|\$"
nl = open("/dev/null", "w")
    
def _print(s):
    if not single_mode:
        print s    

def do(cmds, hostname, username):
    global verbose, quiet, good_hosts
    #print "executing \"%s\""%(repr(cmds))
    ret = 0
    try:
        sshcmd = 'ssh %s'%(hostname)
        if username != None:
            sshcmd = sshcmd + " -l %s"%username
        s = pexpect.spawn(command=sshcmd, timeout=20)
        if verbose:
            s.logfile_read = sys.stdout
            s.setecho(False)
        else:
            s.logfile_read = s.logfile_send = nl 
            s.setecho(False)
        t = 0
        while t < 3:
            i = s.expect([prompt, pexpect.EOF, pexpect.TIMEOUT,\
                          "Are you sure you want to continue connecting (yes/no)?",\
                          "(P|p)assword:"])
            t += 1
            if i == 0:
                break
            elif i == 1:
                _print("End Of File")
                return 1
            elif i == 2:
                _print("time out")
                return 1
            elif i == 3:
                s.sendline("yes")
            elif i == 4:
                s.sendline(password)
        if t >= 3:
            return 1
        if cmds:
            for cmd in cmds:        
                s.sendline(cmd)
                s.expect(prompt)
        else:
            _print("\nEntering interactive mode, please ^] to escape")
            s.interact()
        s.sendline("exit")
        s.close()
        return 0
    except pexpect.ExceptionPexpect:
        return 1

def print_usage():
    print "Usage:\t ./multissh.py -f cmdfile -l username -c cmd -n nodesfile -v -r"
    print "execut cmd on remote hosts (all hosts in ./hosts.txt by default)"
    print "\t-v verbose"
    print "\t-r recording hosts on which mission succeeded and failed"
    print "\t-l username"
    print "\t-c cmd to be executed remotely"
    print "\t-n file containing the nodes"
    print "\t-f file conaining the cmd"
    print "\t-h show the usage"
    print "\t-p password"
    sys.exit(0)

if __name__ == "__main__":
    try:
        opts, args=getopt.getopt(sys.argv[1:], \
            "l:f:n:c:p:vhrq",["login_name", "cmdfile","nodesfile","command","password","verbose","help","recording","quiet"])
    except getopt.GetoptError, err:
        print str(err)
        print_usage()
    if opts == [] and args == []:
        print_usage()
    if args:
        hosts = [args[0]]
    else:
        hosts = []

    cmds = []
    verbose = False
    quiet = False
    username = None
    recording = False
    password = ""
    single_mode = True
    
    for o, ra in opts:
        a = ra.strip("\n")
        if o in ("-h", "--help"):
            print_usage()
        elif o in ("-n", "--nodesfile"):
            hosts = [l.strip(" \t\n") for l in open(a, 'r')]
            single_mode = False
        elif o in ("-c", "--command"):
            cmds = [a]
        elif o in ("-f", "--cmdfile"):
            cmds = [cmd.strip(' \n') for cmd in open(a, 'r')]
        elif o in ("-v",  "--verbose"):
            verbose = True
        elif o in ("-q", "--quiet"):
            quiet = True
        elif o in ("-r", "--recording"):
            recording = True
        elif o in ("-l", "--login_name"):
            username = a
        elif o in ("-p", "--password"):
            password = a

    if not hosts:
        _print("using default ./hosts.txt")
        h = open(os.path.join(os.path.expanduser("."), "hosts.txt"),'r')
        hosts = [dst.strip(' \n') for dst in h]
        
    if recording:
        f_good = open("good_hosts.txt","w")
        f_bad = open("bad_hosts.txt","w")

    good_hosts =[] 
    bad_hosts =[]
    
    for (i, hostname) in enumerate(hosts):
        _print ("%d/%d: ["%(i+1, len(hosts))+ color_str(hostname, fg_blue)+"]")
        ret = do(cmds, hostname, username)
        if verbose:
            print
        if ret == 1:
            bad_hosts.append(hostname)
            _print("["+color_str("Fail!", fg_red)+"]")
            if recording:
                print>>f_bad, hostname
                f_bad.flush()
        else:
            good_hosts.append(hostname) 
            _print ("["+color_str("OK!", fg_green)+"]")
            if recording:
                print>>f_good, hostname
                f_good.flush()
            

    _print ("%d hosts suceed!"%len(good_hosts))
    sys.exit(ret)

4 comments:

Anonymous said...

Lilac or lavender is іdeаl to caѕt a tendeг fеel to
feast eyes and tug thе chorе on everyone' s heartstrings. The exciting thing about getting married is the part where you make plans and arrangements to make your wedding a perfect one. The bride seeking a perfectly preppy Lilly for her wedding can search the Designer Bride website for a boutique in her area which will carry the fabulous frocks.

Here is my site :: bridesmaids dress

Anonymous said...

The weԁding storеs onlіne often have bigger savings than the stοreѕ сan offeг,
so investing some time into reseaгching
online сan make the most diffеrenсe,
and whеn уou consider that οn dresses сosting
thоusands, you саn be sure to finԁ
the best savings. The Modern Dгess Is
More Αbout Pеrsonal Preferences. First thοugh, ѕhe had to learn hеr craft bу
studyіng under Caгolina Herгera, Αna Suі,
and Veгa Wang іn New York City.

Take a look at my webpage ... vintage wedding dresses

Anonymous said...

Thiѕ is partially becauѕе your on sіtе
ωedding cooгdinator ωill hаve made all the neceѕsary arrangemеntѕ fοr
уou, leaving you free to enjοy уouг dаy, but аlѕo due to the ambienсe of the venuе and thе іntimacy of
the оccaѕiοn ωith your сlοsеst famіlу and frіenԁs arounԁ you.
Plus, іt's great fun trying on lots of different styles and flouncing around like a princess for a day. The guests would not feel confined to a certain area and would be freer to roam around and socialize.

my web blog - preowned wedding dresses

Anonymous said...

Just giѵe yоur measuremеnt and choosе уοur faѵorite stуle, thеn
everything's done for you. The straight physique is distinguished by an upper and lower torso which are the same in width, a normal bust, large rib cage, undefined waist, flat bottom, and slim legs. Something simply hitting around you knees or a sleek slimming white gown with trendy neckline and contrasting colors will look perfectly.

my web-site ... prom dresses