paramiko库

Paramiko是用python语言写的一个模块,远程连接到Linux服务器,查看上面的日志状态,批量配置远程服务器,文件上传,文件下载等

paramiko是一个基于SSH用于连接远程服务器并执行相关操作(SSHClient和SFTPClinet,即一个是远程连接,一个是上传下载服务),使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。

简介

ssh是一个协议,OpenSSH是其中一个开源实现,paramiko是Python的一个库,实现了SSHv2协议(底层使用cryptography)。

有了Paramiko以后,我们就可以在Python代码中直接使用SSH协议对远程服务器执行操作,而不是通过ssh命令对远程服务器进行操作。

由于paramiko属于第三方库,所以需要使用如下命令先行安装

$ pip3 install paramiko

Paramiko介绍

paramiko包含两个核心组件:SSHClient和SFTPClient。

  • SSHClient的作用类似于Linux的ssh命令,是对SSH会话的封装,该类封装了传输(Transport),通道(Channel)及SFTPClient建立的方法(open_sftp),通常用于执行远程命令。
  • SFTPClient的作用类似与Linux的sftp命令,是对SFTP客户端的封装,用以实现远程文件操作,如文件上传、下载、修改文件权限等操作。

Paramiko中的几个基础名词:
1、Channel:是一种类Socket,一种安全的SSH传输通道;
2、Transport:是一种加密的会话,使用时会同步创建了一个加密的Tunnels(通道),这个Tunnels叫做Channel;
3、Session:是client与Server保持连接的对象,用connect()/start_client()/start_server()开始会话。

Paramiko的基本使用

SSHClient常用的方法介绍

connect():实现远程服务器的连接与认证,对于该方法只有hostname是必传参数。

常用参数

  • hostname 连接的目标主机
  • port=SSH_PORT 指定端口
  • username=None 验证的用户名
  • password=None 验证的用户密码
  • pkey=None 私钥方式用于身份验证
  • key_filename=None 一个文件名或文件列表,指定私钥文件
  • timeout=None 可选的tcp连接超时时间
  • allow_agent=True, 是否允许连接到ssh代理,默认为True 允许
  • look_for_keys=True 是否在~/.ssh中搜索私钥文件,默认为True 允许
  • compress=False, 是否打开压缩

set_missing_host_key_policy():设置远程服务器没有在know_hosts文件中记录时的应对策略。目前支持三种策略:

设置连接的远程主机没有本地主机密钥或HostKeys对象时的策略,目前支持三种:

  • AutoAddPolicy 自动添加主机名及主机密钥到本地HostKeys对象,不依赖load_system_host_key的配置。即新建立ssh连接时不需要再输入yes或no进行确认
  • WarningPolicy 用于记录一个未知的主机密钥的python警告。并接受,功能上和AutoAddPolicy类似,但是会提示是新连接
  • RejectPolicy 自动拒绝未知的主机名和密钥,依赖load_system_host_key的配置。此为默认选项

exec_command():在远程服务器执行Linux命令的方法。

open_sftp():在当前ssh会话的基础上创建一个sftp会话。该方法会返回一个SFTPClient对象。

# 利用SSHClient对象的open_sftp()方法,可以直接返回一个基于当前连接的sftp对象,可以进行文件的上传等操作. 
sftp = client.open_sftp()
sftp.put('local.txt','remote.txt')

SSHClient常用的方法举例

import paramiko   
# 实例化SSHClient  
ssh_client = paramiko.SSHClient()   
# 自动添加策略,保存服务器的主机名和密钥信息,如果不添加,那么不再本地know_hosts文件中记录的主机将无法连接 ,此方法必须放在connect方法的前面
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())   
# 连接SSH服务端,以用户名和密码进行认证 ,调用connect方法连接服务器
ssh_client.connect(hostname='192.168.137.105', port=22, username='root', password='123456')   
# 打开一个Channel并执行命令  结果放到stdout中,如果有错误将放到stderr中
stdin, stdout, stderr = ssh_client.exec_command('df -hT ') 
# stdout 为正确输出,stderr为错误输出,同时是有1个变量有值   # 打印执行结果  print(stdout.read().decode('utf-8'))  
# 关闭SSHClient连接 
ssh_client.close()

密钥文件的连接方式

# 配置私人密钥文件位置
private = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa') 


#实例化SSHClient
ssh_client = paramiko.SSHClient() 


#自动添加策略,保存服务器的主机名和密钥信息,如果不添加,那么不再本地know_hosts文件中记录的主机将无法连接
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 


#连接SSH服务端,以用户名和密码进行认证
ssh_client.connect(
hostname='192.168.137.100',
port=22,
username='root',
pkey=private
)

密钥字符串的连接方式

import paramiko
from io import StringIO

# 创建SSH客户端
client = paramiko.SSHClient()

# 自动添加服务器的SSH密钥(这将使您的连接不安全,因为它允许任何密钥。在生产环境中,请使用更安全的方法验证服务器的密钥)
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 替换为您的主机IP地址、用户名和私钥文件路径
host = '10.0.0.12'
username = 'admin'
private_key_string = """-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA3UQ3VIIINqd1kmXf2+tPIMBj494rWatU5Y7krBhlIpUakaMW
ksjPcAt2r4vTW1pa96i933BfFXn406lmPR/HFotsw129DLLaEnI9KFDGnFv/Qvzf
SBYtLgguDxbo+tom8oTckJgjAPhUbFM0Wj+Rszv5+9tHnEXLdebYYBWDw/otB1sv
7NHcLRk2LtrYco3HWAoNgRBXj/UpUBlcgBEN0SDx+IEoeQyQpVHvlSksGoC9iR+e
gIxwYfBusVmbQf78RlMmWjYEiTFHWbRg20h9D82cXiErV0fwwx/gmvgCESPRqat7
3J7xOMzo0UJI7Vz6npVbHaWUVG+hLSanuaRXuQIDAQABAoIBAGASxpODAl34yCwQ
3+p1eZ4W60h9pwUAR5SFPvUago9JfofN8Hc7ihZ0Y8xFQjhgOy9drVPfTuncVBZT
b3kK2z8Guur5QKTK47UutS9UI2iw6V0Ev05lkqhyFM2ofPCu2EplNf/yjwBU0xNV
7V1iTLkuSZT52VYZWAaRfVH7BYOJxeutReFvVV5VI1vp1aeNWOGcU0iJLZD46pS8
z/pKHc/tEMe2h62RlgX2MT8QdegYKIBz7E/sPKYeog9IOEuanDHLSoi4Bgz9UGGZ
1ijRLkAM+rYYgXNKfAT/bfvR+uFu9F1hI1LRz/e3ENBeJiaMT7OgsIYE7ygJq0cN
PVZMbAECgYEA/qvMxGN9GjSq+9BCZ2cIjdflNdzVrSHJ2uqm1qkbrxdO1VbbrPN/
XKFGWXJwJ7YnJZCy4eEDF2ybNivulHpkdkF2E9sTduUbuOcI1YHSFA76FSDJVbL5
89Tz+tUP0QnpGZ5zs851TbrpC6vGbcBVCfGBNNIneIY+12eoAxwmMskCgYEA3mvL
AWQlsxfuZIjwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxZGJ
6gCMVEJP5LGoxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAL2
tqy9cQbJhI41xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx6sC
QYUvLkFI4lG2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxovi
h2ylPFgt+CjPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxeOf
7UQwZKbwPPDzxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxp5U
Lq1LJ2HdwsHSHAdzIIkids0ihMVgR6mHLeMSWRya3DOG4qXGgMZJoZK6HYjqSsRK
rkGR7RGgedYVf+tpuuYexxxxxxxxxxxxxxxxxxxxxxeK8AMiFVSIqupw==
-----END RSA PRIVATE KEY-----"""

# 从私钥字符串创建一个RSAKey对象
private_key = paramiko.RSAKey.from_private_key(StringIO(private_key_string))

# 使用SSH密钥连接到主机
client.connect(host, username=username, pkey=private_key)

# 执行远程命令
stdin, stdout, stderr = client.exec_command("hostname;date +'%Y-%m-%d %T'")

# 输出执行结果
print(stdout.read().decode('utf-8'))

# 关闭连接
client.close()

SFTPClient常用方法介绍

#SFTPCLient作为一个sftp的客户端对象,根据ssh传输协议的sftp会话,实现远程文件操作,如上传、下载、权限、状态 
from_transport(cls,t)    #创建一个已连通的SFTP客户端通道
put(localpath, remotepath, callback=None, confirm=True)    #将本地文件上传到服务器 
#参数confirm:是否调用stat()方法检查文件状态,返回ls -l的结果
get(remotepath, localpath, callback=None) #从服务器下载文件到本地
mkdir() #在服务器上创建目录
remove() #在服务器上删除目录
rename() #在服务器上重命名目录
stat() #查看服务器文件状态
listdir() #列出服务器目录下的文件

SFTPClient常用方法举例

import paramiko 
# 实例化一个transport对象
tran = paramiko.Transport(('192.168.137.100', 22)) 
# 连接SSH服务端,使用password
tran.connect(username="root", password='123456')
# 或使用
# 配置私人密钥文件位置
private = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')
# 连接SSH服务端,使用pkey指定私钥
tran.connect(username="root", pkey=private) 
# 获取SFTP实例
sftp = paramiko.SFTPClient.from_transport(tran) 
# 设置上传的本地/远程文件路径
local_path = "/home/1.txt"
remote_path = "/tmp/1.txt" 
# 执行上传动作
sftp.put(local_path, remote_path)
# 执行下载动作
sftp.get(remote_path, local_path) 
# 关闭Transport通道
tran.close()

例子

import datetime
import paramiko
from paramiko.channel import ChannelStdinFile, ChannelFile, ChannelStderrFile

ssh = None
now = datetime.datetime.now()
try:
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy)
    ssh.connect(
        hostname="10.0.0.10",
        username="root",
        password="111111",
        timeout=5
    )
except BaseException as e:
    print(e)
    print("连接失败")
    exit(100)
finally:
    print((datetime.datetime.now() - now).total_seconds())

cmd = "tree /etc/yum.repos.d"
stdin, stdout, stderr = ssh.exec_command(cmd)
stdin: ChannelStdinFile
stdout: ChannelFile
stderr: ChannelStderrFile
stdin.write("abc\n")
for i in stdout.readlines():
    print(i.strip())
print(stderr.readlines())
ssh.close()

完整代码示例

操作单台主机

# 单台主机操作
import paramiko
#############################配置信息#####################################
# 登陆参数设置
hostname = "192.168.137.100"  
host_port = 22
username = "root"
password = "123456"
########################################################################

def ssh_client_con():
    """创建ssh连接,并执行shell指令"""
    # 1 创建ssh_client实例
    ssh_client = paramiko.SSHClient()
    # 自动处理第一次连接的yes或者no的问题
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)

    # 2 连接服务器
    ssh_client.connect(
        port=host_port,
        hostname=hostname,
        username=username,
        password=password
    )

    # 3 执行shell命令
    # 构造shell指令
    shell_command = "ps aux"
    # 执行shell指令
    stdin, stdout, stderr = ssh_client.exec_command(shell_command)
    # 输出返回信息
    stdout_info = stdout.read().decode('utf8')
    print(stdout_info)

    # 输出返回的错误信息
    stderr_info = stderr.read().decode('utf8')
    print(stderr_info)


def sftp_client_con():
    # 1 创建transport通道
    tran = paramiko.Transport((hostname, host_port))
    tran.connect(username=username, password=password)
    # 2 创建sftp实例
    sftp = paramiko.SFTPClient.from_transport(tran)

    # 3 执行上传功能
    local_path = "米汤.jpg"          # 本地路径
    remote_path = "/home/333.jpg"    # 远程路径
    put_info = sftp.put(local_path, remote_path, confirm=True)
    print(put_info)
    print(f"上传{local_path}完成")
    # 4 执行下载功能
    save_path = "7.jpg"             # 本地保存文件路径
    sftp.get(remotepath=remote_path, localpath=save_path)
    print(f'下载{save_path}完成')

    # 5 关闭通道
    tran.close()


# 调用函数执行功能
ssh_client_con()
sftp_client_con()

批量操作主机

import paramiko


def ssh_client_con():
    """创建ssh连接,并执行shell指令"""
    # 1 创建ssh_client实例
    ssh_client = paramiko.SSHClient()
    # 自动处理第一次连接的yes或者no的问题
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)

    # 2 连接服务器
    ssh_client.connect(
        port=host_port,
        hostname=hostname,
        username=username,
        password=password
    )

    # 3 执行shell命令
    # 构造shell指令
    shell_command = """
    path='/tmp'
    tree ${path}
    # 如果tree命令执行失败,则安装tree后再执行
    if [ $? -ne 0 ]
    then
        yum install -y tree
        tree ${path}
    fi

    """
    # 执行shell指令
    stdin, stdout, stderr = ssh_client.exec_command(shell_command)
    # 输出返回信息
    stdout_info = stdout.read().decode('utf8')
    print(stdout_info)

    # 输出返回的错误信息
    stderr_info = stderr.read().decode('utf8')
    print(stderr_info)


def sftp_client_con():
    # 1 创建transport通道
    tran = paramiko.Transport((hostname, host_port))
    tran.connect(username=username, password=password)
    # 2 创建sftp实例
    sftp = paramiko.SFTPClient.from_transport(tran)

    # 3 执行上传功能
    local_path = "米汤.jpg"
    remote_path = "/home/333.jpg"
    put_info = sftp.put(local_path, remote_path, confirm=True)
    print(put_info)
    print(f"上传{local_path}完成")
    # 4 执行下载功能
    save_path = "7.jpg"
    sftp.get(remotepath=remote_path, localpath=save_path)
    print(f'下载{save_path}完成')

    # 5 关闭通道
    tran.close()


# 读取主机信息
try:
    with open('host_site.txt', 'r', encoding='utf8') as host_file:
        for host_info in host_file:
            line = host_info.strip('\n')
            hostname, host_port, username, password = line.split(',')
            print(f'---------------{hostname}执行结果-----------')
            ssh_client_con()   # 执行command并返回结果
            # 本例适合批量主机处理相同的command
except FileNotFoundError as e:
    print(e)


#  host_site.txt 文件内容格式如下
#  主机地址         端口 用户  密码
#  192.168.137.100,22,root,123456
#  192.168.137.101,22,root,123456
#  192.168.137.102,22,root,123456
#  192.168.137.103,22,root,123456
#  192.168.137.104,22,root,123456

例子

获取主机信息

import paramiko
import time


def test(ip, username, password, port):
    # 创建一个ssh的客户端,用来连接服务器
    ssh = paramiko.SSHClient()
    # 创建一个ssh的白名单
    know_host = paramiko.AutoAddPolicy()
    # 加载创建的白名单
    ssh.set_missing_host_key_policy(know_host)
    # 调用connect方法连接服务器
    try:
        ssh.connect(ip, port, username, password, timeout=3)
        print("\n------------------------系统--------------------------------")
        try:
            stdin, stdout, stderr = ssh.exec_command("pwd")
            print("\n【1】.当前位置(pwd):%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("cat /etc/issue")
            print("\n【2】.查看操作系统版本(cat /etc/issue):%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("hostname")
            print("\n【3】.计算机名(hostname):%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("uname -a")
            print("\n【4】.查看系统体系结构(uname -a):%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("uname -m")
            print("\n【5】.CPU架构(uname -m):%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("cat /proc/cpuinfo")
            print("\n【6】.查看CPU信息(cat /proc/cpuinfo):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("lsmod")
            print("\n【7】.列出加载的内核模块(lsmod):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("env")
            print("\n【8】.查看环境变量(env):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("lsusb -tv")
            print("\n【9】.列出所有USB设备(lsusb -tv):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("cat /proc/bus/input/devices")
            print("\n【10】.列出所有输入设备(cat /proc/bus/input/devices):")
            print(stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        try:
            stdin, stdout, stderr = ssh.exec_command("cat /proc/devices")
            print("\n【11】.系统已经加载的所有块设备信息(cat /proc/devices):")
            print(stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)
        print("\n------------------------资源--------------------------------")
        try:
            stdin, stdout, stderr = ssh.exec_command("free -m")
            print("\n【1】.内存信息(free -m):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            # fdisk -l //分区情况 , df -h //大小情况
            stdin, stdout, stderr = ssh.exec_command("fdisk -l")
            print("\n【2】.硬盘信息(fdisk -l):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            stdin, stdout, stderr = ssh.exec_command("df -h")
            print("\n【3】.查看各分区使用情况(df -h):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            stdin, stdout, stderr = ssh.exec_command("cat /proc/loadavg")
            print("\n【4】.查看系统负载:\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        print("\n------------------------网络--------------------------------")

        try:
            stdin, stdout, stderr = ssh.exec_command("ifconfig")
            print("\n【1】.查看所有网络接口的属性(ifconfig):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            stdin, stdout, stderr = ssh.exec_command("iptables -L")
            print("\n【2】查看防火墙设置(iptables -L):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            stdin, stdout, stderr = ssh.exec_command("route -n")
            print("\n【3】查看路由表(route -n):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            stdin, stdout, stderr = ssh.exec_command("netstat -ant")
            print("\n【3】查看所有已经建立的连接(netstat -ant):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        print("\n------------------------进程--------------------------------")

        try:
            stdin, stdout, stderr = ssh.exec_command("ps -ef")
            print("\n【1】.查看所有进程(ps -ef):")
            print(stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            stdin, stdout, stderr = ssh.exec_command("busybox top -n 1")
            print("\n【2】.实时显示进程状态(busybox top -n 1):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        print("\n------------------------串口--------------------------------")

        try:
            stdin, stdout, stderr = ssh.exec_command("ls -l /dev/ttyS*")
            print("\n【1】.查看串口名称使用(ls -l /dev/ttyS*):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

        try:
            stdin, stdout, stderr = ssh.exec_command("dmesg | grep ttyS*")
            print("\n【2】.查看串口设备(dmesg | grep ttyS*):\n%s" % stdout.read().decode("utf-8").strip())
        except Exception as e:
            print('异常:', e)

    except Exception as e:

        print("连接失败:", e)

    # 关闭ssh连接
    ssh.close()


if __name__ == '__main__':
    ip = "10.0.0.12"
    username = "root"
    password = "111111"
    port = 22
    test(ip, username, password, port)
posted @ 2023-01-17 21:46  厚礼蝎  阅读(171)  评论(0编辑  收藏  举报