diff --git a/connect.py b/connect.py index de2e18bdb..9f339205e 100644 --- a/connect.py +++ b/connect.py @@ -72,7 +72,8 @@ class Tty(object): self.vim_flag = False self.ps1_pattern = re.compile('\[.*@.*\][\$#]') self.vim_data = '' - + + @staticmethod def is_output(strings): newline_char = ['\n', '\r', '\r\n'] @@ -80,15 +81,46 @@ class Tty(object): if char in strings: return True return False + + + def remove_obstruct_char(cmd_str): + '''删除一些干扰的特殊符号''' + control_char = re.compile(r'\x07 | \x1b\[1P | \r ', re.X) + cmd_str = control_char.sub('',cmd_str.strip()) + patch_char = re.compile('\x08\x1b\[C') #删除方向左右一起的按键 + while patch_char.search(cmd_str): + cmd_str = patch_char.sub('', cmd_str.rstrip()) + return cmd_str + + + def remove_control_char(result_command): + """ + 处理日志特殊字符 + """ + control_char = re.compile(r""" + \x1b[ #%()*+\-.\/]. | + \r | #匹配 回车符(CR) + (?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd + (?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL) + (?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST) + \x1b. #匹配 转义过后的字符 + [\x80-\x9f] | (?:\x1b\]0.*) | \[.*@.*\][\$#] | (.*mysql>.*) #匹配 所有控制字符 + """, re.X) + result_command = control_char.sub('', result_command.strip()) + global VIM_FLAG + if not VIM_FLAG: + if result_command.startswith('vi') or result_command.startswith('fg'): + VIM_FLAG = True + return result_command.decode('utf8',"ignore") + else: + return '' + def deal_command(self, str_r): """ 处理命令中特殊字符 """ - str_r = re.sub('\x07', '', str_r) # 删除响铃 - patch_char = re.compile('\x08\x1b\[C') # 删除方向左右一起的按键 - while patch_char.search(str_r): - str_r = patch_char.sub('', str_r.rstrip()) + str_r = remove_obstruct_char(str_r) result_command = '' # 最后的结果 backspace_num = 0 # 光标移动的个数 @@ -97,16 +129,15 @@ class Tty(object): while str_r: tmp = re.match(r'\s*\w+\s*', str_r) if tmp: + str_r = str_r[len(str(tmp.group(0))):] if reach_backspace_flag: pattern_str += str(tmp.group(0)) - str_r = str_r[len(str(tmp.group(0))):] continue else: result_command += str(tmp.group(0)) - str_r = str_r[len(str(tmp.group(0))):] continue - tmp = re.match(r'\x1b\[K[\x08]*', str_r) + tmp = re.match(r'\x1b\[K[\x08]*', str_r) #处理删除确认符号,删除退格确认之前的数据,当结果队列不够删除时,则将临时队列中的加上一起删除 if tmp: if backspace_num > 0: if backspace_num > len(result_command): @@ -124,12 +155,12 @@ class Tty(object): str_r = str_r[len(str(tmp.group(0))):] continue - tmp = re.match(r'\x08+', str_r) + tmp = re.match(r'\x08+', str_r) #处理退格符号,第一次碰到则记下,第二次碰到则进行删除操作,如果退格符在最后则不计 if tmp: str_r = str_r[len(str(tmp.group(0))):] if len(str_r) != 0: if reach_backspace_flag: - result_command = result_command[0:-backspace_num] + pattern_str + result_command = result_command[0:-backspace_num] + pattern_str pattern_str = '' else: reach_backspace_flag = True @@ -137,32 +168,32 @@ class Tty(object): continue else: break + + tmp = re.match(r'(\x1b\[1@\w)+', str_r) #处理替换的命令 + if tmp: + str_lists = re.findall(r'(?<=\x1b\[1@)\w',str(tmp.group(0))) + tmp_str =''.join(str_lists) + result_command_list = list(result_command) + if len(tmp_str) > 1: + result_command_list[-backspace_num:-(backspace_num-len(tmp_str))] = tmp_str + elif len(tmp_str) > 0: + result_command_list.insert(-backspace_num, tmp_str) + result_command = ''.join(result_command_list) + str_r = str_r[len(str(tmp.group(0))):] + backspace_num = 0 + continue - if reach_backspace_flag: + if reach_backspace_flag: #处理其他没有匹配的字符 pattern_str += str_r[0] else: result_command += str_r[0] str_r = str_r[1:] - if backspace_num > 0: + if backspace_num > 0: #处理最后的退格符号 result_command = result_command[0:-backspace_num] + pattern_str - control_char = re.compile(r""" - \x1b[ #%()*+\-.\/]. | - \r | #匹配 回车符(CR) - (?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd - (?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL) - (?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST) - \x1b. #匹配 转义过后的字符 - [\x80-\x9f] | (?:\x1b\]0.*) | \[.*@.*\][\$#] | (.*mysql>.*) #匹配 所有控制字符 - """, re.X) - result_command = control_char.sub('', result_command.strip()) - if not self.vim_flag: - if result_command.startswith('vi') or result_command.startswith('fg'): - self.vim_flag = True - return result_command.decode('utf8', "ignore") - else: - return '' + result_command = remove_control_char(result_command) + return result_command def get_log(self): """ @@ -261,6 +292,48 @@ class Tty(object): else: self.ssh = ssh return ssh + + def get_connect2(self): + connect_info = self.get_connect_info() + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect((connect_info.get('ip'), connect_info.get('port'))) + except Exception as e: + raise ServerError('连接失败: ' + str(e)) + + try: + transport = paramiko.Transport(sock) + try: + transport.start_client() + except paramiko.SSHException: + raise ServerError('ssh 协商失败.') + + role_key = connect_info.get('role_key') + if role_key and os.path.isfile(role_key): + mykey=paramiko.RSAKey.from_private_key_file(filename=role_key) + transport.auth_publickey(connect_info.get('role_name'), mykey) + else: + transport.auth_password(connect_info.get('role_name'), connect_info.get('role_pass')) + if not transport.is_authenticated(): + raise ServerError('认证失败') + + transport.set_keepalive(30) + transport.use_compression(True) + channel = transport.open_session() + channel.get_pty() + channel.invoke_shell() + win_size = self.get_win_size() + channel.resize_pty(height=win_size[0], width=win_size[1]) + self.channel = channel + return self.channel + except Exception as e: + raise ServerError('*** Caught exception:' + str(e)) + try: + transport.close() + except: + pass + sys.exit(1) + class SshTty(Tty): @@ -388,18 +461,7 @@ class SshTty(Tty): except: pass - # 设置PS1并提示 Set PS1 and msg it - #channel.send(ps1) - #channel.send(login_msg) - # channel.send('echo ${SSH_TTY}\n') - # global SSH_TTY - # while not channel.recv_ready(): - # time.sleep(1) - # tmp = channel.recv(1024) - #print 'ok'+tmp+'ok' - # SSH_TTY = re.search(r'(?<=/dev/).*', tmp).group().strip() - # SSH_TTY = '' - # channel.send('clear\n') + channel.send('TERM=xterm;clear\n') # Make ssh interactive tunnel self.posix_shell()