15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""hive -- Hive Shell 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This lets you ssh to a group of servers and control them as if they were one. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Each command you enter is sent to each host in parallel. The response of each 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)host is collected and printed. In normal synchronous mode Hive will wait for 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)each host to return the shell command line prompt. The shell prompt is used to 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sync output. 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Example: 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) $ hive.py --sameuser --samepass host1.example.com host2.example.net 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) username: myusername 155e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) password: 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) connecting to host1.example.com - OK 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch connecting to host2.example.net - OK 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) targetting hosts: 192.168.1.104 192.168.1.107 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMD (? for help) > uptime 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ======================================================================= 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host1.example.com 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ----------------------------------------------------------------------- 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptime 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23:49:55 up 74 days, 5:14, 2 users, load average: 0.15, 0.05, 0.01 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ======================================================================= 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host2.example.net 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ----------------------------------------------------------------------- 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uptime 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 23:53:02 up 1 day, 13:36, 2 users, load average: 0.50, 0.40, 0.46 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ======================================================================= 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Other Usage Examples: 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)1. You will be asked for your username and password for each host. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hive.py host1 host2 host3 ... hostN 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch2. You will be asked once for your username and password. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This will be used for each host. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive.py --sameuser --samepass host1 host2 host3 ... hostN 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)3. Give a username and password on the command-line: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive.py user1:pass2@host1 user2:pass2@host2 ... userN:passN@hostN 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)You can use an extended host notation to specify username, password, and host 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)instead of entering auth information interactively. Where you would enter a 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)host name use this format: 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username:password@host 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This assumes that ':' is not part of the password. If your password contains a 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)':' then you can use '\\:' to indicate a ':' and '\\\\' to indicate a single 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'\\'. Remember that this information will appear in the process listing. Anyone 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)on your machine can see this auth information. This is not secure. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This is a crude script that begs to be multithreaded. But it serves its 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)purpose. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Noah Spurrier 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$Id: hive.py 509 2008-01-05 21:27:47Z noah $ 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO add feature to support username:password@host combination 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO add feature to log each host output in separate file 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import sys, os, re, optparse, traceback, types, time, getpass 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import pexpect, pxssh 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import readline, atexit 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#histfile = os.path.join(os.environ["HOME"], ".hive_history") 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#try: 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# readline.read_history_file(histfile) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#except IOError: 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# pass 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#atexit.register(readline.write_history_file, histfile) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CMD_HELP="""Hive commands are preceded by a colon : (just think of vi). 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles):target name1 name2 name3 ... 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set list of hosts to target commands 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles):target all 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reset list of hosts to target all hosts in the hive. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles):to name command 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) send a command line to the named host. This is similar to :target, but 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sends only one command and does not change the list of targets for future 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) commands. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles):sync 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) set mode to wait for shell prompts after commands are run. This is the 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default. When Hive first logs into a host it sets a special shell prompt 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pattern that it can later look for to synchronize output of the hosts. If 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) you 'su' to another user then it can upset the synchronization. If you need 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to run something like 'su' then use the following pattern: 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMD (? for help) > :async 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMD (? for help) > sudo su - root 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMD (? for help) > :prompt 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CMD (? for help) > :sync 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles):async 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set mode to not expect command line prompts (see :sync). Afterwards 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) commands are send to target hosts, but their responses are not read back 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) until :sync is run. This is useful to run before commands that will not 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return with the special shell prompt pattern that Hive uses to synchronize. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles):refresh 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) refresh the display. This shows the last few lines of output from all hosts. 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) This is similar to resync, but does not expect the promt. This is useful 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for seeing what hosts are doing during long running commands. 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles):resync 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) This is similar to :sync, but it does not change the mode. It looks for the 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) prompt and thus consumes all input from all targetted hosts. 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles):prompt 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) force each host to reset command line prompt to the special pattern used to 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) synchronize all the hosts. This is useful if you 'su' to a different user 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) where Hive would not know the prompt to match. 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles):send my text 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) This will send the 'my text' wihtout a line feed to the targetted hosts. 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) This output of the hosts is not automatically synchronized. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles):control X 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This will send the given control character to the targetted hosts. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) For example, ":control c" will send ASCII 3. 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles):exit 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This will exit the hive shell. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def login (args, cli_username=None, cli_password=None): 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # I have to keep a separate list of host names because Python dicts are not ordered. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # I want to keep the same order as in the args list. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host_names = [] 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive_connect_info = {} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive = {} 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # build up the list of connection information (hostname, username, password, port) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for host_connect_string in args: 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hcd = parse_host_connect_string (host_connect_string) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hostname = hcd['hostname'] 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = hcd['port'] 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if port == '': 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) port = None 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(hcd['username']) > 0: 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username = hcd['username'] 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cli_username is not None: 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username = cli_username 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username = raw_input('%s username: ' % hostname) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(hcd['password']) > 0: 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) password = hcd['password'] 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cli_password is not None: 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) password = cli_password 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) password = getpass.getpass('%s password: ' % hostname) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host_names.append(hostname) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive_connect_info[hostname] = (hostname, username, password, port) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # build up the list of hive connections using the connection information. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in host_names: 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'connecting to', hostname 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fout = file("log_"+hostname, "w") 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname] = pxssh.pxssh() 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].login(*hive_connect_info[hostname]) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print hive[hostname].before 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].logfile = fout 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '- OK' 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '- ERROR', 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print str(e) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'Skipping', hostname 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname] = None 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return host_names, hive 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main (): 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global options, args, CMD_HELP 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if options.sameuser: 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cli_username = raw_input('username: ') 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cli_username = None 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if options.samepass: 204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) cli_password = getpass.getpass('password: ') 205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else: 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cli_password = None 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) host_names, hive = login(args, cli_username, cli_password) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) synchronous_mode = True 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_hostnames = host_names[:] 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'targetting hosts:', ' '.join(target_hostnames) 213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while True: 214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) cmd = raw_input('CMD (? for help) > ') 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd = cmd.strip() 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if cmd=='?' or cmd==':help' or cmd==':h': 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print CMD_HELP 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd==':refresh': 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) refresh (hive, target_hostnames, timeout=0.5) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is None: 223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print '/=============================================================================' 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname + ' is DEAD' 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print '/=============================================================================' 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print hive[hostname].before 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '==============================================================================' 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd==':resync': 234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) resync (hive, target_hostnames, timeout=0.5) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is None: 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '/=============================================================================' 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname + ' is DEAD' 239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '/=============================================================================' 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print hive[hostname].before 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '==============================================================================' 246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd==':sync': 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) synchronous_mode = True 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resync (hive, target_hostnames, timeout=0.5) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd==':async': 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) synchronous_mode = False 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd==':prompt': 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is not None: 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].set_unique_prompt() 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Had trouble communicating with %s, so removing it from the target list." % hostname 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print str(e) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname] = None 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd[:5] == ':send': 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd, txt = cmd.split(None,1) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is not None: 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].send(txt) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Had trouble communicating with %s, so removing it from the target list." % hostname 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print str(e) 273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) hive[hostname] = None 274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) continue 275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) elif cmd[:3] == ':to': 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd, hostname, txt = cmd.split(None,2) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is None: 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '/=============================================================================' 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname + ' is DEAD' 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].sendline (txt) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].prompt(timeout=2) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '/=============================================================================' 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print hive[hostname].before 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Had trouble communicating with %s, so removing it from the target list." % hostname 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print str(e) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname] = None 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd[:7] == ':expect': 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd, pattern = cmd.split(None,1) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print 'looking for', pattern 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) try: 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is not None: 300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) hive[hostname].expect(pattern) 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print hive[hostname].before 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Had trouble communicating with %s, so removing it from the target list." % hostname 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print str(e) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname] = None 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd[:7] == ':target': 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_hostnames = cmd.split()[1:] 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(target_hostnames) == 0 or target_hostnames[0] == all: 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_hostnames = host_names[:] 311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print 'targetting hosts:', ' '.join(target_hostnames) 312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) elif cmd == ':exit' or cmd == ':q' or cmd == ':quit': 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) break 315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) elif cmd[:8] == ':control' or cmd[:5] == ':ctrl' : 316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) cmd, c = cmd.split(None,1) 317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if ord(c)-96 < 0 or ord(c)-96 > 255: 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print '/=============================================================================' 319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print '| Invalid character. Must be [a-zA-Z], @, [, ], \\, ^, _, or ?' 320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue 322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for hostname in target_hostnames: 323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) try: 324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if hive[hostname] is not None: 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) hive[hostname].sendcontrol(c) 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) except Exception, e: 327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print "Had trouble communicating with %s, so removing it from the target list." % hostname 328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) print str(e) 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) hive[hostname] = None 330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif cmd == ':esc': 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is not None: 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].send(chr(27)) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Run the command on all targets in parallel 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is not None: 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].sendline (cmd) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Had trouble communicating with %s, so removing it from the target list." % hostname 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print str(e) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname] = None 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # print the response for each targeted host. 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if synchronous_mode: 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in target_hostnames: 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hive[hostname] is None: 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '/=============================================================================' 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname + ' is DEAD' 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].prompt(timeout=2) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '/=============================================================================' 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '| ' + hostname 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '\\-----------------------------------------------------------------------------' 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print hive[hostname].before 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception, e: 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Had trouble communicating with %s, so removing it from the target list." % hostname 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print str(e) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname] = None 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print '==============================================================================' 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def refresh (hive, hive_names, timeout=0.5): 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This waits for the TIMEOUT on each host. 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # TODO This is ideal for threading. 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in hive_names: 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hive[hostname].expect([pexpect.TIMEOUT,pexpect.EOF],timeout=timeout) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def resync (hive, hive_names, timeout=2, max_attempts=5): 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This waits for the shell prompt for each host in an effort to try to get 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) them all to the same state. The timeout is set low so that hosts that are 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) already at the prompt will not slow things down too much. If a prompt match 384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is made for a hosts then keep asking until it stops matching. This is a 385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) best effort to consume all input if it printed more than one prompt. It's 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kind of kludgy. Note that this will always introduce a delay equal to the 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timeout for each machine. So for 10 machines with a 2 second delay you will 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) get AT LEAST a 20 second delay if not more. """ 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # TODO This is ideal for threading. 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for hostname in hive_names: 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for attempts in xrange(0, max_attempts): 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not hive[hostname].prompt(timeout=timeout): 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def parse_host_connect_string (hcs): 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This parses a host connection string in the form 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) username:password@hostname:port. All fields are options expcet hostname. A 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary is returned with all four keys. Keys that were not included are 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set to empty strings ''. Note that if your password has the '@' character 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) then you must backslash escape it. """ 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if '@' in hcs: 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) p = re.compile (r'(?P<username>[^@:]*)(:?)(?P<password>.*)(?!\\)@(?P<hostname>[^:]*):?(?P<port>[0-9]*)') 406 else: 407 p = re.compile (r'(?P<username>)(?P<password>)(?P<hostname>[^:]*):?(?P<port>[0-9]*)') 408 m = p.search (hcs) 409 d = m.groupdict() 410 d['password'] = d['password'].replace('\\@','@') 411 return d 412 413if __name__ == '__main__': 414 try: 415 start_time = time.time() 416 parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='$Id: hive.py 509 2008-01-05 21:27:47Z noah $',conflict_handler="resolve") 417 parser.add_option ('-v', '--verbose', action='store_true', default=False, help='verbose output') 418 parser.add_option ('--samepass', action='store_true', default=False, help='Use same password for each login.') 419 parser.add_option ('--sameuser', action='store_true', default=False, help='Use same username for each login.') 420 (options, args) = parser.parse_args() 421 if len(args) < 1: 422 parser.error ('missing argument') 423 if options.verbose: print time.asctime() 424 main() 425 if options.verbose: print time.asctime() 426 if options.verbose: print 'TOTAL TIME IN MINUTES:', 427 if options.verbose: print (time.time() - start_time) / 60.0 428 sys.exit(0) 429 except KeyboardInterrupt, e: # Ctrl-C 430 raise e 431 except SystemExit, e: # sys.exit() 432 raise e 433 except Exception, e: 434 print 'ERROR, UNEXPECTED EXCEPTION' 435 print str(e) 436 traceback.print_exc() 437 os._exit(1) 438