zoukankan      html  css  js  c++  java
  • Python模块之paramiko

    一、简介

    paramiko是基于实现SSH2远程安全连接,支持认证及密钥方式。可以实现远程命令执行、文件传输、中间SSH代理等功能,相对于Pexpect,封装的层次更高,更贴近SSH协议的功能

    二、安装

    #pip方式安装
    pip install paramiko

    三、简单示例

    import paramiko
    
    hostname='172.17.9.68'
    username='root'
    password='xxxx'
    paramiko.util.log_to_file('login.log')  #发送paramiko日志到login.log文件,没有太大可读性
    
    ssh=paramiko.SSHClient()    #创建ssh客户端client对象
    # ssh.load_system_host_keys()   #首次登录无法找到hosts_keys,会报错,默认在~/.ssh/know_hosts,非默认需指定路径,
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())   #以下标题4.4会讲解
    ssh.connect(hostname=hostname,username=username,password=password)#创建ssh连接
    stdin,stdout,stderr=ssh.exec_command('ps -ef')  #调用远程执行命令方法exec_command()
    print(stdout.read().decode('utf-8'))    #read()得到的内容是Bytes字节,需要解码成utf-8
    ssh.close() #关闭ssh连接
    

      3.2 执行多条命令

    import paramiko
    hostname = '172.26.1.8'
    port = 22
    username = ''
    password = ''
    excute_cmds_list = ['dis cu ','dis ip int brief']
    
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
    ssh.connect(hostname=hostname, port=port, username=username, password=password)
    
    #将要执行的多条命令以
    间隔即可
    command = '
    '.join(excute_cmds_list)
    
    stdin, stdout, stderr = ssh.exec_command(command)
    content = stdout.read().decode('utf-8') + stderr.read().decode('utf-8')
    print(content)

    四、SSHClient类

      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(str类型):连接的目标主机地址
    port(int类型):连接目标主机的端口,默认是22
    username(str类型):校验的用户名(默认为当前的本地用户名)
    password(str类型):密码用于身份校验或解锁私钥
    pkey(PKey类型):私钥方式用于身份验证
    key_filename(str o list(str)类型):一个文件名或文件名的列表,用于私钥的身份验证
    timeout(float类型):一个可选的超时时间(已秒为单位)的TCP连接
    allow_agent(bool类型):设置为False时用于禁用连接到SSH代理
    look_for_keys(bool类型):设置为False时用来禁用在~/.ssh中搜索秘钥文件
    compress(bool类型):设置为True时打开压缩

      2.exec_command方法

    #方法定义
    exec_command(self,command,bufsize=-1)
    
    #参数说明
    command(str类型):执行的命令
    bufsize(int类型):文件缓冲区的大小,默认-1(不限制)
    
    #用处
    远程命名执行方法,分别返回stdin,stdout,stderr

      3.load_system_host_keys方法

    #方法定义
    load_system_host_keys(self,filename=None)
    
    #参数说明
    filename(str类型):指定远程主机公钥记录文件
    
    #用处
    加载本地公钥校验文件,默认为~/.ssh/known_hosts,非默认路径需要手工指定

      4.set_missing_host_key_policy方法

    ssh.set_missing_host_key_policy方法
    针对连接的远程主机没有本地主机密钥或Host_keys对象时的策略。
    目前支持三种参数AutoAddPolicy、RejectPolicy(默认)、WarningPolicy,仅限用于SSHClient类
    1.AutoAddPolicy:自动添加主机名及主机密钥到本地Host_Keys对象,不依赖load_system_host_keys()的配置,
    即使~/.ssh/known_hosts不存在也不产生影响
    2.RejectPolicy:自动拒绝未知的主机名和密钥,依赖load_system_host_keys()的配置
    3.WarningPolicy:用于记录一个未知的主机密钥的Python警告,并接受它,功能上与AutoAddPolicy相似,
    但未知主机会有告警

    ssh=paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    五、SFTPClient类

       5.1简介

    SFTPClient作为一个SFTP客户端对象,根据SSH传输协议的sftp会话,实现远程操作,比如文件上传,下载,权限,状态等,端口就是SSH端口

      5.2 from_transport方法

    #方法定义
    from_transport(cls,t)
    
    #参数
    t(Transport),一个已通过验证的传输对象
    
    #应用
    t=paramiko.Transport(("192.168.1.22",22))
    t.connect(username='root',password='xxxxx')
    sftp=paramiko.SFTPClient.from_transport(t)

      5.3 put方法

    #方法定义
    put(self,localpath,remotepath,callback=None,confirm=True)
    
    #参数说明
    localpath(str类型):需上传的本地文件(源)
    remotepath(str类型):远程路径(目标)
    callback(function(int,int)),获取已接收的字节数及总传输字节数,以便毁掉函数调用,默认为None
    confirm(bool类型):文件上传完毕后是否调用stat()方法,以便确认文件的大小
    
    #应用
    localpath='/home/access.log'
    remotepath='/data/logs/access.log'
    sftp.put(localpath,remotepath)

      5.4 get方法

    #方法定义
    get(self,remotepath,localpath,callback=None)
    
    #参数说明
    remotepath(str类型):需下载的远程文件(源)
    localpath(str类型):本地路径(目标)
    callback(function(int,int)),获取已接收的字节数及总传输字节数,以便回调函数调用,默认为None
    
    #应用
    remotepath='/data/log/access.log'
    localpath='/home/access.log'
    
    sftp.get(remotepath=remotepath,localpath=localpath)    #推荐使用关键字参数,因为容易与put上传的位置参数混淆

     5.5 其他方法

    mkdir:在SFTP服务器端创建目录,如sftp.mkdir('/home/userdir',777)
    remove:删除SFTP服务端指定目录,如sftp.remove('/home/userdir')
    rename:重命名SFTP服务器端文件或目录,如sftp.rename('/home/test.sh','/home/newfile.sh')
    stat:获取远程SFTP服务器指定文件信息,如sftp.stat('/home/newfile.sh')
    listdir:获取远程SFTP服务器端指定目录列表,以Python的列表(List)形式返回,如sftp.listdir('/home')

      5.6 SFTP示例

    '''
    实现文件上传,下载和 创建目录,删除目录等功能
    '''
    import paramiko
    
    username='root'
    password='xxxx'
    hostname='172.17.9.68'
    port =22
    
    try:
        t=paramiko.Transport((hostname,port))
        t.connect(username=username,password=password)
        sftp=paramiko.SFTPClient.from_transport(t)
    
        sftp.put(remotepath='/home/test05.py',localpath='test05.py')
        sftp.get(remotepath='/home/test05.py',localpath='test0555.py')
        # sftp.mkdir('/home/kuku327',mode=775)
        sftp.rmdir('/home/kuku327')
        print(sftp.listdir('/home'))
        print(sftp.stat('/home/kuku326'))
        t.close()
    except Exception as e:
        print(str(e))

    六、实现密钥方式登录远程主机

    #制作密钥
    1.在主控端/root文件下输入ssh-keygen,一路回车到结束,此时在/root/.ssh/文件夹下会生成一对密钥(id_rsa 和id_rsa.pub)
    2.将id_rsa.pub下发给被控端,通过ssh-copy-id
        在主控端上输入ssh-copy-id -i /root/.ssh/id_rsa.pub  root@被控端ip
    
    3.输入被控端密码即可完成下发公钥到/root/.ssh/文件夹,并自动命名为authorized_keys文件
    4.验证,主控端直接输入ssh roo@被控端ip,无需输入密码即可登录
    
    ===========================================================================
    import paramiko
    import os
    
    hostname='172.17.9.68'
    username='root'
    paramiko.util.log_to_file('6_3_1_login.log')
    
    ssh = paramiko.SSHClient()
    ssh.load_system_host_keys()
    privatekey=os.path.expanduser('/root/.ssh/id_rsa')   #定义私钥存放路径,os.path.expanduser把path中包含的"~"和"~user"转换成用户目录
    key=paramiko.RSAKey.from_private_key_file(privatekey)   #创建私钥对象key
    
    ssh.connect(hostname=hostname,username=username,pkey=key)
    stdin,stdout,stderr=ssh.exec_command('free -m')
    print(stdout.read().decode('utf-8'))
    ssh.close()

    七、paramiko通过堡垒机在远程访问服务器示例

    import paramiko
    import sys
    
    blip="10.254.24.100"    #堡垒机地址
    bluser="xxx"    #堡垒机用户名
    blpasswd='xxx'  #堡垒机密码
    
    hostname='10.100.255.220'   #业务服务器地址
    username='root' #业务服务器用户名
    password='xxxx' #业务服务器密码
    
    port=22 #堡垒机连接端口
    
    def receive_data(match,receive_len=9999):
        buff=''
        resp=''
        while not buff.endswith(match): #接受到的数据末尾如果是match,结束循环
            try:
                resp = channel.recv(receive_len)    #远端接受数据
            except Exception as e:
                print('Eroor info:%s connection time' % str(e))
                channel.close()
                ssh.close()
                sys.exit()
            buff += resp.decode('utf-8')    #resp为bytes,需转成str,才可进行字符串拼接成buff
        return buff
    
    def save_file(filename,mode,content):
        with open(filename,mode,encoding='utf-8') as f:
            f.write(content)
    
    if __name__ == '__main__':
        sum =''
        paramiko.util.log_to_file('login.log')
    
        ssh=paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname=blip,port=port,username=bluser,password=blpasswd)
    
        channel=ssh.invoke_shell()  #创建会话,开启命令调用
        channel.settimeout(20)  #20秒超时
        match_list=['page: ','account: ','Input account: ',"'s password: ",'# ','# ']
        send_list=['0
    ','%s
    '%blip,'1
    ','%s
    '%username,'%s
    '%password,'ifconfig
    ']
        for index,per_match in enumerate(match_list):
    
            channel.send(send_list[index])
            buff=receive_data(per_match)
            sum +=buff
            # print(buff)
        print(sum)  #打印真个过程的交互数据
        save_file('6_3_2_operate.log','w',sum)
        channel.close()
        ssh.close()

     八、通过堡垒机登录业务机上传文件

    #客户端先上传文件到堡垒机,在通过堡垒机上传文件到业务服务器
    import paramiko
    import os,sys,time
    
    blip='172.17.9.68'  #堡垒机信息
    bluser='root'
    blpasswd='xxx'
    
    hostname='172.17.9.70'  #定义业务服务器信息
    username='root'
    password='xxxx'
    
    tmpdir="/root"
    remotedir='/root'
    localpath='6_1_login.log'   #本地源文件路径
    tmppath=tmpdir+'/6_1_login.log' #堡垒机临时路径
    remotepath=remotedir+'/6_1_login.log'   #业务主机目标路径
    port =22
    passinfo="'s password: "
    paramiko.util.log_to_file('syslogin.log')
    
    t=paramiko.Transport((blip,port))
    t.connect(username=bluser,password=blpasswd)
    sftp=paramiko.SFTPClient.from_transport(t)
    sftp.put(localpath=localpath,remotepath=tmppath) #上传本地文件源到堡垒机临时路径
    sftp.close()
    
    ssh=paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname=blip,username=bluser,password=blpasswd)
    
    channel=ssh.invoke_shell()
    channel.settimeout(20)
    
    buff=""
    resp=""
    print ('scp '+tmpdir+' '+username+'@'+hostname+':'+remotepath+'
    ')
    #scp中转目录文件到目标主机
    channel.send('scp '+tmppath+' '+username+'@'+hostname+':'+remotepath+'
    ')
    while not buff.endswith(passinfo):
    
        try:
            resp=channel.recv(9999)
        except Exception as e:
            print('Error info:%s connection time.'%(str(e)))
            channel.close()
            ssh.close()
            sys.exit()
        buff +=resp.decode('utf-8')
        # print(buff)
        if not buff.find('yes/no') == -1:   #找到yes/no字符,执行以下语句
            channel.send('yes
    ')
            buff=''
    
    
    channel.send(password+'
    ')
    
    buff=''
    while not buff.endswith('# '):  #buff末尾不是'# '字符,就执行以下语句
        resp=channel.recv(9999)
        if not resp.decode('utf-8').find(passinfo) ==-1:    #找到‘s password:字符就执行以下语句,说明密码错误
            print ('Error info:Authentication failed.')
            channel.cholse()
            ssh.close()
            sys.exit()
        buff +=resp.decode('utf-8')
    print (buff)
    channel.close()
    ssh.close()
    堡垒机模式下的文件上传

    九、常见问题

      1.出现编码错误

    UnicodeDecodeError: 'utf-8' codec can't decode     byte 0xff in position 0: invalid start byte

      原因分析

    从远端传回来的是bytes字节流,需要将其编码成utf-8,保存在文件里,而有些特殊字符无法编码成utf-8,因此需要这些特殊字符在远端删除

      解决办法

    经过逐行将bytes编码成utf-8,发现在
    ip route-static 192.168.1.0 24 192.168.2.1 description To—_XX
    出现了问题,经测试—_编码有问题,删除—即可

      2.关于H3C设备使用paramiko的问题

      2.1 使用paramiko.SSHClient().exec_command方法,出现paramiko.ssh_exception.SSHException: Channel closed.错误

    遇见此问题的H3C硬件型号和软件型号如下:
    1.硬件型号:S5560-30C-EI
    1.软件版本:Version 7.1.045, Release 1109
    
    
    2.硬件型号:H3C MSR 36-60
    2.软件版本:Version 7.1.059, Release 0304P15
    
    (并非所有H3C设备都会报错)

      解决办法:

    使用paramiko.SSHClient().invoke_shell()代替paramiko.SSHClient().exec_command(),只适用上述软件型号:V7.1.059,而V7.1.045仍然不行
  • 相关阅读:
    线性最小二乘两种方法
    Coursera machine learning 第二周 编程作业 Linear Regression
    Coursera machine learning 第二周 quiz 答案 Octave/Matlab Tutorial
    Coursera machine learning 第二周 quiz 答案 Linear Regression with Multiple Variables
    Codeforces Round #392 (Div. 2) F. Geometrical Progression
    四边形不等式优化DP——石子合并问题 学习笔记
    Codeforces Round #373 (Div. 2) E. Sasha and Array
    hihoCoder #1388 : Periodic Signal
    hihoCoder #1388 : Periodic Signal ( 2016 acm 北京网络赛 F题)
    Java动态代理分析
  • 原文地址:https://www.cnblogs.com/lisenlin/p/9201781.html
Copyright © 2011-2022 走看看