paramiko 库的简单学习

2019/01/21 Python Python模块

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,进行一定的操作,并且退出后脚本可以继续执行。 实现步骤:

  1. 连接远端主机
  2. 创建 tty
  3. 执行一些指令
  4. 退出
  5. 脚本继续运行

创建一个文件,叫做 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的自述文件即可。

八、更多

Search

    Table of Contents