python 库 Paramiko

Paramiko 说明

Paramiko 是一个用于在 Python 中实现SSH协议的模块,它允许你在远程服务器上执行命令、上传和下载文件等操作。

Paramiko 组件

paramiko.Transport

paramiko.Transport 是用于建立安全通信隧道的类,它是 SSH 连接的核心部分。它负责与远程服务器建立连接、身份验证和通信。通过 Transport 对象,你可以执行 SSH 命令、上传和下载文件等操作。
核心功能:
  paramiko.Transport 是 Paramiko 中处理 SSH 连接和传输数据的底层组件。
  它负责建立 SSH 连接,处理加密、身份验证和数据传输等底层细节。

使用场景:
  通常用于需要更底层控制的情况,比如需要自定义算法、处理连接细节或在更高级别的 SSH 客户端之上构建特定功能时使用。

主要方法:
  connect(): 用于建立连接。
  send(): 用于发送数据。
  recv(): 用于接收数据。
  close(): 关闭连接。

paramiko.SSHClient

paramiko.SSHClient 是用于建立 SSH 连接的主要类。通过它,你可以连接到远程服务器,执行命令,上传/下载文件,以及进行其他操作。
核心功能:
  paramiko.SSHClient 是建立在 paramiko.Transport 之上的更高级别的 SSH 客户端类。
  它封装了一些常见的 SSH 操作,简化了与远程服务器的交互。

使用场景:
  通常用于高级别的 SSH 操作,如执行命令、文件传输等常见任务,适合大多数基本的 SSH 客户端需求。

主要方法:
  connect(): 建立连接。
  exec_command(): 执行命令。
  put(): 上传文件。
  get(): 下载文件。
  close(): 关闭连接。

区别

paramiko.Transport 是底层的 SSH 连接实现,提供更细粒度的控制,适合需要处理更多细节的情况。
paramiko.SSHClient 是建立在 paramiko.Transport 之上的高级别接口,简化了常见的 SSH 操作,适合一般的 SSH 客户端需求。
如果需要更多控制或自定义功能,可以使用 paramiko.Transport,而如果只需要简单的 SSH 操作,通常使用 paramiko.SSHClient 更便利。

SSHClient()

属性(Attributes)

missing_host_key_policy:用于设置如何处理缺失的主机密钥的策略。
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

方法(Methods)

连接方法(Connection Methods)

connect(hostname, port=22, username=None, password=None, pkey=None, key_filename=None, timeout=None): 建立到远程主机的 SSH 连接
  hostname: 远程主机的主机名或 IP 地址。
  port: SSH 服务器监听的端口号,默认为 22。
  username: 登录用户名。
  password: 登录密码。
  pkey: SSH 密钥。
  key_filename: SSH 密钥文件的路径。
  timeout: 连接超时时间,以秒为单位。
  
client.connect(hostname, port, username, password, timeout=10)

命令执行方法(Command Execution) 

这一行代码通过SSH客户端执行一个远程命令。exec_command()方法允许你在远程服务器上执行指定的命令。该方法将发送一个命令字符串到远程服务器,并等待服务器的响应。这通常用于执行简单的命令或脚本。
exec_command(command): 在远程主机上执行单个命令。
  command: 要执行的命令字符串。
  返回值:返回包含标准输入、标准输出和标准错误的文件对象。
stdin, stdout, stderr = client.exec_command(f"echo '{password}' | sudo -S -p '' {command}", get_pty=False, timeout=10)

# 读取输出和错误消息(如果有的话)
output = stdout.read().decode('utf-8')  # 读取标准输出
error = stderr.read().decode('utf-8')  # 读取标准错误(如果有的话)

创建新的通道

client.get_transport().open_session(): 这一行代码的作用是创建一个新的SSH会话(session)。它首先从SSH客户端(client)获取一个传输对象(transport),然后通过该传输对象创建一个新的会话(session)。会话用于管理连接生命周期中的所有数据交换,例如发送命令、接收响应等。在这个会话上,可以执行一些会话相关的命令。
  client: 这是一个已经建立的 SSHClient 实例,用于管理 SSH 连接和操作。
  get_transport(): 这是用于获取底层的传输(transport)对象的方法,transport 对象处理底层的数据传输和连接管理。
  open_session(): 这是在传输(transport)上创建一个新的会话(session)通道。通过这个通道,可以执行远程命令、交换数据等。
  channel: 这是一个被创建的会话通道对象,你可以使用它来执行一系列操作,比如执行命令、传输文件等。通常,你会在这个通道上执行具体的操作。
channel.exec_command()
这一行代码与client.exec_command()类似,但它是在特定的会话通道(channel)上执行命令。在SSH连接中,一个会话可以包含多个通道,每个通道可以用于不同的任务。这里通过特定的会话通道执行命令。注意这里的channel是前面通过open_session()方法创建的会话对象。这个调用执行在该通道上下文中定义的命令或脚本。这个方法通常用于发送更多的复杂交互性或需要对服务器返回内容进行进一步处理的情况。与client.exec_command()不同,它可以更加精细地控制通道的生命周期和交互过程。
import paramiko

# 创建SSH客户端并连接到远程服务器
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())  # 自动接受未知主机密钥(仅用于示例)
client.connect('hostname', username='username', password='password')  # 使用实际的主机名、用户名和密码替换这里的信息

# 创建一个会话通道(channel)
channel = client.get_transport().open_session()

# 通过会话通道发送命令并获取输出
channel.exec_command('ls -l')  # 例如,执行一个'ls -l'命令

# 读取输出
output_stdout = channel.recv(4096).decode()  # 读取输出(示例中假设最大输出大小为4096字节)
output_stderr = channel.recv_stderr(4096).decode()

print("命令执行结果:")
print(output_stdout)    # 输出标准输出
print(output_stderr)    # 输出标准错误输出

# 执行第二条命令
channel.exec_command('pwd')  # 例如获取当前工作目录
output = channel.recv(4096).decode()  # 读取命令输出
print(output)  # 打印第二条命令的输出内容


# 关闭会话通道
channel.close()

# 关闭SSH连接
client.close()

SFTP 方法(Secure File Transfer Protocol)

client.open_sftp() 方法用于创建一个 SFTP(SSH 文件传输协议)会话,允许你在 SSH 连接上进行文件操作,如上传、下载、删除文件等
client.open_sftp() 的常见情形:
  文件传输操作:如果你需要与远程服务器上的文件进行交互,如上传文件、下载文件、以及文件夹的创建和删除等操作,client.open_sftp() 方法是很有用的。
  备份和同步:在自动化脚本中备份数据或同步文件时,Paramiko 提供的 SFTP 功能是一种常见的选择。
import paramiko

remote_host = 'xxxxx'
user_name = 'xxxxx'
password = 'xxxxx'

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 连接到远程主机
client.connect(remote_host, username=user_name, password=password,port=22, timeout=5)

# 创建 SFTP 会话
sftp = client.open_sftp()

# 本地文件路径和远程路径
local_path = r'G:\kylinos.repo'
remote_path = '/tmp/kylinos.repo'

try:
    # 上传本地文件到远程服务器
    sftp.put(local_path, remote_path)
    print("File uploaded successfully.")
except Exception as e:
    print(f"Upload failed: {str(e)}")

try:
    # 下载远程文件到本地
    sftp.get(remote_path, r'F:\work\python\files\kylinos.repo')
    print("File downloaded successfully.")
except Exception as e:
    print(f"Download failed: {str(e)}")


# 列出远程目录内容
directory_contents = sftp.listdir('/tmp')
print(directory_contents)

# 关闭 SFTP 会话和 SSH 连接
sftp.close()
client.close()  # 关闭连接

关闭连接

close():关闭 SSH 连接。

示例

import paramiko
import logging


def execute_ssh_commands(hostname, port, username, password, commands):
    # 设置日志记录
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    all_output = {}
    hosts_info = {}

    try:
        logging.info(f"Connecting to {hostname}...")
        client.connect(hostname, port, username, password, timeout=10)

        for command in commands:
            print(f"Executing command: {command}")
            stdin, stdout, stderr = client.exec_command(f"echo '{password}' | sudo -S -p '' {command}", get_pty=False,
                                                        timeout=10)

            command_output = []
            command_error = []

            out_msg = stdout.read().decode('utf-8')
            if out_msg:
                logging.info(out_msg)
                command_output.append(out_msg)

            err_msg = stderr.read().decode('utf-8')
            if err_msg:
                logging.error(err_msg)
                command_error.append(err_msg)

            # 检查命令执行状态
            exit_status = stdout.channel.recv_exit_status()
            if exit_status == 0:
                command_status = 'Success'
            else:
                command_status = 'Failed'

            all_output[command] = {
                'stdout': command_output,
                'stderr': command_error,
                'status': command_status
            }
        hosts_info[hostname] = all_output
        return hosts_info

    except Exception as e:
        logging.error(f"An error occurred: {e}")
        return {hostname: {'error': str(e)}}
    finally:
        if client:
            client.close()
            logging.info("Connection closed.")


# 定义主机信息和命令列表
remote_host = ''
remote_port = 
remote_username = ''
remote_password = '1'
ports = 
commands_to_execute = [
    "bash -c 'for i in $(docker ps | grep -v CONT | awk \"{print \$1}\"); do docker exec -t $i bash -c \"netstat -nlptu | grep -v tcp6 |egrep \"" + str(
        ports) + "\"\"; done | wc -l'",
    "ls",
    "date"
]

# 连接到 SSH,依次执行多个命令并获取结果
result = execute_ssh_commands(remote_host, remote_port, remote_username, remote_password, commands_to_execute)

print(result)

参考文档

https://github.com/paramiko/paramiko

posted @ 2024-07-16 10:07  小吉猫  阅读(1)  评论(0编辑  收藏  举报