• Python之paramiko


    一、基础

    paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。paramiko支持Linux, Solaris, BSD, MacOS X, Windows等平台通过SSH从一个平台连接到另外一个平台。利用该模块,可以方便的进行ssh连接和sftp协议进行sftp文件传输

    1、SSHClient类

    SSHClient类是SSH服务会话的高级表示,封装了传输、通道以及SFTPClient的校验、建立方法,通常用于执行命令。
    1)connect方法
    connect(self,hostname,port=22,username=None,password=None,pkey=None,key_filename=None,timeout=None,allow_agent=True,look_for_keys=True,compress=False)
    参数说明:
    hostname:连接目标的主机地址
    port:连接目录的端口,默认为22
    username:用户名
    password:密码
    pkey:私钥方式用户验证
    key_filename:私钥文件名
    timeout:连接超时时间
    allow_agent:是否允许使用ssh代理
    look_for_keys:是否允许搜索私钥文件
    compress:打开时是否压缩
    2)exec_command方法
    exec_command(self,command,bufsize=-1)
    参数说明:
    command:执行的的指令
    bufsize:文件缓冲区大小,-1不限制
    3)load_system_host_keys方法
    load_system_host_keys(self,filename=None)
    参数说明:
    filename:指定远程主机的公钥文件,默认为.ssh目录下的known_hosts文件
    4)set_missing_host_key_policy方法
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    参数说明:
    AutoAddPolicy:自动添加主机名及密钥到本地并保存,不依赖load_system_host_keys()配置,即如果known_hosts里没有远程主机的公钥时,默认连接会提示yes/no,自动yes
    RejectPolicy:自动拒绝未知主机名和密钥,依赖load_system_host_keys()
    WarnningPlicy:功能与AutoAddPolicy相同,但是未知主机会提示yes/no

    2、SFTPClient类

    根据SSH传输协议的sftp会话,实现远程文件上传、下载等操作。
    1)from_transport方法
    classmethod from_transport(cls,t)
    参数说明:
    t:一个已通过验证的传输对象

    示例:

    >>> import paramiko
    >>> a = paramiko.Transport((“127.0.0.1″,2222))
    >>> a.connect(username=”root”, password=’123456′)
    >>> sftp = paramiko.SFTPClient.from_transport(a)
    2) put方法
    put(self,localpath,remotepath,callback=None,confirm=True)
    参数说明:
    localpath:上传源文件的本地路径
    remotepath:目标路径
    callback:获取接收与总传输字节数
    confirm:上传完毕后是否调用stat()方法,以便确认文件大小

    示例:

    >>> localpath=’ftp-test.log’
    >>> remotepath=’/data/ftp-test.log’
    >>> sftp.put(localpath,remotepath)
    3)get方法
    get(self, remotepath, localpath, callback=None)
    参数说明:
    remotepath:需要下载的远程文件
    localpath:本地存储路径
    callback:同put方法
    4)其他方法
    mkdir:用于创建目录
    remove:删除目录
    rename:重命名
    stat:获取文件信息
    listdir:获取目录列表
    代码示例
    Paramiko ssh客户端:
    # coding:utf-8
    
    import paramiko
    
    import os,sys
    
    ssh_host = sys.argv[1]
    ssh_port = 22
    user = 'root'
    password = 'root1234'
    cmd = sys.argv[2]
    paramiko.util.log_to_file = 'paramiko.log'
    
    s = paramiko.SSHClient()
    s.load_system_host_keys()
    s.set_missing_host_key_policy(paramiko.AutoAddPolicy)
    s.connect(ssh_host,ssh_port,user,password,timeout=5)
    stdin,stdout,stderr = s.exec_command(cmd)
    cmd_result = stdout.read(),stderr.read()
    for line in cmd_result:
        print line
    s.close()
    使用ssh密钥连接:
    # coding:utf-8
    
    import paramiko
    
    import os,sys
    
    ssh_host = sys.argv[1]
    ssh_port = 22
    user = 'root'
    password = 'root1234'
    cmd = sys.argv[2]
    paramiko.util.log_to_file = 'paramiko.log'
    
    s = paramiko.SSHClient()
    s.load_system_host_keys()
    s.set_missing_host_key_policy(paramiko.AutoAddPolicy)
    
    
    # s.connect(ssh_host,ssh_port,user,password,timeout=5)
    pkey_file = '/root/.ssh/id_rsa'
    key = paramiko.RSAKey.from_private_key_file(pkey_file)
    s.connect(ssh_host,ssh_port,user,pkey=key,timeout=5)
    
    
    stdin,stdout,stderr = s.exec_command(cmd)
    cmd_result = stdout.read(),stderr.read()
    for line in cmd_result:
        print line
    s.close()
    Paramiko SFTP传送文件:
    #!/usr/bin/python
    import os,sys
    import paramiko
    host = sys.argv[1]
    rfilename = sys.argv[2]
    lfilename = os.path.basename(rfilename)
    user = 'root'
    password = 'xxxx'
    paramiko.util.log_to_file('/tmp/test') 
    t = paramiko.Transport((host,22))
    t.connect(username=user,password=password)
    sftp = paramiko.SFTPClient.from_transport(t)
    sftp.get(rfilename,lfilename)
    #sftp.put('paramiko1.py','/tmp/paramiko1.py')
    t.close()
    使用interactive模块实现SSH交互:
    interactive.py模块内容如下
    #!/usr/bin/python
    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 '
    *** EOF
    ',
    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.
    
    ")         
    def writeall(sock):
    while True:
                data = sock.recv(256)
    if not data:
                    sys.stdout.write('
    *** EOF ***
    
    ')
                    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
    View Code
    inter_ssh.py交互脚本如下:
    #!/usr/bin/python
    #_*_coding:utf8_*_
    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('192.168.128.82',port=22,username='root',password='cheyian')
    #建立交互式shell连接
    channel=ssh.invoke_shell()
    #建立交互式管道
    interactive.interactive_shell(channel)
    #关闭连接
    channel.close()
    ssh.close()
    View Code

     小结:

    paramiko模块是一个比较强大的ssh连接模块,以上的示例只是列出了该模块的一些简单的使用方法,还可以使用threading模块加块程序并发的速度;也可以使用configparser模块处理配置文件,而我们将所有IP、用户信息操作都放入配置文件;使用setproctitle模块为执行的程序加一个容易区分的title等。

    同样,虽然连fabric这样大名鼎鼎的软件使用的ssh都是用paramiko模块进行的封装,不过你依然可以选择不使用它,你也可以选择pexpect模块实现封装一个简易的ssh连接工具、或者使用同样比较火的salt-ssh模块。

    二、应用

    基于用户名和密码的 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()

    基于密钥的 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()

     传文件 SFTP

    # 实例化一个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("
    **** EOF **** 
    ")
                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("
    **** EOF **** 
    ")
                    break
                # 输出到屏幕
                sys.stdout.write(result.decode())
                sys.stdout.flush()
    finally:
        # 执行完后将现在的终端属性恢复为原操作终端属性
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
    
    # 关闭通道
    channel.close()
    # 关闭链接
    trans.close()
    View Code
  • 相关阅读:
    python初识面向对象
    python装饰器
    python递归函数及二分法查找
    python内置函数及匿名函数
    生成器和生成器函数以及各种推导式
    第一类对象 函数名 变量名
    初识函数
    文件操作
    基本数据类型补充 深浅拷贝
    Python小程序练习及认识小数据池和编码
  • 原文地址:https://www.cnblogs.com/wanstack/p/7569299.html
Copyright © 2020-2023  润新知