zoukankan      html  css  js  c++  java
  • python paramiko

    简介:
        paramiko 是 python 下对 ssh(v2) 协议封装的一个库, 可以用于实现客户端或者服务器端的一些功能。本章节主要讲述如何实现客户端功能

    安装:
        pip install paramiko

    常用组件:
        Channel 实现 ssh 通道建立和维护功能
        Client 实现 ssh 客户端功能
        SFTP 实现 sftp 功能
        Transport 实现 ssh 客户端和服务器端数据传输功能

    Client:

    Client 组件主要有以下几个 class:
        SSHClient           对 Transport 的高级封装, 实现了传输、通道、SFTP 等方法
    
        以下几个 class 实现 ssh 新主机密钥管理策略:
            AutoAddPolicy           自动添加主机名和秘钥到 HostKeys 对象(默认为 known_hosts)
            RejectPolicy            缺省值, 自动拒绝未知的主机和秘钥
            WarningPolicy           类似于 AutoAddPolicy 但会发出一个警告
    
    
    paramiko.client.SSHClient
        常用方法:
            load_system_host_keys()         # 加载 known_hosts 文件默认为 ~/.ssh/known_hosts
            set_missing_host_key_policy()   # 设置新主机和密码管理策略, 接受一个参数, 值可以是 AutoAddPolicy、RejectPolicy、WarningPolicy, 默认为 RejectPolicy
            connect()                       # 建立服务器和客户端之间的连接
                参数:
                    hostname                    # 远程主机的地址    
                    port=22                     # 远程主机 sshd 监听的端口, 默认 22
                    username=None               # 要进行身份验证的用户名(默认为当前系统用户的用户名)
                    password=None               # 用户名对应的密码, 使用秘钥登录时如果 passphrase 没有给定值而 password 给定了值时, password 将作为 key 的解密密码
                    passphrase=None             # ssh key 的解密密码
                    pkey=None                   # 指定 ssh 秘钥路径(如果该选项不为 None , 将启用 ssh 秘钥认证)
                    key_filename=None           # 尝试进行身份验证的可选秘钥文件或者文件列表
                    timeout=None                # TCP 连接超时时间
                    allow_agent=True            # 是否允许连接到 ssh 代理, 默认允许
                    look_for_keys=True          # 是否允许 paramiko 在当前系统的 ~/.ssh/ 中搜索秘钥用于尝试认证, 默认允许
                    compress=False              # 是否打开压缩 
                    banner_timeout=None         # 等待显示 ssh 标题的超时时间
                    auth_timeout=None           # 等待身份认证的超时时间
            
            exec_command()                  # 执行远程命令
                参数:
                    command                     # 执行指定的 shell 命令
                    timeout                     # 设置命令超时时间
                    environment                 # 设置 shell 环境变量, 字典类型
    
                返回值:
                    stdint                      # 标准输入
                    stdout                      # 标准输出
                    stderr                      # 标准错误
    
            get_transport()                 # 获取底层的 transport 对象, 用于执行低级的任务
                返回值:
                    返回 Transport 对象
    
            invoke_shell()                  # 打开一个 ssh 交互式会话
                参数:
                    term                        # 模拟终端的类型
                    width                       # 终端窗口的宽度(以字符为单位)
                    height                      # 终端窗口的高度(以字符为单位)
                    width_pixels                # 终端窗口的宽度(以像素为单位)
                    height_pixels               # 终端窗口的高度(以像素为单位)
                    environment                 # 设置 shell 环境变量, 字典类型
            
            open_sftp()                     # 向 ssh 服务器申请打开 sftp
    
            close()                         # 断开和服务器的连接
    
        异常:  
            BadHostKeyException        无法验证服务器的主机密钥
            AuthenticationException    认证失败
            SSHException               连接或建立 SSH 会话时出现任何其他错误	
            socket.error               连接时发生套接字错误
    

      

    Client 示例:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Author  : HuYuan
    # @File    : paramiko_ssh_client.py
    
    import paramiko
    
    class UseSSHClient:
        def __init__(self, hostname, username, port=22, password=None, pkey=None, timeout=30, passphrase=None):
            self.hostname = hostname
            self.username = username
            self.port = port
            self.password = password
            self.pkey = pkey
            self.timeout = timeout
            self.passphrase = passphrase
    
            self._open_ssh()
    		
    	def get_key_obj(self, pkeyobj, pkey_file=None, pkey_obj=None, password=None):
    		if pkey_file:
    			with open(pkey_file) as fo:
    				try:
    					pkey = pkeyobj.from_private_key(fo, password=password)
    					return pkey
    				except:
    					pass
    		else:
    			try:
    				pkey = pkeyobj.from_private_key(pkey_obj, password=password)
    				return pkey
    			except:
    				pkey_obj.seek(0)
    
        def _open_ssh(self):
            sshclient = paramiko.client.SSHClient()
            sshclient.set_missing_host_key_policy(paramiko.client.AutoAddPolicy)
            if self.password:
                sshclient.connect(hostname=self.hostname, username=self.username, port=self.port,
                                  password=self.password, timeout=self.timeout)
            else:
                # 解析 key
    			pkey = get_key_obj(paramiko.RSAKey, pkey_file=self.pkey) or 
    			       get_key_obj(paramiko.DSSKey, pkey_file=self.pkey) or 
    			       get_key_obj(paramiko.ECDSAKey, pkey_file=self.pkey) or 
    			       get_key_obj(paramiko.Ed25519Key, pkey_file=self.pkey)
    				   
                sshclient.connect(hostname=self.hostname, username=self.username, pkey=pkey,
                                  port=self.port, timeout=self.timeout)
    
            self.ssh = sshclient
    
        def exec_comd(self, cmd):
            result = self.ssh.exec_command(cmd)
            return result
    
        def sftp_get(self, server_path, local_path):
            sftp = self.ssh.open_sftp()
            sftp.get(server_path, local_path)
    
        def sftp_put(self, server_path, local_path):
            sftp = self.ssh.open_sftp()
            sftp.put(local_path, server_path)
    
        def close(self):
            self.ssh.close()
    
    
    if __name__ == '__main__':
        hostname = '192.168.1.100'
        username = 'root'
        password = '123.com'
    
        sshClient = UseSSHClient(hostname=hostname, username=username, password=password)
    
        sshClient.sftp_get('/etc/fstab', 'fstab')
        sshClient.sftp_put('/tmp/fstab', 'fstab')
    
        stdin, stdout, stderr = sshClient.exec_comd('ls /tmp/fstab')
        print(stdout.read())
    
        sshClient.close()
    

      

    pkey 对象:

    paramiko 目前支持 4 总 key 认证, 分别为:
        RSAKey     --> rsa     加密 --> 实现 class  paramiko.rsakey.RSAKey
        DSSKey     --> dsa     加密 --> 实现 class  paramiko.dsskey.DSSKey
        ECDSAKey   --> ecdsa   加密 --> 实现 class  paramiko.ecdsakey.ECDSAKey
        Ed25519Key --> ed25519 加密 --> 实现 class  paramiko.ed25519key.Ed25519Key
    
    他们拥有相同的方法和属性:
        from_private_key()                  # 从文件(或类文件) 对象中读取私钥来创建密钥对象
            参数:
                file_obj                        # 文件或类文件对象
                password=None                   # 如果 password 不为 None, 则 password 值作为私钥的解密密码
    
            返回值:
                返回密钥对象, 传递给类似 connect() 的参数, 进行身份验证
    
        from_private_key_file()             # 从文件中读取私钥来创建密钥对象
            参数:
                filename                        # 密钥文件
                password=None                   # 如果 password 不为 None, 则 password 值作为私钥的解密密码
    
            返回值:
                返回密钥对象, 传递给类似 connect() 的参数, 进行身份验证
    
        write_private_key()                 # 将私钥内容写入文件(或类文件)对象
            参数:
                file_obj                        # 文件或类文件对象
                password=None                   # 如果 password 不为 None, 则在写入之前使用 password 指定的密码对密钥进行加密
    
        write_private_key_file()            # 将私钥内容写入文件
            参数:
                filename                        # 密钥文件
                password=None                   # 如果 password 不为 None, 则在写入之前使用 password 指定的密码对密钥进行加密
    
        get_name()                          # 获取密钥文件的名称
    
        get_base64()                        # 获取密钥公共部分的 base64 字符串
    
        get_bits()                          # 返回此键中的有效位数, 这对于判断密钥的相对安全性很有用
    
        get_fingerprint()                   # 获取密钥公共部分的 MD5 指纹
    

      

    SFTP:

    组件:
        paramiko.sftp_client.SFTPClient      用于实现 sftp client 功能
        paramiko.sftp_client.SFTP            SFTPClient 用于向后兼容的别名
    
    
    常用方法:
        from_transport()                    # 从 Transport 对象中打开 sftp 会话
    
        put()                               # 上传文件
            参数:
                remotepath                      # 远程路径
                localpath                       # 本地路径
                callback                        # 回掉函数,获取已接收的字节数和总字节数
                confirm                         # 文件传输完成之后是否调用stat()函数 以确认文件大小,默认为True
    
        get()                               # 下载文件
            参数:
                remotepath                      # 远程路径
                localpath                       # 本地路径
                callback                        # 回掉函数,获取已接收的字节数和总字节数
    
        getfo()                             # 下载文件, 本地打开一个文件句柄用于写入远程服务的数据
            参数:
                remotepath                      # 远程路径
                fl                              # 本地文件句柄
                callback
    
        putfo()                             # 上传文件, 参数类似于 getfo() 
    
        getcwd()                            # 获取当前 sftp 会话所在目录
    
        listdir()                           # 列出指定路径下的所有文件目录列表(包括以隐藏文件), 默认 sftp 会话所在目录
            参数:
                path                            # 指定远程路径
    
        listdir_attr()                      # 以类似于 ls -l 的格式列出指定路径下的所有文件目录列表(包括以隐藏文件), 默认 sftp 会话所在目录
            参数:
                path                            # 指定远程路径
    
        mkdir()                             # 在远程服务器上创建目录
            参数:
                path                            # 要创建的目录路径和名称
                mode                            # 目录权限, 数字格式, 默认为 o777
        
        open()                              # 在远程服务器上打开文件, 参数和 python 的 open() 函数相同
    
        readlink()                          # 返回符号链接的原始路径
            参数:
                path                            # 指定符号链接
    
        symlink()                           # 创建符号链接
            参数:
                source                          # 符号链接的原始路径
                dest                            # 符号链接的目标路径
    
        remove()                            # 删除指定的文件(不能对目录进行删除)
            参数:
                path                            # 指定需要删除的文件
    
        rmdir()                             # 删除指定目录, 参数和 remove() 相同
    
        rename()                            # 重命名文件或目录
            参数:
                oldpath                         # 指定需要重命名的文件
                newpath                         # 重命名之后的名称
    
        stat()                              # 检查远程系统上的指定文件的信息
            参数:
                path                            # 需要检查的文件
    
        utime()                             # 修改文件的 atime 和 mtime
            参数:
                path                            # 指定的文件
                times                           # 修改后的时间元组, 格式 (atime, mtime)
    

      

    Channel:

    paramiko.channel.Channel            对 paramiko 的底层 class 之一, 实现通道建立和维护等功能 
    
    常用方法:
        exec_command()                      # 在远程服务器上执行命令
    
        fileno()                            # 返回 OS 级文件描述符, 可用于轮询, 但不能用于读取或写入, 这主要是为了让 Python 的 select 模块能够工作(此方法将导致 Channel 读取效率降低)
        
        get_id()                            # 获取通道 ID
    
        set_name()                          # 设置通道名称
    
        get_name()                          # 获取通道名称
    
        get_pty()                           # 向服务器请求一个 pty 终端
            参数:
                term="vt100"                    # 终端类型
                width                           # 终端窗口的宽度(以字符为单位)
                height                          # 终端窗口的高度(以字符为单位)
                width_pixels                    # 终端窗口的宽度(以像素为单位)
                height_pixels                   # 终端窗口的高度(以像素为单位)
    
        get_transport()                       # 获取底层的 transport 对象, 用于执行低级的任务
        getpeername()                         # 获取服务器地址
    
        settimeout()                          # 设置通道超时时间
        gettimeout()                          # 查看通道超时时间
    
        invoke_shell()                      # 在此 channel 上请求交互式 shell 会话(通常会和 get_pty() 一起使用)
    
        invoke_subsystem()                  # 请求服务器上的子系统
            参数:
                subsystem                       # 子系统的名称, 比如: sftp
    
        recv()                                  # 接收远程服务器返回的数据
            参数:           
                nbytes                          # 设置一次获取的最大字节数
    
        recv_exit_status()                      # 获取服务上进程返回的退出状态, 在使用 exec_command 执行命令获取返回值时有用
    
        request_forward_agent()             # 请求转发 ssh 代理
    
        request_x11()                       # 请求 x11 会话
    
        resize_pty()                        # 重新设置 pty 的大小, 用于更改 get_pty() 设置的大小
            参数:
                width                           # 终端窗口的宽度(以字符为单位)
                height                          # 终端窗口的高度(以字符为单位)
                width_pixels                    # 终端窗口的宽度(以像素为单位)
                height_pixels                   # 终端窗口的高度(以像素为单位)
    
    
        send()                              # 向服务器发送数据, 检查数据是否发送完毕, 如果仅传输了部分数据, 则尝试传送剩余数据
            参数:
                s                               # 要发送的数据
    
        sendall()                           # 向服务器发送数据, 直到所有数据都已发送或发生错误
            参数:
                s                               # 要发送的数据
    
        set_environment_variable()          # 设置环境变量 
            参数:
                name                            # 变量名
                value                           # 变量值
    
        update_environment()                # 更新环境变量
            参数:
                environment                     # 需要更新的环境变量的值, 类型为 dict
    
    
        setblocking()                       # 设置通道的阻塞模式:
            参数:
                blocking                        # 如果 blocking 为 0, 则将通道设置为非阻塞模式; 否则设置为阻止模式, 默认为阻塞模式
    
        settimeout()                        # 设置阻塞读写的超时时间, 如果 setblocking() 设置为 0, 那么相当于 settimeout(0)
            参数:
                timeout                         # 超时时间
    
        shutdown()                          # 关闭通道
            how                                 # 怎么样关闭通道, 0: 停止接收数据、1: 停止发送数据、2: 停止接收和发送数据
    
        shutdown_read()                     # shutdown(0) 的简写
        shutdown_write()                    # shutdown(1) 的简写
    
        close()                             # 断开和服务器的连接
    

      

    Transport:

    paramiko.transport.Transport        paramiko 的核心主件, 实现了一系列对 ssh 底层的操作
    
    常用方法:
        connect()                           # 协商会话, 并可选的进行身份认证
            参数: 
                username=""                     # 要进行身份验证的用户名
                password=None                   # 用户名对应的密码
                pkey=None                       # 使用秘钥认证
    
        # 如果 connect() 方法只是进行了会话协商而没有进行身份验证时, 则可以使用以下方法进行身份验证
            auth_password()                 # 使用密码认证
                参数:
                    username                    # 进行身份验证的用户
                    password                    # 用户密码
    
            auth_publickey()                # 使用秘钥认证
                参数:
                    username                    # 进行身份验证的用户
                    key                         # 用户秘钥
    
            auth_none()                     # 尝试使用空密码登录, 由于 Linux 的密码策略所以该方法几乎都是失败
                参数:
                    username                    # 用户名
    
        close()                             # 断开和服务器的连接
    
        get_username()                      # 获取登录用户的用户名
        
        getpeername()                       # 获取服务器地址
    
        is_active()                         # 如果当前会话处于活动状态则返回 True, 反之则返回 false
    
        is_authenticated()                  # 如果当前会话处于活动状态且已通过身份验证则返回 True, 反之则返回 false
    
        open_channel()                      # 向服务器请求打开新的 channel
            参数:
                kind                        # 打开通道的类型(session, forwarded-tcpip, direct-tcpip, x11)
                dest_addr=None              # 端口转发的目标地址(ip, port), 只有当通道类型为 forwarded-tcpip 和 direct-tcpip 时生效
                src_addr=None               # 端口转发的源地址, 只有当通道类型为 forwarded-tcpip、direct-tcpip 或 x11 时生效
                window_size=None            # 会话的窗口大小
                max_packet_size=None        # 此会话的最大数据包大小
                timeout=None                # 打开通道的超时时间, 默认问 1h
    
        open_forwarded_tcpip_channel()      # open_channel() forwarded-tcpip 的简写
        open_session()                      # open_channel() session 的简写
        open_x11_channel()                  # open_channel() x11 的简写
    
        open_sftp_client()                  # 打开 sftp 通道
    
        set_keepalive()                     # 打开/关闭 keepalive 数据包(默认为关闭), 如果设置了此值, 在 interval 指定的时间内没有数据传输将发送 keepalive 数据包
            参数:
                interval                        # 指定多长时间没有数据传输后开始发送 keepalive
    
        use_compression()                   # 打开或关闭压缩, 建议关闭, 因为它会对交互式会话产生负面影响
            参数:
                compress                    # 是否打开压缩, true/false
    

      

    Transport 示例:

    import paramiko
    
    hostname = '192.168.1.100'
    username = 'root'
    password = '123.com'
    port = 22
    transport = paramiko.transport.Transport(sock=(hostname, port))
    transport.connect()
    transport.auth_password('root','123.com')
    sftp = transport.open_sftp_client()
    sftp.get('/etc/fstab', 'fstab-transport')
    

      

    示例: 实现 ssh 客户端(只能在 Linux 下运行)

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Author  : HuYuan
    # @File    : python_shell.py
    
    import paramiko
    import sys
    import socket
    import termios
    import tty
    import select
    
    
    def posix_shell(chan):
        local_tty = termios.tcgetattr(sys.stdin)
        try:
            tty.setraw(sys.stdin.fileno())
            tty.setcbreak(sys.stdin.fileno())
            chan.settimeout(0.0)
            while True:
                read, write, error = select.select([chan, sys.stdin], [], [])
                if chan in read:
                    try:
                        recv = chan.recv(1024)
                        if not len(recv):
                            break
                        sys.stdout.write(recv.decode())
                        sys.stdout.flush()
                    except socket.timeout:
                        pass
    
                if sys.stdin in read:
                    content = sys.stdin.read(1)
                    if not len(content):
                        break
    
                    chan.send(content)
        finally:
            termios.tcsetattr(sys.stdin, termios.TCSADRAIN, local_tty)
    
    
    def open_ssh_client():
        hostname = '192.168.1.100'
        username = 'root'
        password = '123.com'
        port = 22
    
        try:
            ssh_client = paramiko.client.SSHClient()
            ssh_client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
            ssh_client.connect(hostname=hostname, username=username, password=password, port=port, timeout=10)
            tran = ssh_client.get_transport()
            chan = tran.open_session()
            chan.get_pty()
            chan.invoke_shell()
            posix_shell(chan)
            tran.close()
    
        except socket.timeout as e:
            print('连接超时', e)
            exit(10)
    
        except Exception as e:
            print(e)
    
    
    if __name__ == '__main__':
        open_ssh_client()
    

      

    相关项目:

    django + paramiko + websocket 实现 webssh:
    项目地址: https://github.com/huyuan1999/django-webssh
    

      

  • 相关阅读:
    系统调用与库函数
    在树莓派上 搭建sqlite数据库
    (转)inux Read系统调用
    查看当前日期是这一年的第几天
    求解某个范围内的全部完数
    求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字。
    输入三个整数x,y,z,请把这三个数据由大到小输出。
    模仿ArrayList底层实现
    可视化日历
    Oracle之约束条件1:主键约束
  • 原文地址:https://www.cnblogs.com/huyuanblog/p/10155933.html
Copyright © 2011-2022 走看看