介绍
paramiko 是一个基于 SSH 用于连接远程服务器并执行相关操作 (SSHClient 和 SFTPClinet, 即一个是远程连接, 一个是上传下载服务), 使用该模块可以对远程服务器进行命令或文件操作, 值得一说的是, fabric 和 ansible 内部的远程管理就是使用的 paramiko 来现实
安装
Paramiko 模块内部依赖 pycrypto, 所以先下载安装 pycrypto, 再安装 Paramiko
模块使用
SSHClient:
远程连接分为两种:(1) 基于用户名密码连接 (2) 基于公钥秘钥连接
通过是用 paramiko 远程操作, 其实本质也分为两种:(1) 只用 SSHClient (2) 自己创建一个 transport
(1) 基于用户名和密码的 sshclient 连接
- import paramiko
- # 创建一个 sshclient 对象
- ssh=paramiko.SSHClient()
- # 将要连接的主机加入到 host_allow 信任列表, 此方法必须放在 connect 方法的前面
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- # 调用 connect 方法连接服务器
- ssh.connect(hostname=192.168.2.129, port=22, username=super, password=super)
- # 执行命令
- stdin, stdout, stderr = ssh.exec_command(df -hl)
- # 结果放到 stdout 中, 如果有错误将放到 stderr 中
- print (str(stdout.read(),encoding=utf-8))
- ssh.close()
基于用户名和密码的 transport 连接
上面的方法是传统的连接服务器执行命令关闭的一个操作, 有时候需要登录上服务器执行多个操作, 比如执行命令上传 / 下载文件, 方法 1 则无法实现, 可以通过如下方式来操作
- # 实例化一个 transport 对象
- trans = paramiko.Transport((192.168.2.129, 22))
- # 建立连接
- trans.connect(username=super, password=super)
- # 将 sshclient 的对象的 transport 指定为以上的 trans
- ssh = paramiko.SSHClient()
- ssh._transport = trans
- # 执行命令, 和传统方法一样
- stdin, stdout, stderr = ssh.exec_command(df -hl)
- print(stdout.read().decode())
- # 关闭连接
- trans.close()
(2) 基于秘钥 sshclient 连接
- # 指定本地的 RSA 私钥文件, 如果建立密钥对时设置的有密码, password 为设定的密码, 如无不用指定 password 参数
- pkey = paramiko.RSAKey.from_private_key_file(/home/super/.ssh/id_rsa, password=12345)
- # 建立连接
- ssh = paramiko.SSHClient()
- ssh.connect(hostname=192.168.2.129,
- port=22,
- username=super,
- pkey=pkey)
- # 执行命令
- stdin, stdout, stderr = ssh.exec_command(df -hl)
- # 结果放到 stdout 中, 如果有错误将放到 stderr 中
- print(stdout.read().decode())
- # 关闭连接
- ssh.close()
以上需要确保被访问的服务器对应用户. ssh 目录下有 authorized_keys 文件, 也就是将服务器上生成的公钥文件保存为 authorized_keys 并将私钥文件作为 paramiko 的登陆密钥
基于秘钥 transport 连接
- # 指定本地的 RSA 私钥文件, 如果建立密钥对时设置的有密码, password 为设定的密码, 如无不用指定 password 参数
- pkey = paramiko.RSAKey.from_private_key_file(/home/super/.ssh/id_rsa, password=12345)
- # 建立连接
- trans = paramiko.Transport((192.168.2.129, 22))
- trans.connect(username=super, pkey=pkey)
- # 将 sshclient 的对象的 transport 指定为以上的 trans
- ssh = paramiko.SSHClient()
- ssh._transport = trans
- # 执行命令, 和传统方法一样
- stdin, stdout, stderr = ssh.exec_command(df -hl)
- print(stdout.read().decode())
- # 关闭连接
- trans.close()
(3) 文件上传
- # 实例化一个 trans 对象# 实例化一个 transport 对象
- trans = paramiko.Transport((192.168.2.129, 22))
- # 建立连接
- trans.connect(username=super, password=super)
- # 实例化一个 sftp 对象, 指定连接的通道
- sftp = paramiko.SFTPClient.from_transport(trans)
- # 发送文件
- sftp.put(localpath=/tmp/11.txt, remotepath=/tmp/22.txt)
- # 下载文件
- # sftp.get(remotepath, localpath)
- trans.close()
实现输入命令立马返回结果的功能
以上操作都是基本的连接, 如果我们想实现一个类似 xshell 工具的功能, 登录以后可以输入命令回车后就返回结果:
- import paramiko
- import os
- import select
- import sys
- # 建立一个 socket
- trans = paramiko.Transport((192.168.2.129, 22))
- # 启动一个客户端
- trans.start_client()
- # 如果使用 rsa 密钥登录的话
- default_key_file = os.path.join(os.environ[HOME], .ssh, id_rsa)
- prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
- trans.auth_publickey(username=super, key=prikey)
- # 如果使用用户名和密码登录
- trans.auth_password(username=super, password=super)
- # 打开一个通道
- channel = trans.open_session()
- # 获取终端
- channel.get_pty()
- # 激活终端, 这样就可以登录到终端了, 就和我们用类似于 xshell 登录系统一样
- channel.invoke_shell()
- # 下面就可以执行你所有的操作, 用 select 实现
- # 对输入终端 sys.stdin 和 通道进行监控,
- # 当用户在终端输入命令后, 将命令交给 channel 通道, 这个时候 sys.stdin 就发生变化, select 就可以感知
- # channel 的发送命令获取结果过程其实就是一个 socket 的发送和接受信息的过程
- while True:
- readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
- # 如果是用户输入命令了, sys.stdin 发生变化
- if sys.stdin in readlist:
- # 获取输入的内容
- input_cmd = sys.stdin.read(1)
- # 将命令发送给服务器
- channel.sendall(input_cmd)
- # 服务器返回了结果, channel 通道接受到结果, 发生变化 select 感知到
- if channel in readlist:
- # 获取结果
- result = channel.recv(1024)
- # 断开连接后退出
- if len(result) == 0:
- print("\r\n**** EOF **** \r\n")
- break
- # 输出到屏幕
- sys.stdout.write(result.decode())
- sys.stdout.flush()
- # 关闭通道
- channel.close()
- # 关闭链接
- trans.close()
- View Code
支持 tab 自动补全
- import paramiko
- import os
- import select
- import sys
- import tty
- import termios
实现一个 xshell 登录系统的效果, 登录到系统就不断输入命令同时返回结果
支持自动补全, 直接调用服务器终端
- # 建立一个 socket
- trans = paramiko.Transport((192.168.2.129, 22))
- # 启动一个客户端
- trans.start_client()
- # 如果使用 rsa 密钥登录的话
- default_key_file = os.path.join(os.environ[HOME], .ssh, id_rsa)
- prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
- trans.auth_publickey(username=super, key=prikey)
- # 如果使用用户名和密码登录
- trans.auth_password(username=super, password=super)
- # 打开一个通道
- channel = trans.open_session()
- # 获取终端
- channel.get_pty()
- # 激活终端, 这样就可以登录到终端了, 就和我们用类似于 xshell 登录系统一样
- channel.invoke_shell()
- # 获取原操作终端属性
- oldtty = termios.tcgetattr(sys.stdin)
- try:
- # 将现在的操作终端属性设置为服务器上的原生终端属性, 可以支持 tab 了
- tty.setraw(sys.stdin)
- channel.settimeout(0)
- while True:
- readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
- # 如果是用户输入命令了, sys.stdin 发生变化
- if sys.stdin in readlist:
- # 获取输入的内容, 输入一个字符发送 1 个字符
- input_cmd = sys.stdin.read(1)
- # 将命令发送给服务器
- channel.sendall(input_cmd)
- # 服务器返回了结果, channel 通道接受到结果, 发生变化 select 感知到
- if channel in readlist:
- # 获取结果
- result = channel.recv(1024)
- # 断开连接后退出
- if len(result) == 0:
- print("\r\n**** EOF **** \r\n")
- break
- # 输出到屏幕
- sys.stdout.write(result.decode())
- sys.stdout.flush()
- finally:
- # 执行完后将现在的终端属性恢复为原操作终端属性
- termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
- # 关闭通道
- channel.close()
- # 关闭链接
- trans.close()
- View Code
来源: http://www.bubuko.com/infodetail-2490250.html