#!/usr/bin/python
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
from pexpect import *
import os, sys, re, commands
from optparse import OptionParser
##exit codes
SPAWNED_BASE_CODE = 100 #exit codes by spawned ssh will be added to 100
MAIN_ERROR = 1 #main program error
TIME_OUT_ERROR = 2 #ssh timeout
SSH_CON_ERROR = 3 #ssh conn error
PASS_ERROR = 4 #ssh pass error
UNKNOWN_ERROR = 5 #ssh unknwon error
#parse options
usage = "pssh [options] host password command"
parser = OptionParser(usage)
parser.add_option("-u", "--username", dest="user",
help="Run using USER, default is current user.")
parser.add_option("-e", "--encrypt-password", action="store_true", dest="encrypt",
help="Use this command with a encrypted password, for DMS only."
)
parser.add_option("-t", "--timeout",
type="int", dest="timeout",
help="When execute time exceeds TIMEOUT, force to exit, default value is 30s.")
#don't parse options in command
p_args = sys.argv[1:]
i = 0
while i < len(p_args):
if re.compile("-[ut].*").match(p_args[i]):
if len(p_args[i]) > 2:
i += 1
else:
i += 2
elif "-e" == p_args[i]:
i += 1
elif re.compile("--[eut].*").match(p_args[i]):
i += 1
else:
break
p_cmd = p_args[(i + 2):]
p_args = p_args[:i+2]
#parse options args.
options, args = parser.parse_args(p_args)
if len(args) < 2:
print parser.format_help()
sys.exit(MAIN_ERROR)
user = options.user
timeout = 30
if options.timeout:
timeout = options.timeout
host = args[0]
password = args[1]
encrypt = False
if options.encrypt:
encrypt = options.encrypt
#if encrypt:
# ret = commands.getstatusoutput('/opt/dms/linux-addon/dms_decrypt ' + password)
# ret = password
# if ret[0] != 0:
# print "decrypt password error."
# sys.exit(MAIN_ERROR)
# password = ret[1]
password = password
cmd = ""
for str in p_cmd:
cmd += ' ' + str
#expect keys
keys = [ 'authenticity',
TIMEOUT,
EOF,
'pssh_exit', #a little chance, ssh don't echo EOF, while remote cmd exiting.
'@@@@@@@@@@@@@@@@@@@@', #key failed
'assword:'
]
def clear_ssh_key():
hostname = host.split('@')[-1]
keyfile = os.environ['HOME'] + "/.ssh/known_hosts"
tmpfile = os.environ['HOME'] + "/.ssh/known_hosts.tmp"
cmd = "sed '/%s/d' %s > %s; mv %s %s" % (hostname, keyfile, tmpfile, tmpfile, keyfile)
os.system(cmd)
clear_ssh_key()
def do_ssh(ssh_cmd, login_test = False):
#clear ; at tail of commands
ssh_cmd=ssh_cmd.strip(';')
#build command to spawn
if user :
command = "ssh -l %s %s '%s; echo $?pssh_exit'" % (user,host,ssh_cmd)
else:
command = "ssh %s '%s; echo $?pssh_exit'" % (host,ssh_cmd)
#spawn it
try:
child = spawn(command, [], timeout)
except Exception, inst:
print inst
sys.exit(MAIN_ERROR)
index = child.expect(keys)
##ssh key failed
if index == 4 or index == 2:
clear_ssh_key()
#respawn it
try:
child = spawn(command, [], timeout)
except Exception, inst:
print inst
sys.exit(MAIN_ERROR)
index = child.expect(keys)
#ssh connect failed
if index == 2 or index == 4:
print child.before.strip()
sys.exit(SSH_CON_ERROR)
#new connection need authenticity
if index == 0:
child.sendline('yes')
index = child.expect(keys)
#got 'assword:', and send it.
if index == 5:
child.sendline(password)
#don't expect password again
if not login_test:
del keys[index]
index = child.expect(keys)
#got 'TIMEOUT'
if index == 1:
print 'run command timeout'
child.close()
sys.exit(TIME_OUT_ERROR)
#got 'assword'
elif index == 5:
print 'wrong password'
sys.exit(PASS_ERROR)
#complete
elif index == 3:
#login_test successful, return to main
if login_test:
return True
output = child.before.strip()
output = output.replace('\r','')
exitval = output.split('\n')[-1]
s = output.split('\n')[0:-1]
for line in s:
print line
try:
sys.exit(int(exitval) + SPAWNED_BASE_CODE)
except StandardError, inst:
print output.split('\n')[-1]
sys.exit(SPAWNED_BASE_CODE) #solve problem when use ps in commands
#Unknown
print 'unknown error'
sys.exit(UNKNOWN_ERROR)
#do twice ssh login, solve this problem: ssh login a host use non-root user,
#and then use su - root change to root run something, su - root will prompt 'Password' like
#ssh do.
#login test
do_ssh("echo ok", True)
#do cmd
do_ssh(cmd)