ssh paramiko

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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值