import time import os, sys path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'libs') sys.path.append(path) import traceback import stat import paramiko from func.wcar_log import printe, printi, printd from func.wcar_config import SLAVE_LOG_PATH, C_SOFT_PATH class SSHConnection(object): """ 功能描述: 完成远程控制相关操作 接口: 通道的链接、关闭 下发命令 文件的上传、下载 远端目录/文件的创建、删除、查看 """ # 初始化连接创建Transport通道 def __init__(self, ip='192.168.200.16', user='root', pwd='Huawei12#$', port=22): try: self.ip = ip self.port = port self.user = user self.pwd = pwd self.is_send = None self.channel_num = 0 # 设置ssh连接的远程主机地址和端口 self.__transport = paramiko.Transport(self.ip, self.port) # # 设置登录名和密码 self.__transport.connect(username=self.user, password=self.pwd) self.sftp = paramiko.SFTPClient.from_transport(self.__transport) self.channel = None self.channels = list() self.project_dir = '/usr/local/bin/mdc_test_tool/' self.home = '/root' print('init, 377-------------------------') except Exception as e: print(e) finally: pass def establish_channel(self): # 连接成功后打开一个channel self.channel = self.__transport.open_session() # 打开远程的terminal self.channel.get_pty() # 激活terminal self.channel.invoke_shell() self.channel_num += 1 time.sleep(0.1) return self.channel def add_channels(self): if self.__transport.is_active(): channel = self.establish_channel() self.channels.append(channel) if self.channel_num > 10: printe('默认最大ssh子进程为10个') return channel @staticmethod def _send_cmd(cmd, channel): size = channel.send(cmd + '\r') time.sleep(0.1) if size: return True else: return False def send_cmd(self, cmd): channel = self.establish_channel() ret = self._send_cmd(cmd, channel) if ret: self.is_send = True else: self.is_send = False return self.is_send def send_cmds(self, cmd_list): self.is_send = True if self.channels: for channel in self.channels: channel.close() self.channel_num -= 1 self.channels = list() for cmd in cmd_list: channel = self.add_channels() ret = self._send_cmd(cmd, channel) self.is_send = self.is_send and bool(ret) return self.is_send def recv_cmd_output(self, timeout=30): start_time = time.time() recs = '' cost_time = -1 cost = 0 while self.is_send and cost < timeout: time.sleep(0.1) if self.channel.recv_ready(): rec = (self.channel.recv(65535).decode('utf-8')) recs += rec if rec.endswith("]# "): cost_time = time.time() - start_time self.is_send = False break cost = time.time() - start_time if cost >= timeout: printe("接收ssh返回数据超时") recs = '' self.channel.close() return recs, cost_time def recv_cmds_output(self, length, timeout=30): recs = [''] * length rec_tmp = [''] * length cost_time = -1.0 start_time = time.time() cost = 0.0 while cost < timeout and self.is_send: time.sleep(0.3) end_flag = False for ch in range(length): if self.channels[ch].recv_ready(): rec = (self.channels[ch].recv(65535).decode('utf-8')) recs[ch] += rec rec_tmp[ch] = rec for rec in range(length): end_flag = True end_flag = end_flag and rec_tmp[rec].endswith("]# ") if end_flag: cost_time = time.time() - start_time break cost = time.time() - start_time if cost >= timeout: recs = [] printe('接收ssh返回数据超时') for chan in self.channels: chan.close() return recs, cost_time def get_cmd_output(self, cmd, timeout=30): self.send_cmd(cmd) recs, cost_time = self.recv_cmd_output(timeout) return recs, cost_time def get_cmds_output(self, cmd_list, timeout=60): send_cmds = cmd_list if isinstance(cmd_list, list) else [cmd_list] length = len(send_cmds) self.send_cmds(send_cmds) recs, cost_time = self.recv_cmds_output(length, timeout) return recs, cost_time def check_exist(self, path_name): cmd = f'ls {path_name}' rec, cost_time = self.get_cmd_output(cmd) if "No such" in rec: return False else: return True def get_cwd(self): cmd = 'pwd' rec, cost_time = self.get_cmd_output(cmd) return rec def chdir(self, path): cmd = f'cd {path}' rec, cost_time = self.get_cmd_output(cmd) dir_name = os.path.basename(path) if dir_name in rec: return True else: return False def tar_dir(self, dirpath): dir_name = os.path.basename(dirpath) cmd = f'tar -czvf ./{dir_name}.tar.gz {dirpath}' rec, cost_time = self.get_cmd_output(cmd) return rec # 关闭通道 def close(self): if self.channel: self.channel.close() self.channel = None self.channel_num -= 1 if self.channels: for channel in self.channels: channel.close() self.channel_num -= 1 self.channels = list() self.__transport.close() # 上传文件到远程主机 def upload(self, local_file, remote_path): try: self.sftp.put(local_file, remote_path) except IOError: local_dir = os.path.dirname(local_file) remote_filename = local_file.replace(local_dir, remote_path) remote_filename = remote_filename.replace('\\', r'/') self.sftp.put(local_file, remote_filename) # 本地文件夹的上传到远程服务器 def sftp_put_dir(self, local_dir, remote_dir): if remote_dir[-1] == "/": remote_dir = remote_dir[0:-1] all_files = self._get_all_files_in_local_dir(local_dir) for file in all_files: if not os.path.isdir(file): remote_filename = file.replace(local_dir, remote_dir) remote_filename = remote_filename.replace('\\', r'/') try: self.sftp.put(file, remote_filename) except FileNotFoundError: break # 下载文件到本地主机 def download(self, remote_path, local_path, remove_enable=False): time.sleep(1) # 获取该文件夹及子文件夹下的所有文件的全路径 remote_all_files = self._get_all_files_in_remote_dir(remote_path) if local_path[-1] != os.sep: local_path += os.sep for remote_filename in remote_all_files: local_filename = str.replace(remote_filename, remote_path, local_path) local_filename = str.replace(local_filename, '/', '\\') try: local_filepath = os.path.dirname(local_filename) if not os.path.exists(local_filepath): os.makedirs(local_filepath) self.sftp.get(remote_filename, local_filename) except Exception as e: print(e.args) print('ssh get dir from master failed.\n==============') # traceback捕获详细的错误信息 print(traceback.format_exc()) finally: pass if remove_enable: main_document = self.sftp.listdir(remote_path) channel = self.establish_channel() for i in main_document: if "MDC_610_1.1_HW_Test" in i or "display" in i: pass else: delete_main_document_cmd = f'rm -rf {remote_path}/{i}\r' time.sleep(0.1) channel.send(delete_main_document_cmd) time.sleep(0.2) def download_file(self, remote_filename, local_path): try: self.sftp.stat(remote_filename) local_filename = str.replace(remote_filename, os.path.dirname(remote_filename), local_path) local_filename = str.replace(local_filename, '/', '\\') self.sftp.get(remote_filename, local_filename) except Exception: print('[Error info]' + remote_filename + ' is not exist.') finally: pass # 下载下位机日志文件到本地 def download_log(self, local_path): self.download(SLAVE_LOG_PATH, local_path) def _get_all_files_in_remote_dir(self, remote_dir): all_files = [] if remote_dir[-1] == '/': remote_dir = remote_dir[0:-1] files = self.sftp.listdir_attr(remote_dir) for i in files: filename = f'{remote_dir}/{i.filename}' if stat.S_ISDIR(i.st_mode): # 文件夹递归处理 all_files.extend(self._get_all_files_in_remote_dir(filename)) else: all_files.append(filename) return all_files # 递归遍历本地服务器指定目录下的所有文件 @staticmethod def _get_all_files_in_local_dir(local_dir): all_files = list() for root, dirs, files in os.walk(local_dir, topdown=True): for file in files: filename = os.path.join(root, file) all_files.append(filename) return all_files # 查看目录下文件以及子目录(如果需要更加细粒度的文件信息建议使用listdir_attr) def listdir(self, target_path): return self.sftp.listdir(target_path) # 查看目录下文件以及子目录的详细信息(包含内容和参考os.stat返回一个FSTPAttributes对象,对象的具体属性请用__dict__查看) def list_dir(self, target_path): try: listdir = self.sftp.listdir_attr(target_path) return listdir except BaseException as e: print(e) finally: pass # 获取文件详情 def stat(self, remote_path): return self.sftp.stat(remote_path) # # copy某一文件夹下的所有文件到指定文件夹 # def copy_file_to_directory(self, old_dir, new_dir): # """ # copy某一文件夹下的所有文件到指定文件夹, 但要除了history和MDC_610_1.1_HW_Test这两个文件夹 # """ # # 获取该文件夹及子文件夹下的所有文件的全路径 # self.get_cmd_output(f"cd /usr/local/bin/mdc_test_tool/") # time.sleep(1) # self.get_cmd_output(f"ll") # time.sleep(1) # self.get_cmd_output(f"cp -r `ls {old_dir} |grep -v history|xargs` {new_dir}") # time.sleep(10) if __name__ == '__main__': # cmd_list = ['USS', 'CAMA', 'VOLT', 'TEMP', 'ETHa', 'ETHb', 'ETHc', 'ETHd', 'ETHe', 'ETHf', # 'ARMA_AIA', 'SPI', 'UFSA'] # cmds_list = ['ETHa', 'ETHb', 'ETHc', 'ETHd', 'ETHe', 'ETHf'] # send_cmds = [] # from scripts.adcsc.cmd_list import PyScripts # for cmd in cmds_list: # send_cmd = PyScripts.get(cmd) # send_cmds.append(send_cmd) ssh = SSHConnection() print(ssh) recs, cost = ssh.get_cmds_output('env') for rec in recs: print(rec) # print(cost) # ssh.close()
ssh paramiko
于 2023-10-25 16:21:14 首次发布