paramiko 库的简单学习
paramiko,一个听起来不像英语的库,在诸多英文名的库中独立旗帜(官方解释为:”Paramiko” is a combination of the Esperanto words for “paranoid” and “friend”)。
它的主要功能就是实现对 ssh 协议的封装,能够在一个更高层面上,轻松地使用 ssh 以及 sftp 等功能。
一、安装
pip install paramiko
二、ssh 连接对象
1.使用密码连接
import paramiko
# 这行代码可以生成连接日志,大部分情况下不需要
# paramiko.util.log_to_file('/tmp/sshout')
ssh = paramiko.SSHClient()
#这行代码的作用是允许连接不在know_hosts文件中的主机。
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("IP", port, "username", "password")
2.使用秘钥连接
import paramiko
ssh = paramiko.SSHClient()
ssh.connect('10.120.48.109', port, '用户名', key_filename='私钥')
三、ssh 执行指令
成功连接主机后,可以使用 ssh.exec_command(cmd) 的方法执行指令。 但默认返回三个 paramiko.channelfile 对象,我们可以用以下的方法读取数据或者写入确认等。
stdin, stdout, stderr = ssh.exec_command(cmd)
# 如果成功,stdout会拿到输出的结果
for line in stdout.readlines():
print(line)
# 执行过程中,可以使用以下方法进行确认,但此时的确认是对指令操作过程中的指令,例如“确认删除”等
stdin.write('Y')
# 执行过程中若出现错误信息,报错信息会保存在stderr中
四、sftp 对象
paramiko 的 sftp 对象有多种生成方式。 倘若已有 ssh 对象,则:
- sftp = paramiko.SFTPClient.from_transport(ssh.get_transport())
- sftp = ssh.open_sftp() # 推荐,简单
倘若没有ssh对象,可以直接创建一个加密管道,开启传输。
scp = paramiko.Transport(('ip', port))
scp.connect(username='username', password='password')
sftp = paramiko.SFTPClient.from_transport(scp)
五、sftp 相关操作
当已经创建了 sftp 对象,查看对象拥有的方法,发现会有很多,并且做了一定的封装,例如 sftp.chown(),sftp.chmod() 等方法,这些方法其实可以通过 ssh.exec_command(cmd) 的方法实现,但在这里可以明显的感受到:ssh 对象面向的是主机,sftp 对象面向的是文件系统。 几个常见的操作:
- sftp.get(remotepath, localpath, callback=None) # 下载文件
- sftp.put(localpath, remotepath, callback=None, confirm=True) # 上传文件
- sftp.stat(path) # 查看文件状态
更多操作可见sftp对象的方法
六、利用 paramiko 实现 ssh 的交互式连接
这样可以让我们在执行 py 文件的时候,连接到远端主机的 shell,进行一定的操作,并且退出后脚本可以继续执行。 实现步骤:
- 连接远端主机
- 创建 tty
- 执行一些指令
- 退出
- 脚本继续运行
创建一个文件,叫做 interactive.py。
import socket
import sys
# windows does not have termios...
try:
import termios
import tty
has_termios = True
except ImportError:
has_termios = False
def interactive_shell(chan):
if has_termios:
posix_shell(chan)
else:
windows_shell(chan)
def posix_shell(chan):
import select
oldtty = termios.tcgetattr(sys.stdin)
try:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
chan.settimeout(0.0)
while True:
r, w, e = select.select([chan, sys.stdin], [], [])
if chan in r:
try:
x = chan.recv(1024)
if len(x) == 0:
print 'rn*** EOFrn',
break
sys.stdout.write(x)
sys.stdout.flush()
except socket.timeout:
pass
if sys.stdin in r:
x = sys.stdin.read(1)
if len(x) == 0:
break
chan.send(x)
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
# thanks to Mike Looijmans for this code
def windows_shell(chan):
import threading
sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.rnrn")
def writeall(sock):
while True:
data = sock.recv(256)
if not data:
sys.stdout.write('rn*** EOF ***rnrn')
sys.stdout.flush()
break
sys.stdout.write(data)
sys.stdout.flush()
writer = threading.Thread(target=writeall, args=(chan,))
writer.start()
try:
while True:
d = sys.stdin.read(1)
if not d:
break
chan.send(d)
except EOFError:
# user hit ^Z or F6
pass
主脚本 ssh_inter.py
# -*- coding:utf-8 -*-
import paramiko
import interactive
# 记录日志
paramiko.util.log_to_file('/tmp/test')
# 建立ssh连接
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(
'10.10.100.71',
port=22,
username='root',
password='cljslrl0620',
compress=True)
# 建立交互式shell连接
channel = ssh.invoke_shell()
# 建立交互式管道
interactive.interactive_shell(channel)
# 关闭连接
channel.close()
ssh.close()
终端执行 python ssh_inter.py,可以看到效果。
这一段感谢python模块paramiko与ssh。
同时需要注意,执行脚本的机器和远端机器的 shell 最好为一种 shell,例如 bash。
七、paramiko使用scp传输数据
众所周知,使用 paramiko 库进行远程文件传输,通常会使用 sftp 的方式进行。
我们又清楚,sftp 总体来说优于 scp,但特殊场景特殊对待,也许有些场景无法使用 sftp 进行传输。
博主在日常中遇到了一个报错信息,信息如下:
paramiko.ssh_exception.SSHException: EOF during negotiation
在这个问题下Paramiko’s open_sftp() to dropbear SSH server raising “EOF during negotiation” exception得到了答案。
So it looks like the dropbear does not support SFTP though SCP works fine.
那么就用 scp 传输文件吧,看了下 paramiko 的 api,没找到 scp 传输的接口。
在 GitHub 上找到了一个库jbardin/scp.py,项目的自述文件写道:这个 scp 模块通过 paramiko 的 transport ,并使用 scp1 协议去发送或接收文件。
具体的使用过程看 jbardin/scp.py的自述文件即可。