一、EasyXMS简介
EasyXMS是一个用于批量管理Linux/Unix服务器的简易系统,如:多线程批量执行命令、多线程批量上传文件等功能,EasyXMS使用Python2.7编写,并使用paramiko模块来实现SSH连接和SFTP功能。
关注项目主页以获取最新版本:
有什么优势?
简单易用
轻量级,只需要一个脚本文件,不需要安装Client端
安装部署快,一键安装所需的环境
二、主要功能
批量执行命令
批量上传文件
记录每次输入的命令到文件
记录每次执行命令的结果到文件
三、环境安装
1.Python2.7
下载地址:
2.easy_install 工具(是Python安装模块的一个工具,像yum,可以自动解决依赖)
下载地址:
3.PyCrypto 2.1+ 模块(PyCrypto是使用Python编写的加密工具包)
下载地址:
4.paramiko 模块(是用Python编写的支持SSH协议的模块)
使用easy_install 进行安装
具体的安装过程,参看上一篇文章:
http://linux5588.blog.51cto.com/65280/1275180
想省事? 可下载博客附件的一键安装脚本,来安装paramiko模块需要的环境
请使用 < source 脚本名 > 的方式执行脚本
四.运行过程中产生的文件
在脚本的执行过程中,默认是会在当前目录下生成以下文件
1. server.conf
该文件是用于存储各个服务器的连接信息如 IP地址:端口:用户名:密码,存储的信息是经过简单的加密,当然使用的可逆的加密算法,如下所示每行代表一个IP信息:
1
2
MTkyLjE2OC4xMDAuMjAxOjIyOnJvb3Q6MTIzNDU2
MTkyLjE2OC4xMDAuMjAyOjIyOnJvb3Q6MTIzNDU2
2.paramiko.log
该文件是paramiko模块在运行过程中产生的日志文件
3.command_history.log
该文件是记录执行过的命令
4.command_result_history.log
该文件是记录执行过的命令的结果
五、怎么执行脚本?
1. 使用 python 脚本名 方式来执行
1
python EasyXMS.py
2. 使用 脚本的绝对路径来执行,注意加上可执行权限
1
./EasyXMS.py
如果出现以下情况,使用dos2unix转换一下即可
[error.png]
如果没有dos2unix,那么在Windows上使用像EmEditor这类的文本编辑器(不要使用Windows自带的记事本),把换行符修改为仅Unix,即可
[lf.png]
六、操作演示
点击这里看动态演示
1.主菜单
输入? 即可获得主菜单帮助
[mainmenu.png]
功能描述:
1
2
3
4
5
6
7
8
0 增加服务器的IP信息到配置文件(server.conf 以下都指的是该配置文件)
1 加载一个包含多个服务器IP信息的文件,用于批量添加服务器到
2 列出当前配置文件中存在的服务器
3 从配置文件中删除指定的服务器信息
4 清空配置文件
5 批量执行命令
6 批量上传文件
7 清屏
2.选项 0 增加服务器的IP信息到配置文件
[addip1.png]
[addip2.png]
3.选项1 加载一个包含多个服务器IP信息的文件
准备一个文本文件,里面的包含这些内容 IP地址:端口(22端口可以不写):用户名:密码 每行一个 例如:
192.168.100.204:root:123456
192.168.100.205:root:123
192.168.100.206:root:123
[loadfile1.png]
[loadfile2.png]
4.选项 2 列出当前配置文件中存在的服务器
[列出IP地址.gif]
5.选项 3 从配置文件中删除指定的服务器信息
[delete.png]
6.选项 4 清空配置文件
[empty.png]
7.选项 5 批量执行命令
[exec.png]
8.选项 6 批量上传文件
[upload1.png]
[upload2.png]
9.选项 7 清屏
[clear.png]
七、注意事项
1.不能使用vi或者vim编辑远程文件
2.目前不支持tab键补全命令
3.在按 Backspace 键出现以下情况时
[back.png]
可用如下方式来解决:
如果你使用的SecureCRT,可以这样解决
[secre.png]
如果使用的是Xshell,可以这样解决:
[xshell.png]
putty 使用下来没这个问题,但是如果有这个问题,找到类似设置的地方 设置一下即可
八.脚本内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
#!/usr/bin/env python
# coding=utf-8
#---------------------------------------------------------------------
# Name: EasyXMS
# Purpose: Multithreading Batch Execution Commands and Upload Files
# Version: 1.0
# Author: LEO
# BLOG: http://linux5588.blog.51cto.com
# EMAIL: chanyipiaomiao@163.com
# Created: 2013-7-29
# Copyright: (c) LEO 2013
#---------------------------------------------------------------------
from base64 import encodestring,decodestring
from os.path import basename,exists,isfile
from sys import exit,platform
from time import strftime
from Queue import Queue
from os import system
import threading
import paramiko
# 控制输出类
class PrintHelp(object):
def __init__(self):
"""定义命令列表"""
self.cmd_list = [' Add Server ',
' Load File',
' List Servers ',
' Delete Server ',
' Empty File',
' Execute Command ',
' Upload File ',
' Clear Screen',
]
self.name = 'EasyXMS'
self.example = '*** Example *** : '
self.example_ip = '%s192.168.1.1:22:root:123456 192.168.1.3:test:123456 ' % self.example
self.example_delete = '%s192.168.1.1 192.168.1.2 ' % self.example
self.example_filepath = '%s: /tmp/1.txt /tmp' % self.example
def printPrompt(self):
"""脚本运行提示符"""
return "%s( ? Help ) >>> " % self.name
def loopPrintCmd(self):
"""循环打印命令列表"""
print
print "Please Choose A Number : "
print
for i, v in enumerate(self.cmd_list):
print "%5s %-5s" % (i, v)
print
def printHead(self):
"""输出头部提示信息"""
print_string = 'Welcome to Use < %s > , Please Input < ? > ' \
'Get Help Or Direct < Enter > Exit' % self.name
string_temp = "-" * len(print_string)
print string_temp
print
print print_string
print
print string_temp
print
def wantQuit(self):
"""退出提示"""
return "Want Quit? (y/n) [y|Enter]: "
def printInputWrong(self):
"""提示命令输入有误"""
print
print "Wrong Input,Enter < ? > Get Help Or Enter Exit ! "
print
def printFileError(self, e):
"""提示读取主机配置文件出错"""
print "Oops! Read File Occur Wrong : %s" % e
def printFileNotExistOrEmpty(self):
"""提示主机配置文件不存在或者为空,请创建或者添加IP地址到文件"""
print
print "The File [ %s ] Not Exist Or Empty," \
" Enter < 0/1 > to Create Or Add Server IP." % configfile
print
def printInvalidIP(self,info):
"""提示无效的信息"""
print "Invalid Format [ %s ] !!! " % info
print
def printIPFormat(self):
"""添加服务器IP地址的格式"""
print
print self.example_ip
def printDeleteIPFormat(self):
"""删除服务器IP时的格式"""
print
print self.example_delete
print
def printInputIP(self):
"""提示输入IP地址以空格分开"""
return "Enter Server Info : "
def printInputIPForDelete(self):
"""提示输入服务器的IP地址"""
return "Enter Server IP (Only IP Address) : "
def printAddIPSuccessful(self, ip):
"""提示增加服务器IP到配置文件成功"""
print "Add Server [ %s ] to [ %s ] Successful !!! " % (ip, configfile)
print
def printRemoveIPSuccessful(self,ip):
"""提示从配置文件中删除IP地址成功"""
print "Remove [ %s ] From [ %s ] Successful !!!" % (ip,configfile)
print
def printIPNotInFile(self, ip):
"""输出IP地址不在配置文件中"""
print "%s is Not in [ %s ]" % (ip, configfile)
print
def printIPAlreadyInFile(self, ip):
"""输出IP地址已经在配置文件中"""
print "IP [ %s ] Already in [ %s ] !!!" % (ip, configfile)
print
def youSureEmptyFile(self):
"""提示用户是否确认清空文件"""
return "Are You Sure Empty [ %s ] (y/n) : " % configfile
def emptySuccessful(self):
"""输出清空文件成功"""
print "Empty Config File [ %s ] Successful !!!" % configfile
print
def emptyFileFailure(self, e):
"""输出清空文件失败"""
print "Empyt File %s Failure !!! ( %s )" % (configfile, e)
def enterCommand(self):
"""提示输入命令"""
return "Enter Command( q|Q Quit ) : "
def enterFilePath(self):
"""提示输入文件的路径"""
return "Enter [ Local ] Path And < Remote > Path : "
def enterFilePath2(self):
"""加载文件时,提示输入文件路径"""
return "Enter File Path( File Include ip:username:password ) : "
def invaildCommand(self):
"""输出无效的命令"""
print "Invaild Command !!!"
print
def invaildFilePath(self,filepath):
"""无效的文件路径"""
print "Invaild File Path ' %s ' !!!" % filepath
print
def printSSHBePatient(self):
"""输出正在初始化SSH连接,请耐心等待"""
print "Initializing < SSH > Connections, Please Be Patient ..."
print
def printSFTPBePatient(self):
"""输出正在初始化SFTP连接,请耐心等待"""
print "Initializing < SFTP > Connections, Please Be Patient ..."
print
def printCommandResult(self,ip,cmd,out,error):
"""输出命令执行的结果"""
result = "======== [ %s ] Execute Command: ' %s ',The Result is : \n\n%s%s" % (ip,cmd,out,error)
print result
return result
def printCanNotConnectIP(self,ip):
"""输出不能连接到该IP地址"""
print "[ Error ] ... Can't Connect This IP ' %s ', Please Check !!!" % ip
print
def uploadFileOK(self, src, ip):
"""上传文件成功"""
print "Upload File < %s > to %s ... OK " % (src, ip)
print
def uploadFileError(self, src, ip, e):
"""上传文件出现错误"""
print "Upload File < %s > to %s ... Error: %s " % (src, ip, e)
print
def printFilePath(self):
"""输出上传文件时路径的例子"""
print
print self.example_filepath
def printArgsNotenough(self):
"""输出参数不够提示"""
print "Arguments Not Enough !!!"
print
def getDateTime(self):
"""获取日期和时间"""
return strftime('%Y-%m-%d %H:%M:%S')
def returnDateString(self):
"""返回一个日期加星号的字符串用于标识命令执行的结果"""
return '\n********** %s **********\n\n' % self.getDateTime()
def printCannotCreateFile(self,filename,error):
"""提示无法创建文件"""
print
print "Can't Create < %s > !!! : %s" % (filename, error)
print
# 控制输入类
class InputValue(object):
def __init__(self):
self.inputValue = None
def setInputvalue(self):
"""提示输入命令"""
self.inputValue = raw_input(printhelp_obj.printPrompt())
return self.inputValue
def closeConnections(self):
"""关闭连接函数"""
ssh_connect_pool_dict = connectSSH_obj.getConnectionPool()
sftp_connect_pool_dict = connectSFTP_obj.getConnectionPool()
if ssh_connect_pool_dict:
for i in ssh_connect_pool_dict:
ssh_connect_pool_dict[i].close()
if sftp_connect_pool_dict:
for j in sftp_connect_pool_dict:
sftp_connect_pool_dict[j].close()
def exitFunction(self):
"""退出本程序"""
try:
print
quitp = raw_input(printhelp_obj.wantQuit())
print
except EOFError:
self.closeConnections()
print
print
exit(0)
if not quitp or quitp == 'y' or quitp == 'Y':
self.closeConnections()
exit(0)
else:
self.loopGetValue()
def loopGetValue(self):
"""循环得到用户的输入,并判断"""
try:
while self.setInputvalue():
if self.inputValue == '?':
printhelp_obj.loopPrintCmd()
elif self.inputValue == '0':
readwriteconfigFile_obj.writeIPToFile()
elif self.inputValue == '1':
readwriteconfigFile_obj.loadFile()
elif self.inputValue == '2':
readwriteconfigFile_obj.readIPFromFile()
elif self.inputValue == '3':
readwriteconfigFile_obj.deleteIPFromFile()
elif self.inputValue == '4':
readwriteconfigFile_obj.emptyConfigFile()
elif self.inputValue == '5':
startExecAction_obj.startExecCommand()
elif self.inputValue == '6':
startExecAction_obj.startSFTP()
elif self.inputValue == '7':
startExecAction_obj.clearScreen()
else:
printhelp_obj.printInputWrong()
else:
self.exitFunction()
except EOFError :
print
self.exitFunction()
except KeyboardInterrupt:
print
self.exitFunction()
# 操作配置文件类
class ReadWriteConfigFile(object):
def readIPAsDict(self):
"""读取所有的IP地址为一个字典
像这样: {'192.168.1.1':{'port':22,'user':root,'pwd':123456}, }
"""
ip_dict = {}
try:
data = open(configfile,'r')
config_file = data.readlines()
if config_file:
for i in config_file:
i = decodestring(i)
tempstring = i.split(':')
ip = tempstring[0]
if ip not in ip_dict:
ip_dict[ip] = {'port':int(tempstring[1]),
'user':tempstring[2],
'pwd':tempstring[3]}
except:
pass
# 如果文件句柄被打开过,则关闭
try:
data.close()
except:
pass
return ip_dict
def readIPFromFile(self):
"""返回一个IP地址列表"""
ip_list = self.readIPAsDict().keys()
if ip_list:
print
for i in ip_list:
print i
print
else:
printhelp_obj.printFileNotExistOrEmpty()
def fileAppendObject(self,filename):
"""以追加方式打开文件并返回对象"""
data = None
error = None
try:
data = open(filename,'a')
except IOError,e:
error = e
return data,error
def writeFile(self,data,server_list):
"""写文件函数,用于写服务器的配置信息"""
ip_list = self.readIPAsDict().keys()
for ip_info in server_list:
ip,info = self.checkIPInfo(ip_info)
if ip and info:
if ip not in ip_list:
data.write(encodestring(info))
printhelp_obj.printAddIPSuccessful(ip)
else:
printhelp_obj.printIPAlreadyInFile(ip)
def loadFile(self):
"""加载一个包含 IP地址:端口:用户名:密码 的文件批量进行添加"""
data2,error = self.fileAppendObject(configfile)
if data2:
print
filename = raw_input(printhelp_obj.enterFilePath2())
print
if filename:
try:
data = open(filename,'r')
file_ip_list = data.readlines()
data.close()
self.writeFile(data2, file_ip_list)
except IOError,e:
printhelp_obj.printFileError(e)
print
data2.close()
else:
printhelp_obj.printArgsNotenough()
else:
printhelp_obj.printCannotCreateFile(configfile,error)
def checkIPInfo(self,ipinfo):
"""简单的检查输入的IP等信息格式是否正确"""
ip,info = None,None
maohao_num = ipinfo.count(':')
if maohao_num in (2,3):
if ipinfo.count('.') == 3:
info_list = ipinfo.split(':')
if maohao_num == 3:
ip, port, user, passwd = info_list
if maohao_num == 2:
ip, user, passwd = info_list
port = 22
if passwd:
info = '%s:%s:%s:%s' % (ip, port, user, passwd)
else:
printhelp_obj.printInvalidIP(ipinfo)
else:
printhelp_obj.printInvalidIP(ipinfo)
else:
printhelp_obj.printInvalidIP(ipinfo)
return ip,info
def writeIPToFile(self):
"""写入IP地址到配置文件"""
data,error = self.fileAppendObject(configfile)
if data:
printhelp_obj.printIPFormat()
print
hosts = raw_input(printhelp_obj.printInputIP())
print
if not hosts:
printhelp_obj.printArgsNotenough()
else:
server_list = hosts.split()
self.writeFile(data,server_list)
data.close()
else:
printhelp_obj.printCannotCreateFile(configfile, error)
def deleteIPFromFile(self):
"""从配置文件中删除指定的IP地址"""
ip_from_configfile_dict = self.readIPAsDict()
if ip_from_configfile_dict:
printhelp_obj.printDeleteIPFormat()
hosts = raw_input(printhelp_obj.printInputIPForDelete())
print
if len(hosts) == 0:
printhelp_obj.printArgsNotenough()
else:
delete_ip_list = hosts.split()
for i in delete_ip_list:
if i in ip_from_configfile_dict:
del ip_from_configfile_dict[i]
printhelp_obj.printRemoveIPSuccessful(i)
else:
printhelp_obj.printIPNotInFile(i)
if ip_from_configfile_dict:
try:
data = open(configfile, 'w')
for key,value in ip_from_configfile_dict.items():
tempstring = "%s:%s:%s:%s" % (key, value['port'], value['user'], value['pwd'])
data.write(encodestring(tempstring))
except IOError, e:
print
printhelp_obj.printFileError(e)
print
else:
data = open(configfile, 'w')
try:
data.close()
except:
pass
else:
printhelp_obj.printFileNotExistOrEmpty()
def emptyConfigFile(self):
"""清空整个主机配置文件"""
if self.readIPAsDict():
print
ok = raw_input(printhelp_obj.youSureEmptyFile())
print
if ok == 'y' or ok == 'Y':
try:
data = open(configfile, 'w')
except IOError,e:
printhelp_obj.emptyFileFailure(e)
# 如果文件句柄被打开过,则关闭
try:
data.close()
printhelp_obj.emptySuccessful()
except:
pass
else:
printhelp_obj.printFileNotExistOrEmpty()
def readCommandHistory(self):
"""读取历史执行命令"""
command_history_list = []
try:
data = open(command_history,'r')
for cmd in data.readlines():
command_history_list.append(cmd.strip('\n'))
data.close()
except IOError:
pass
return command_history_list
def writeCommandToFile(self,cmd):
"""命令写入到文件"""
command_history_list = self.readCommandHistory()
data,error = self.fileAppendObject(command_history)
if data:
if cmd not in command_history_list:
data.write(cmd+'\n')
data.close()
else:
printhelp_obj.printCannotCreateFile(command_history, error)
def writeCommandResultToFile(self, result_list):
"""命令输出结果写入到文件"""
data,error = self.fileAppendObject(command_result_history)
if data:
data.write(printhelp_obj.returnDateString())
data.write(''.join(result_list))
data.write('\n')
data.close()
else:
printhelp_obj.printCannotCreateFile(command_result_history,error)
# 连接SSH和SFTP类的父类
class Connect(object):
def __init__(self):
self.connect_pool_dict = {}
self.ip_list = []
self.thread_num = None
def getIPList(self):
"""获取SSH/SFTP连接成功的IP地址"""
return self.ip_list
def getThreadNum(self):
"""获取到线程数量,是通过计算IP地址数量得到"""
return self.thread_num
def getConnectionPool(self):
"""获取SFTP/SSH连接池信息"""
return self.connect_pool_dict
# 连接SSH类
class ConnectSSH(Connect):
def connectSSH(self):
"""连接到SSH服务"""
paramiko.util.log_to_file(EasyXMS_log)
server_dict = readwriteconfigFile_obj.readIPAsDict() # 首先获得ServerIP地址列表
if server_dict:
# 这一段就是判断,在ssh的connect_pool_dict这里面现存的IP地址列表跟从配置文件读取出来的列表是否一致
# 如果不一致,那么以配置文件读取出来的IP地址列表为准,删除多余的连接
if self.connect_pool_dict:
connect_pool_list = self.connect_pool_dict.keys()
for i in connect_pool_list:
if i not in server_dict:
del self.connect_pool_dict[i]
self.ip_list.remove(i)
# 这一段是增加 成功进行SSH连接的IP地址到self.connect_pool_dict中去,同时也增加到成功IP地址列表去
for ip,value in server_dict.items():
if ip not in self.connect_pool_dict:
conn = paramiko.SSHClient()
conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
conn.connect(ip,value['port'],value['user'],value['pwd'], timeout=0.8)
self.connect_pool_dict[ip] = conn
self.ip_list.append(ip)
except:
printhelp_obj.printCanNotConnectIP(ip)
self.thread_num = len(self.ip_list)
else:
printhelp_obj.printFileNotExistOrEmpty()
def setCommand(self,command):
"""设定命令行输入的命令"""
self.command = command
def getCommand(self):
"""返回命令"""
return self.command
# 连接到SFTP类
class ConnectSFTP(Connect):
def connectSFTP(self):
"""连接到SFTP服务"""
paramiko.util.log_to_file(EasyXMS_log)
server_dict = readwriteconfigFile_obj.readIPAsDict() # 首先获得ServerIP地址列表
if server_dict:
# 这一段就是判断,在sftp的connect_pool_dict这里面现存的IP地址列表跟从配置文件读取出来的列表是否一致
# 如果不一致,那么以配置文件读取出来的IP地址列表为准,删除多余的连接
if self.connect_pool_dict:
connect_pool_list = self.connect_pool_dict.keys()
for i in connect_pool_list:
if i not in server_dict:
del self.connect_pool_dict[i]
self.ip_list.remove(i)
# 这一段是增加 成功进行SFTP连接的IP地址到self.connect_pool_dict中去,同时也增加到成功IP地址列表去
for ip,value in server_dict.items():
if ip not in self.connect_pool_dict:
conn = paramiko.Transport((ip, value['port']))
try:
conn.connect(username=value['user'], password=value['pwd'])
sftp = paramiko.SFTPClient.from_transport(conn)
self.connect_pool_dict[ip] = sftp
self.ip_list.append(ip)
except:
printhelp_obj.printCanNotConnectIP(ip)
self.thread_num = len(self.ip_list)
else:
printhelp_obj.printFileNotExistOrEmpty()
def getDirectoryName(self, filename, dest):
"""拼接目标文件名"""
if dest.endswith('/'):
dest = '%s/%s' % (dest.rstrip('/'), filename)
else:
dest = '%s/%s' % (dest, filename)
return dest
def setFilePath(self,filepath):
"""设定当前命令行输入的文件路径"""
self.filepath = filepath
def getFilePath(self):
"""返回命令行输入的文件路径"""
return self.filepath
# 多线程类
class MutilThreadControl(threading.Thread):
def setConnectionPool(self, pool):
"""设置使用那个连接池 有SSH和SFTP连接池"""
self.init_pool = pool
def initIPQueueAndtConnectionPool(self):
"""初始一个队列并把IP地址放入队列,返回IP地址列表的长度(指定产生线程的数量)和队列"""
if self.init_pool == 'ssh':
ip_list = connectSSH_obj.getIPList()
connect_pool_dict = connectSSH_obj.getConnectionPool()
elif self.init_pool == 'sftp':
ip_list = connectSFTP_obj.getIPList()
connect_pool_dict = connectSFTP_obj.getConnectionPool()
thread_num = len(ip_list)
ip_queue = Queue(thread_num)
for ip in ip_list:
ip_queue.put(ip)
return ip_queue, thread_num, connect_pool_dict
def run(self):
"""开始多线程执行命令和SFTP上传文件"""
ip_queue, threads_num, connect_pool_dict = self.initIPQueueAndtConnectionPool()
result_list = []
if self.init_pool == 'ssh':
cmd = connectSSH_obj.getCommand()
for i in xrange(threads_num):
ip = ip_queue.get()
stdin,stdout,stderr = connect_pool_dict[ip].exec_command(cmd)
result = printhelp_obj.printCommandResult(ip, cmd, stdout.read(), stderr.read())
result_list.append(result)
readwriteconfigFile_obj.writeCommandResultToFile(result_list)
elif self.init_pool == 'sftp':
file_path = connectSFTP_obj.getFilePath().split()
if len(file_path) == 2:
src,dest = file_path
if exists(src) and isfile(src):
filename = basename(src)
dest = connectSFTP_obj.getDirectoryName(filename, dest)
for i in xrange(threads_num):
ip = ip_queue.get()
try:
connect_pool_dict[ip].put(src, dest)
printhelp_obj.uploadFileOK(src, ip)
except IOError, e:
printhelp_obj.uploadFileError(src, ip, e)
else:
printhelp_obj.invaildFilePath(src)
else:
printhelp_obj.printArgsNotenough()
# 执行指定的动作(执行命令 上传文件 清屏)
class StartExecAction(object):
def startExecCommand(self):
"""开始多线程执行命令"""
mutilThreadControl_ssh_obj = MutilThreadControl()
mutilThreadControl_ssh_obj.setConnectionPool('ssh')
if readwriteconfigFile_obj.readIPAsDict():
print
cmd = raw_input(printhelp_obj.enterCommand())
print
if cmd:
if cmd == 'q' or cmd == 'Q':
pass
else:
readwriteconfigFile_obj.writeCommandToFile(cmd)
connectSSH_obj.setCommand(cmd)
if not connectSSH_obj.getConnectionPool():
printhelp_obj.printSSHBePatient()
connectSSH_obj.connectSSH()
mutilThreadControl_ssh_obj.start()
mutilThreadControl_ssh_obj.join()
self.startExecCommand()
else:
printhelp_obj.invaildCommand()
else:
printhelp_obj.printFileNotExistOrEmpty()
def startSFTP(self):
"""开始上传文件"""
mutilThreadControl_sftp_obj = MutilThreadControl()
mutilThreadControl_sftp_obj.setConnectionPool('sftp')
if readwriteconfigFile_obj.readIPAsDict():
printhelp_obj.printFilePath()
print
filepath = raw_input(printhelp_obj.enterFilePath())
print
if filepath:
connectSFTP_obj.setFilePath(filepath)
if not connectSFTP_obj.getConnectionPool():
printhelp_obj.printSFTPBePatient()
connectSFTP_obj.connectSFTP()
mutilThreadControl_sftp_obj.start()
mutilThreadControl_sftp_obj.join()
else:
printhelp_obj.printArgsNotenough()
else:
printhelp_obj.printFileNotExistOrEmpty()
def clearScreen(self):
"""清屏"""
clear_screen = {'win32':'cls','linux2':'clear',
'linux':'clear','darwin':'clear'}[platform]
system(clear_screen)
if __name__ == '__main__':
configfile = 'server.conf'
EasyXMS_log = 'paramiko.log'
command_history = 'command_history.log'
command_result_history = 'command_result_history.log'
printhelp_obj = PrintHelp()
printhelp_obj.printHead()
readwriteconfigFile_obj = ReadWriteConfigFile()
connectSSH_obj = ConnectSSH()
connectSFTP_obj = ConnectSFTP()
startExecAction_obj = StartExecAction()
input_obj = InputValue()
input_obj.loopGetValue()
阅读(1719) | 评论(1) | 转发(0) |