/
deployer.py
227 lines (189 loc) · 8.56 KB
/
deployer.py
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
#! /usr/bin/python
# coding:utf-8
import os
import pexpect
import sys
import time
import threading
from multiprocessing import cpu_count, Pool
from fabric import Connection
from server import Server
from getopt import getopt,GetoptError
from utils import print_run_time, auto_save_data, color_str, check_ip, Color, generate_rsa
__author__ = 'Jrohy'
class Deployer:
def _read_file_to_list(self, file_path):
"""
配置文件每一行为一个服务器
格式为 `user@ip port Timestamp`
example: root@192.168.35.62 22 123242343
"""
if not os.path.exists(file_path):
path_tuple = os.path.split(file_path)
if not os.path.exists(path_tuple[0]):
os.makedirs(path_tuple[0])
with open(file_path, 'w'):
return []
server_list=[]
with open(file_path, 'r') as profile:
content_list = profile.readlines()
if content_list:
for line in content_list:
frag_info = line.split("@")
user = frag_info[0]
frag_info = frag_info[1].split(" ")
if len(frag_info) != 4:
raise ValueError('配置格式不正确, 请执行:{}, 再重新运行'.format(color_str(Color.CYAN, 'rm -f ' + file_path)))
ip = frag_info[0]
port = frag_info[1]
keyword = frag_info[2]
create_date = int(frag_info[3])
one_server = Server(ip, user=user, port=port, create_date=create_date, keyword=keyword)
server_list.append(one_server)
return server_list
def print_server(self):
"""
打印这样的格式
====== 服务器列表 =====
serverinfo....
==========================
"""
key = "服务器列表"
print()
print("{:=^90}".format(" {0} ".format(key)))
for index, server in enumerate(self.server_list):
print("%d. %s" % (index + 1, server))
index, condition = 0, 90 + len(key)
while index < condition:
print("{}".format("="), end="")
index = index + 1
print()
print()
def __init__(self, file_path):
self._file_path = file_path
self._server_list = self._read_file_to_list(file_path)
@property
def file_path(self):
return self._file_path
@property
def server_list(self):
return self._server_list
# 不提供setter方法, 只能由modify_server_list方法修改
# @server_list.setter
# def server_list(self, value):
# self._server_list = value
def test_server(self):
"""
批量测试服务器连接性
"""
for server in self.server_list:
server.test_ssh()
def _process_copy(self, server, scp_command, local_path, remote_path, reverse):
if reverse:
print("\n{0} {color_ip}:{local} to {remote}".format(color_str(Color.YELLOW, 'Downloading...'), local=local_path, remote=remote_path, color_ip=color_str(Color.FUCHSIA, server.ip)))
else:
print("\n{0} {local} to {color_ip}:{remote}".format(color_str(Color.YELLOW, 'Uploading...'), local=local_path, remote=remote_path, color_ip=color_str(Color.FUCHSIA, server.ip)))
os.system(scp_command)
@print_run_time('scp传输文件')
def copy_file(self, local_path, remote_path=None, select_server=None, reverse=False):
"""
scp方式复制文件,reverse=True表示从远程复制到本地
"""
select_server = select_server if select_server else self.server_list
pool = Pool(cpu_count() + 1)
for server in select_server:
if not server.is_ok:
print("{} 无法连接, 直接跳过".format(color_str(Color.RED, server.ip)))
continue
# 如果remote_path为空则自动获取
if not remote_path:
if reverse:
remote_path = '.'
else:
result = Connection(server.ip, server.user, server.port).run('echo $HOME', hide=True)
remote_path = result.stdout
else:
# 传输文件前先确保目录远程存在, 自动创建目录
if remote_path.count('/') > 1:
if reverse:
os.system('mkdir -p {}'.format(remote_path[:remote_path.rfind('/')]))
else:
Connection(server.ip, server.user, server.port).run('mkdir -p {}'.format(remote_path[:remote_path.rfind('/')]), hide=True)
if reverse:
scp_command = 'scp -P {server.port} -r {server.user}@{server.ip}:{local} {remote}'.format(server=server, local=local_path, remote=remote_path)
else:
scp_command = 'scp -P {server.port} -r {local} {server.user}@{server.ip}:{remote}'.format(server=server, local=local_path, remote=remote_path)
if server.is_ok:
print("\n多进程模式传输文件: %s" % color_str(Color.CYAN, local_path))
pool.apply_async(self._process_copy, args=(server, scp_command, local_path, remote_path, reverse))
pool.close()
#调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
pool.join()
def _thread_run(self, server, command):
Connection(server.ip, server.user, server.port).run(command)
@print_run_time('运行命令')
def run_command(self, command, select_server=None):
"""
运行命令
"""
select_server = select_server if select_server else self.server_list
if 'tar ' in command:
thread_list = []
print("\n多线程运行命令: %s" % color_str(Color.CYAN, command))
for server in select_server:
if not server.is_ok:
print("{} 无法连接, 直接跳过".format(color_str(Color.RED, server.ip)))
continue
thread = threading.Thread(target=self._thread_run, args=(server, command))
thread_list.append(thread)
thread.start()
for thread in thread_list:
thread.join()
else:
for server in select_server:
print("\n{color_ip} ==> 运行结果:".format(color_ip=color_str(Color.FUCHSIA, server.ip)))
Connection(server.ip, server.user, server.port).run(command)
@auto_save_data
def modify_server_list(self, server=None, clean=False, delete_index=None, orderBy=None, keyword_dict={}):
if server:
for exist_server in self.server_list:
if exist_server.ip == server.ip and exist_server.is_ok:
print("{0} 已存在".format(color_str(Color.FUCHSIA, server.ip)))
return
self._server_list.append(server)
if keyword_dict:
self._server_list[keyword_dict.get('index')].keyword = keyword_dict.get('keyword')
if clean:
self._server_list = list(filter(lambda server:server.is_ok, self.server_list))
if delete_index:
del self._server_list[delete_index]
if orderBy == 'asc':
self._server_list = sorted(self.server_list, key=lambda server:server.create_date)
elif orderBy == 'desc':
self._server_list = sorted(self.server_list, key=lambda server:server.create_date, reverse = True)
def add_server(self, input_str):
if not input_str:
raise ValueError("无传参, 请重新输入")
argv_list = input_str.split(" ")
user, port = 'root', 22
ip = argv_list[0]
if not check_ip(ip):
print("{0} 不是ip".format(color_str(Color.RED, ip)))
return
try:
opts = getopt(argv_list[1:], "u:p:")
for cmd, arg in opts[0]:
if cmd in ("-u", "--username"):
user=arg
elif cmd in ("-p", "--port"):
port=arg
except GetoptError:
print("输入错误, 输入格式为 ip [ -u ][ -p ]\nexample: 192.168.35.62 -u root -p 22")
server=Server(ip, user=user, port=port)
#测试能否连接
server.test_ssh()
#无法连接则复制密钥
if not server.is_ok:
generate_rsa()
server.copy_ssh_id()
self.modify_server_list(server=server)