• Python (paramiko) 连接Linux服务器


    参考资料

    https://www.liujiangblog.com/blog/15/

    https://blog.csdn.net/leorx01/article/details/71141643

    http://docs.paramiko.org/en/stable/api/client.html

    https://www.bilibili.com/video/BV1cQ4y1P7dg?p=4

    Paramiko

    简单说就是一款SSH2的连接工具,Python写的,作为一个测试用来干嘛尼,为了实现个需求,连上数据库服务器,备份/恢复SQL用,(测试前的数据备份-测试后的数据恢复,达到一个互不污染的数据环境, 思路提供者QQ: 1301559180)

    安装

    pip install paramiko

    连接Linux

    import paramiko
    
    # SSH连接对象
    ssh_client = paramiko.SSHClient()
    # 自动接受服务器发过来的密钥
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 用户名 + 密码连接
    ssh_client.connect(hostname="192.168.60.222", port=22, username="root", password="123456")
    # # 用户名 + 私钥连接; 私钥 文件路径
    # private = paramiko.RSAKey.from_private_key_file(r'C:Userszy7y.sshid_rsa')
    # ssh_client.connect(hostname="192.168.60.222", port=22, username="root", pkey=private)
    
    # 执行命令,得到结果 , 返回多个数据 第一个标准输入-用于交互式命令, 第二个标准输出-保存命令的正常执行结果, 第三个标准错误输出
    stdin, stdout, stderr = ssh_client.exec_command("pwd")
    # 返回类型字节 type(stdout.read()) <class 'bytes'>
    # 转成字符串
    print(stdout.read().decode())
    
    # 关闭连接
    ssh_client.close()
    

    文件上传/下载

    import paramiko
    
    # 进行SSH连接
    ssh_client = paramiko.Transport(("192.168.60.222", 22))
    ssh_client.connect(username="root", password="123456")
    
    # # 配置私人密钥文件位置
    # private = paramiko.RSAKey.from_private_key_file('/Users/root/.ssh/id_rsa')
    # # 连接SSH服务端,使用pkey指定私钥
    # ssh_client.connect(username="root", pkey=private)
    
    # 创建ftp客户端
    ftp_client = paramiko.SFTPClient.from_transport(ssh_client)
    
    # 上传文件到服务器,将当前目录下的test.sql 上传到服务器上
    ftp_client.put(localpath="test.sql", remotepath="/root/test3/hello.sql")
    
    
    # 下载文件到本地
    ftp_client.get(localpath="test1.sql", remotepath="/root/test3/hello.sql")
    
    # 关闭ssh连接
    ssh_client.close()
    

    文件封装

    #!/usr/bin/env python
    # _*_ coding: utf-8 _*_
    """
    @project: apiAutoTest
    @file: ssh_demo.py
    @author: zy7y
    @time: 2021/1/18
    @site: https://cnblogs.com/zy7y
    @github: https://github.com/zy7y
    @gitee: https://gitee.com/zy7y
    @desc:
    paramiko封装
    """
    import paramiko
    import os
    
    
    class SSHTools:
        def __init__(self, host: str, port: int = 22, username: str = "root",
                     password: str = None, private_key_file: str = None):
            """
            SSH连接服务器的方案,密码(password)方式和私钥文件(private_key_file)方式只能选择一个
            :param host: 主机地址 str
            :param port: 主机端口 默认(int) 22
            :param username: 登录时所用账号 默认(str) root
            :param password:  账号所对应密码 (str) 默认 None
            :param private_key_file: 私钥文件路径 (str) 默认None 与password 只可选择一个
            """
            ssh_client = paramiko.SSHClient()
            # 自动接受服务器发过来的密钥
            ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            try:
                if password is None:
                    # 用户名 + 私钥文件连接
                    ssh_client.connect(hostname=host, port=port, username=username,
                                       pkey=paramiko.RSAKey.from_private_key_file(private_key_file))
                else:
                    # 用户名 + 密码连接
                    ssh_client.connect(hostname=host, port=port, username=username, password=password)
                print(f"SSH连接成功,address: {host}:{port}!")
                self.ssh_client = ssh_client
            except Exception as e:
                print(f"SSH连接失败, 错误内容: {e}")
    
        def execute_cmd(self, cmd: str):
            """
            :param cmd: 服务器下对应的命令, 可以是list,或者str
            """
            try:
                if isinstance(cmd, list):
                    for c in cmd:
                        stdin, stdout, stderr = self.ssh_client.exec_command(c)
                        print(f"输入命令: {c} -> 输出结果: {stdout.read().decode()},
    异常信息: {stderr.read().decode()}")
                else:
                    stdin, stdout, stderr = self.ssh_client.exec_command(cmd)
                    print(f"输入命令: {cmd} -> 输出结果: {stdout.read().decode()}
    异常信息: {stderr.read().decode()}")
            except Exception as e:
                print(f"错误如下, {e}")
    
        def ssh_close(self):
            """关闭连接"""
            self.ssh_client.close()
            print("已关闭SSH连接...")
    
    
    class SFTPTools:
    
        def __init__(self, host: str, port: int = 22, username: str = "root", password: str = None, private_key_file: str = None):
            # 进行SSH连接
            ssh_client = paramiko.Transport((host, port))
            self.host = host
            if password is None:
                ssh_client.connect(username="root", pkey=paramiko.RSAKey.from_private_key_file(private_key_file))
            else:
                ssh_client.connect(username=username, password=password)
            self.ssh_client = ssh_client
            # 创建ftp客户端
            self.ftp_client = paramiko.SFTPClient.from_transport(ssh_client)
    
        def files_action(self, post: bool, local_path: str = os.getcwd(), remote_path: str = "/root"):
            """
            :param post: 动作 为 True 就是上传, False就是下载
            :param local_path: 本地的文件路径, 默认当前脚本所在的工作目录
            :param remote_path: 服务器上的文件路径,默认在/root目录下
            """
            if post:     # 上传文件
                if remote_path[-1] != "/":
                    remote_path += "/"
                self.ftp_client.put(localpath=local_path, remotepath=f"{remote_path}{os.path.split(local_path)[1]}")
                print(f"文件上传成功: {local_path} -> {host}:{remote_path}{os.path.split(local_path)[1]}")
            else:   # 下载文件
                if local_path[-1] != "\":
                    local_path += "\"
                self.ftp_client.get(localpath=f"{local_path}{os.path.split(remote_path)[1]}", remotepath=remote_path)
                print(f"文件下载成功: {host}:{remote_path}{os.path.split(local_path)[1]} -> {local_path}")
    
        def ssh_close(self):
            """关闭连接"""
            self.ssh_client.close()
            print("已关闭SSH连接...")
    
    
    if __name__ == '__main__':
        # 自己的虚拟机哈
        host = "192.168.60.222"
        username = "root"
        password = "123456"
    
        ssh = SSHTools(host=host, username=username, password=password)
        shell = "uname"
        ssh.execute_cmd(shell)
        ssh.ssh_close()
    
        # SFTP
        sftp = SFTPTools(host=host, username=username, password=password)
        sftp.files_action(True, r"C:Userszy7yDesktopFastAPI.xmind", "/root")
        sftp.files_action(0, remote_path="/root/FastAPI.xmind")
        sftp.ssh_close()
    

    另一种简洁点的

    #!/usr/bin/env python
    # _*_ coding: utf-8 _*_
    """
    @project: apiAutoTest
    @file: ssh_demo.py
    @author: zy7y
    @time: 2021/1/18
    @site: https://cnblogs.com/zy7y
    @github: https://github.com/zy7y
    @gitee: https://gitee.com/zy7y
    @desc:
    paramiko封装
    """
    # SSH  + SFTP 参考链接 https://www.liujiangblog.com/blog/15/
    class LinuxTools:
        def __init__(self, host: str, port: int = 22, username: str = "root", password: str = None, private_key_file: str = None):
            # 进行SSH连接
            self.trans = paramiko.Transport((host, port))
            self.host = host
            if password is None:
                self.trans.connect(username="root", pkey=paramiko.RSAKey.from_private_key_file(private_key_file))
            else:
                self.trans.connect(username=username, password=password)
            # 将sshclient的对象的transport指定为以上的trans
            self.ssh = paramiko.SSHClient()
            self.ssh._transport = self.trans
            # 创建SFTP客户端
            self.ftp_client = paramiko.SFTPClient.from_transport(self.trans)
    
        def execute_cmd(self, cmd: str):
            """
            :param cmd: 服务器下对应的命令, 可以是list,或者str
            """
            try:
                if isinstance(cmd, list):
                    for c in cmd:
                        stdin, stdout, stderr = self.ssh.exec_command(c)
                        print(f"输入命令: {c} -> 输出结果: {stdout.read().decode()},
    异常信息: {stderr.read().decode()}")
                else:
                    stdin, stdout, stderr = self.ssh.exec_command(cmd)
                    print(f"输入命令: {cmd} -> 输出结果: {stdout.read().decode()}
    异常信息: {stderr.read().decode()}")
            except Exception as e:
                print(f"错误如下, {e}")
    
        def files_action(self, post: bool, local_path: str = os.getcwd(), remote_path: str = "/root"):
            """
            :param post: 动作 为 True 就是上传, False就是下载
            :param local_path: 本地的文件路径, 默认当前脚本所在的工作目录
            :param remote_path: 服务器上的文件路径,默认在/root目录下
            """
            if post:  # 上传文件
                if remote_path[-1] != "/":
                    remote_path += "/"
                self.ftp_client.put(localpath=local_path, remotepath=f"{remote_path}{os.path.split(local_path)[1]}")
                print(f"文件上传成功: {local_path} -> {self.host}:{remote_path}{os.path.split(local_path)[1]}")
            else:  # 下载文件
                if local_path[-1] != "\":
                    local_path += "\"
                self.ftp_client.get(localpath=f"{local_path}{os.path.split(remote_path)[1]}", remotepath=remote_path)
                print(f"文件下载成功: {self.host}:{remote_path}{os.path.split(local_path)[1]} -> {local_path}")
    
        def ssh_close(self):
            """关闭连接"""
            self.trans.close()
            print("已关闭SSH连接...")
    
    
    
    if __name__ == '__main__':
        # 自己的虚拟机哈
        host = "192.168.60.222"
        username = "root"
        password = "123456"
        
        ssh_sftp = LinuxTools(host=host, username=username, password=password)
        ssh_sftp.execute_cmd("docker images")
        ssh_sftp.files_action(True, r"C:Userszy7yDesktopFastAPI.xmind", "/root")
        ssh_sftp.files_action(0, remote_path="/root/FastAPI.xmind")
        ssh_sftp.ssh_close()
    

    其他

    找个时间把其和apiAutoTest集成一下吧~~~

  • 相关阅读:
    函数调用与参数传递总结(完成)
    序列总结
    python中如何调用.py文件
    反射获取Class对象的方式有哪些,反射创建对象的方式有哪些
    Dubbo的协议
    长连接和短连接
    hashset 和 treeset
    说说你对java中GC机制的理解
    找不着 jdbc 配置文件解决方案
    web.xml标准配置
  • 原文地址:https://www.cnblogs.com/zy7y/p/14295902.html
Copyright © 2020-2023  润新知