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:\Users\zy7y\.ssh\id_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()},\n異常信息: {stderr.read().decode()}")
            else:
                stdin, stdout, stderr = self.ssh_client.exec_command(cmd)
                print(f"輸入命令: {cmd} -> 輸出結果: {stdout.read().decode()}\n異常信息: {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:\Users\zy7y\Desktop\FastAPI.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()},\n異常信息: {stderr.read().decode()}")
            else:
                stdin, stdout, stderr = self.ssh.exec_command(cmd)
                print(f"輸入命令: {cmd} -> 輸出結果: {stdout.read().decode()}\n異常信息: {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:\Users\zy7y\Desktop\FastAPI.xmind", "/root")
    ssh_sftp.files_action(0, remote_path="/root/FastAPI.xmind")
    ssh_sftp.ssh_close()

其他

找個時間把其和apiAutoTest集成一下吧~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章