. python+ssh 首先都会想到用 paramiko,可能因为水平有限,写出来的代码批量操作时就算用了多线程指令特别慢。所以直接封装ssh和scp
本人也是初学python,代码虽然感觉不太规范但能实现功能
准备工作:
- 机器首先密钥认证
- 目录结构
ssh
├── bin/ssh.py
├── conf/host.conf
└── log/201506/30/ 日志按日志分目录保存 - host配置文件:hosts.conf格式如下
ID 服务器 公网IP 内网IP 端口号 1 dev 201.120.111.xx 10.10.10.xx 22
代码:
#!/usr/bin/python
# coding:utf8
import readline,os,commands,sys,threading,datetime,subprocess,re
readline.set_completer_delims(' \t\n`~!@#$%^&*()=+[{]}\\|;:\'",<>/?')
'''本地系统命令补全'''
def allcommands():
a=commands.getoutput("PATH=$PATH:./:/usr/lib:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/cheung/bin;for c in $(echo $PATH |sed 's/:/ /g');do ls $c;done")
return a.strip().split('\n')
def alllocalpath(path=''):
result = []
if not path: path = '.'
for f in os.listdir(path):
qf = os.path.join(path,f)
if os.path.isdir(qf):
result.append(f+os.sep)
else:
result.append(f)
return result
class BufferAwareCompleter(object):
def __init__(self, custcmd, allcmd):
self.options = custcmd
self.current_candidates = []
self.allcmd = allcmd
return
def complete(self, text, state):
response = None
if state == 0:
origline = readline.get_line_buffer()
begin = readline.get_begidx()
end = readline.get_endidx()
being_completed = origline[begin:end]
words = origline.split()
if not words:
self.current_candidates = sorted(self.options)
else:
try:
if begin == 0:
candidates = self.allcmd
else:
if origline.endswith(' '):words.append('')
basedir,basefile = os.path.split(words[-1])
candidates = alllocalpath(basedir)
being_completed = basefile
if being_completed:
self.current_candidates = [ w for w in candidates
if w.startswith(being_completed) ]
else:
self.current_candidates = candidates
except (KeyError, IndexError), err:
self.current_candidates = []
try:
response = self.current_candidates[state]
except IndexError:
response = None
return response
custcmd = ['exit','quit','ex','q','Q','bye']
allcmd = custcmd[:]
allcmd.extend(allcommands())
readline.set_completer(BufferAwareCompleter(custcmd,allcmd).complete)
readline.parse_and_bind('tab: complete')
YearMouth = datetime.datetime.now().strftime('%Y%m')
day = datetime.datetime.now().strftime('%d')
subprocess.call(["mkdir -p ../log/%s/%s" % (YearMouth,day)],shell=True)
class PrintHelp(object):
'''输出类'''
def __init__(self):
self.cmd_ssh = [
'仅单服务器操作',
'批量上传文件',
'批量下载文件',
]
def loopPrintInc(self):
print
for i, v in enumerate(self.cmd_ssh):
print "%5s %-5s" % (i, v)
class Config(object):
'''获取IP列表'''
def getipinfo(self):
iplist = []
data=open('../conf/hosts.conf','r')
ipinfo=data.readlines()
if ipinfo:
for i in ipinfo:
ip = i.split()[3]
if ip not in iplist:
iplist.append(ip)
return iplist
'''生成字典用于单服操作'''
def getipdict(self):
ipinfo = []
dict = {}
dictname = {}
data=open('../conf/hosts.conf','r')
servlist=data.readlines()
if servlist:
for i in servlist:
ip = i.split()[3]
name = i.split()[1]
info = ip + ' ' + name
if info not in ipinfo:
ipinfo.append(info)
for i, v in enumerate(ipinfo):
print "%5s %-5s" % (i, v)
dict[i]=v.split()[0]
dictname[i]=v.split()[1]
choose = raw_input("[choose nums]# ")
if choose in qlist:
exit()
while not choose.isdigit():
choose = raw_input("[only input nums]# ")
if choose in qlist:
exit()
num = int(choose)
if dict.has_key(num):
ip = dict[num]
info = dictname[num]
return ip,info
'''交互输入指令'''
def inputvalue(self):
try:
while True:
printhelp_obj.loopPrintInc()
print
cmd_backlist = ['mv','half','shutdown','reboot','rm -fr','ex']
cmd = raw_input("[ssh_manage]#")
if cmd in custcmd:
exit()
elif cmd in cmd_backlist:
print "Dangerous command [%s],So exit." % cmd
config_obj.inputvalue()
elif cmd == '1':
ip,info = config_obj.getipdict()
while True:
rawout = '[' + ip + '_' + info + ']#'
scmd = raw_input(rawout)
if scmd in qlist:
config_obj.inputvalue()
Control_obj.execommand(ip,scmd)
elif cmd == '2':
Control_obj.putfile()
elif cmd == '3':
Control_obj.getfile()
if cmd:
for ip in config_obj.getipinfo():
Control_obj.execommand(ip,cmd)
'''如果不是特别熟悉避免使用多线程'''
#threads = []
#for ip in config_obj.getipinfo():
# th = threading.Thread(target=Control_obj.execommand,args=(ip,cmd,))
# th.start()
# threads.append(th)
#for th in threads:
# th.join()
except EOFError:
print
exit()
except KeyboardInterrupt:
print
exit()
'''控制类'''
class Control(object):
'''执行命令'''
def execommand(self,ip,cmd):
data=open('../log/' + YearMouth + '/' + day + '/' + 'ssh.log','a')
output=open('../log/' + YearMouth + '/' + day + '/' + 'cmd.log','a')
history="%s|%s: \t%s\n" % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),ip,cmd)
p = subprocess.Popen(['ssh %s -l root -p 22 "%s"' % (ip,cmd)],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout,stderr = p.communicate()
if "sh" not in cmd:
if stderr:
result="[ %s ][ %s ] Execute Command: ' %s ',The Result is :\r\n\n\033[1;31m%s\033[0m" % (ip,datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),cmd,stderr)
else:
result="[ %s ][ %s ] Execute Command: ' %s ',The Result is :\r\n\n\033[1;32m%s\033[0m" % (ip,datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),cmd,stdout)
print result
else:
result="[ %s ][ %s ] Execute Command: ' %s ',The Result is :\r\n\n%s" % (ip,datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),cmd,stdout)
print result
data.write(result)
output.write(history)
data.close()
output.close()
'''上传文件'''
def putfile(self):
local = raw_input("[本地文件路径]#")
remote = raw_input("[远程上传路径]#")
localfile = local.split('/')[-1]
ullog = open('../log/' + YearMouth + '/' + day + '/' + 'upload.log','a')
for ip in config_obj.getipinfo():
p = subprocess.Popen(["scp -rP 22 %s root@%s:%s" % (local,ip,remote)],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout,stderr = p.communicate()
if stderr:
result="\033[1;31m[%s] Upload file \033[1;32m[%s]\033[0m \033[1;31mto [%s] : Failed\033[0m\n" % (datetime.datetime.now().strftime('%H:%M:%S'),localfile,ip)
else:
result="\033[1;32m[%s] Upload file \033[1;31m[%s]\033[0m \033[1;32mto [%s] [%s]: Ok\033[0m\n" % (datetime.datetime.now().strftime('%H:%M:%S'),localfile,ip,remote)
print result
ullog.write(result)
ullog.close()
config_obj.inputvalue()
'''下载文件'''
def getfile(self):
remote = raw_input("[目标文件路径]#")
local = raw_input("[本地绝对路径]#")
remotefile = remote.split('/')[-1]
dllog = open('../log/' + YearMouth + '/' + day + '/' + 'download.log','a')
for ip in config_obj.getipinfo():
localdir = local + '/' + ip
if os.path.exists(localdir):
pass
else:
os.mkdir(localdir)
p = subprocess.Popen(["scp -rP 22 root@%s:%s %s" % (ip,remote,localdir)],shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout,stderr = p.communicate()
if stderr:
result="\033[1;31m[%s] Download file \033[1;32m[%s]\033[0m \033[1;31mfrom [%s] : Failed\033[0m\n" % (datetime.datetime.now().strftime('%H:%M:%S'),remotefile,ip)
else:
result="\033[1;32m[%s] Download file \033[1;31m[%s]\033[0m \033[1;32mfrom [%s] in [%s] : Ok\033[0m\n" % (datetime.datetime.now().strftime('%H:%M:%S'),remotefile,ip,localdir)
print result
dllog.write(result)
dllog.close()
config_obj.inputvalue()
if __name__ == "__main__":
dirname=os.path.split(os.path.realpath(sys.argv[0]))[0]
os.chdir(dirname)
print "欢迎使用[SSH批量操作脚本] 选择一项进行操作 或 直接输入系统命令 [exit]退出"
printhelp_obj = PrintHelp()
config_obj = Config()
Control_obj = Control()
config_obj.inputvalue()
操作功能演示:
登陆后直接对所有服务器进行操作
w

选择单服器操作

批量上传

批量下载

查看日志
[root@10-10-64-58 ssh]# tree log/
log/
└── 201506
└── 30
├── cmd.log
├── download.log
├── ssh.log
└── upload.log
2 directories, 4 files
Linux运维笔记|自动化运维攻城狮

