• Python之开发自动化管理工具paramiko


    一、paramiko模块使用

    1)远程执行主机命令获取结果

    方法一

    import paramiko
    
    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 连接服务器
    ssh.connect(hostname='192.168.12.217', port=22, username='root', password='123456')
    
    # 执行命令
    stdin, stdout, stderr = ssh.exec_command('ls /root')
    # 获取命令结果
    result = stdout.read()
    print(result.decode('utf-8'))
    # 关闭连接
    ssh.close()
    View Code

    方法二

    import paramiko
    
    transport = paramiko.Transport(('192.168.12.217', 22))
    transport.connect(username='root', password='123456')
    
    ssh = paramiko.SSHClient()
    ssh._transport = transport
    
    stdin, stdout, stderr = ssh.exec_command('df')
    res=stdout.read()
    print(res.decode('utf-8'))
    
    transport.close()
    View Code

     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())     意义在于,ssh 第一次连接没有连接过的主机,可以跳过会弹出的yes,并且在 /root/.ssh/known_hosts里面添加主机信息

     2)基于公钥连接,制作密钥连接服务器群,

    服务端必须有文件名authorized_keys(在用ssh-keygen时,必须制作一个authorized_keys,可以用ssh-copy-id来制作)

    import paramiko
    
    private_key = paramiko.RSAKey.from_private_key_file('/tmp/id_rsa')
    
    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 连接服务器
    ssh.connect(hostname='120.92.84.249', port=22, username='root', pkey=private_key)
    
    # 执行命令
    stdin, stdout, stderr = ssh.exec_command('df')
    # 获取命令结果
    result = stdout.read()
    print(result.decode('utf-8'))
    # 关闭连接
    ssh.close()
    View Code

      3)上传下载文件,强调是文件

    import paramiko
     
    transport = paramiko.Transport(('192.168.12.55',22))
    transport.connect(username='root',password='xxx')
     
    sftp = paramiko.SFTPClient.from_transport(transport)
    # 将location.py 上传至服务器 /tmp/test.py
    sftp.put('/tmp/id_rsa', '/etc/test.rsa')
    # 将remove_path 下载到本地 local_path
    sftp.get('remove_path', 'local_path')
     
    transport.close()
    View Code

    基于公钥上传下载

    import paramiko
    
    private_key = paramiko.RSAKey.from_private_key_file('/tmp/id_rsa')
    
    transport = paramiko.Transport(('192.168.12.55', 22))
    transport.connect(username='root', pkey=private_key )
    
    sftp = paramiko.SFTPClient.from_transport(transport)
    # 将location.py 上传至服务器 /tmp/test.py
    sftp.put('/tmp/id_rsa', '/tmp/a.txt')
    # 将remove_path 下载到本地 local_path
    sftp.get('remove_path', 'local_path')
    
    transport.close()
    View Code

    原文连接:http://www.cnblogs.com/linhaifeng/articles/6817679.html#_label5

    二、paramiko模块源码分析

     1)下载源码

    git clone https://github.com/paramiko/paramiko.git
    或下载zip文件

     2)执行脚本

    [root@jenkens demos]# pwd
    /root/paramiko-master/paramiko-master/demos
    [root@jenkens demos]# python3 demo.py

     3)修改  interactive.py 文件

    # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
    #
    # This file is part of paramiko.
    #
    # Paramiko is free software; you can redistribute it and/or modify it under the
    # terms of the GNU Lesser General Public License as published by the Free
    # Software Foundation; either version 2.1 of the License, or (at your option)
    # any later version.
    #
    # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
    # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
    # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    # details.
    #
    # You should have received a copy of the GNU Lesser General Public License
    # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
    # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
    
    
    import socket
    import sys
    import time          # 新增内容
    from paramiko.py3compat import u
    
    # 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)
    
            cmd = []  # 增加的内容
            f = open('ssh_test.log','w')        # 新增内容
            while True:
                r, w, e = select.select([chan, sys.stdin], [], [])
                if chan in r:
                    try:
                        x = u(chan.recv(1024))
                        if len(x) == 0:
                            sys.stdout.write("
    *** 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
                    if x =='
    ':            # 新增内容
                        print('input>',''.join(cmd))  # 新增内容
                        log = "%s  %s
    " %(time.strftime("%Y-%m-%d %X",time.gmtime()),''.join(cmd))          # 新增内容
                        f.write(log)     # 新增内容
                        cmd = []             # 新增内容
                    else:                   # 新增内容
                        cmd.append(x)            # 新增内容
                    chan.send(x)
    
        finally:
            termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
            f.close()    # 新增内容
    
    
    # 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
    修改后的文件

     4)查看执行效果,获取到实时的日志记录

     5)分析,用到的文件为

    demo.py                 执行入口文件
    interactive.py         实时输入命令的交互文件
    

    二)实现Django后台传值实时交互

    1)调用程序 ssh_connect函数

    调用ssh_connect连接,self指传送的对象,封装了ip,端口,用户名,密码
    from backend import paramiko_ssh 
    paramiko_ssh.ssh_connect(self, selected_host_to_user_obj )

    2)paramiko_ssh文件代码编写,即ssh_connect入口文件

    #!/usr/bin/env python
    
    # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
    #
    # This file is part of paramiko.
    #
    # Paramiko is free software; you can redistribute it and/or modify it under the
    # terms of the GNU Lesser General Public License as published by the Free
    # Software Foundation; either version 2.1 of the License, or (at your option)
    # any later version.
    #
    # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
    # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
    # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    # details.
    #
    # You should have received a copy of the GNU Lesser General Public License
    # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
    # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
    
    
    import base64
    from binascii import hexlify
    import getpass
    import os
    import select
    import socket
    import sys
    import time
    import traceback
    from paramiko.py3compat import input
    
    import paramiko
    try:
        import interactive
    except ImportError:
        from . import interactive
    
    
    def manual_auth(t,hostname,username, password):
        default_auth = 'p'
        #auth = input('Auth by (p)assword, (r)sa key, or (d)ss key? [%s] ' % default_auth)
        # if len(auth) == 0:
        #     auth = default_auth
        auth = default_auth
        if auth == 'r':
            default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
            path = input('RSA key [%s]: ' % default_path)
            if len(path) == 0:
                path = default_path
            try:
                key = paramiko.RSAKey.from_private_key_file(path)
            except paramiko.PasswordRequiredException:
                password = getpass.getpass('RSA key password: ')
                key = paramiko.RSAKey.from_private_key_file(path, password)
            t.auth_publickey(username, key)
        elif auth == 'd':
            default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_dsa')
            path = input('DSS key [%s]: ' % default_path)
            if len(path) == 0:
                path = default_path
            try:
                key = paramiko.DSSKey.from_private_key_file(path)
            except paramiko.PasswordRequiredException:
                password = getpass.getpass('DSS key password: ')
                key = paramiko.DSSKey.from_private_key_file(path, password)
            t.auth_publickey(username, key)
        else:
            #pw = getpass.getpass('Password for %s@%s: ' % (username, hostname))
            t.auth_password(username, password)
    
    
    def ssh_connect(ssh_handler_instance,host_to_user_obj):
        hostname = host_to_user_obj.host.ip_addr
        port = host_to_user_obj.host.port
        username = host_to_user_obj.remote_user.username
        password = host_to_user_obj.remote_user.password
    
        # now connect
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((hostname, port))
        except Exception as e:
            print('*** Connect failed: ' + str(e))
            traceback.print_exc()
            sys.exit(1)
    
        try:
            t = paramiko.Transport(sock)
            try:
                t.start_client()
            except paramiko.SSHException:
                print('*** SSH negotiation failed.')
                sys.exit(1)
    
            try:
                keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
            except IOError:
                try:
                    keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
                except IOError:
                    print('*** Unable to open host keys file')
                    keys = {}
    
            # check server's host key -- this is important.
            key = t.get_remote_server_key()
            if hostname not in keys:
                print('*** WARNING: Unknown host key!')
            elif key.get_name() not in keys[hostname]:
                print('*** WARNING: Unknown host key!')
            elif keys[hostname][key.get_name()] != key:
                print('*** WARNING: Host key has changed!!!')
                sys.exit(1)
            else:
                print('*** Host key OK.')
    
    
            if not t.is_authenticated():
                manual_auth(t,hostname,username, password)
            if not t.is_authenticated():
                print('*** Authentication failed. :(')
                t.close()
                sys.exit(1)
    
            chan = t.open_session()
            chan.get_pty()
            chan.invoke_shell()
    
            chan.crazyeye_account = ssh_handler_instance.user
            chan.host_to_user_obj = host_to_user_obj
            chan.models = ssh_handler_instance.models
            print('*** Here we go!
    ')
            ssh_handler_instance.models.AuditLog.objects.create(
                user = ssh_handler_instance.user ,
                log_type = 0 ,
                host_to_remote_user = host_to_user_obj,
                content = "***user login***"
            )
    
            interactive.interactive_shell(chan)
            chan.close()
            t.close()
    
            ssh_handler_instance.models.AuditLog.objects.create(
                user=ssh_handler_instance.user,
                log_type=2,
                host_to_remote_user=host_to_user_obj,
                content="***user logout***"
            )
    
        except Exception as e:
            print('*** Caught exception: ' + str(e.__class__) + ': ' + str(e))
            traceback.print_exc()
            try:
                t.close()
            except:
                pass
            sys.exit(1)
    ssh_connnect

    3)与命令交互接口

    # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
    #
    # This file is part of paramiko.
    #
    # Paramiko is free software; you can redistribute it and/or modify it under the
    # terms of the GNU Lesser General Public License as published by the Free
    # Software Foundation; either version 2.1 of the License, or (at your option)
    # any later version.
    #
    # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
    # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
    # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
    # details.
    #
    # You should have received a copy of the GNU Lesser General Public License
    # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
    # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
    
    
    import socket
    import sys
    import time 
    from paramiko.py3compat import u
    
    # 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)
            cmd = [] 
            #f = open('ssh_test.log','w')
            while True:
                r, w, e = select.select([chan, sys.stdin], [], [])
                if chan in r:
                    try:
                        x = u(chan.recv(1024))
                        if len(x) == 0:
                            sys.stdout.write('
    *** 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
                    if x == '
    ':
                        print('input>',''.join(cmd))
                        #log = "%s   %s
    " %(time.strftime("%Y-%m-%d %X", time.gmtime()), ''.join(cmd))
                        #print(log)
                        chan.models.AuditLog.objects.create(
                            user=chan.crazyeye_account,
                            log_type=1,
                            host_to_remote_user=chan.host_to_user_obj,
                            content=''.join(cmd)
                        )
                        #f.write(log)
                        cmd = []
                    else:
                        cmd.append(x)
                    chan.send(x)
    
        finally:
            termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
            #f.close()
        
    # thanks to Mike Looijmans for this code
    def windows_shell(chan):
    
        print("window chan",chan.host_to_user_obj)
        print("window chan",chan.crazyeye_account)
        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
    interactive

    三、修改上面的代码,方便个人扩展,不使用表结构

    1)修改ssh_connect文件

    #!/usr/bin/env python
    import getpass
    import os
    import socket
    import sys
    import traceback
    from paramiko.py3compat import input
    import paramiko
    
    try:
        import interactive
    except ImportError:
        from . import interactive
    
    
    def manual_auth(t, hostname, username, password):
        default_auth = 'p'
        auth = default_auth
        if auth == 'r':
            default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
            path = input('RSA key [%s]: ' % default_path)
            if len(path) == 0:
                path = default_path
            try:
                key = paramiko.RSAKey.from_private_key_file(path)
            except paramiko.PasswordRequiredException:
                password = getpass.getpass('RSA key password: ')
                key = paramiko.RSAKey.from_private_key_file(path, password)
            t.auth_publickey(username, key)
        elif auth == 'd':
            default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_dsa')
            path = input('DSS key [%s]: ' % default_path)
            if len(path) == 0:
                path = default_path
            try:
                key = paramiko.DSSKey.from_private_key_file(path)
            except paramiko.PasswordRequiredException:
                password = getpass.getpass('DSS key password: ')
                key = paramiko.DSSKey.from_private_key_file(path, password)
            t.auth_publickey(username, key)
        else:
            t.auth_password(username, password)
    
    
    def ssh_connect(hostname, port, username, password):
        hostname = hostname
        port = port
        username = username
        password = password
    
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((hostname, port))
        except Exception as e:
            print('*** Connect failed: ' + str(e))
            traceback.print_exc()
            sys.exit(1)
    
        try:
            t = paramiko.Transport(sock)
            try:
                t.start_client()
            except paramiko.SSHException:
                print('*** SSH negotiation failed.')
                sys.exit(1)
    
            try:
                keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
            except IOError:
                try:
                    keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
                except IOError:
                    print('*** Unable to open host keys file')
                    keys = {}
    
            key = t.get_remote_server_key()
            if hostname not in keys:
                print('*** WARNING: Unknown host key!')
            elif key.get_name() not in keys[hostname]:
                print('*** WARNING: Unknown host key!')
            elif keys[hostname][key.get_name()] != key:
                print('*** WARNING: Host key has changed!!!')
                sys.exit(1)
            else:
                print('*** Host key OK.')
    
            if not t.is_authenticated():
                manual_auth(t, hostname, username, password)
            if not t.is_authenticated():
                print('*** Authentication failed. :(')
                t.close()
                sys.exit(1)
    
            chan = t.open_session()
            chan.get_pty()
            chan.invoke_shell()
    
            # 获取到登录时的用户信息
            print('*** Here we go!
    ')
            # 创建登录时的用户信息,时间等,写入表
    
            print('登录成功')
    
            interactive.interactive_shell(chan)
            chan.close()
            t.close()
    
            # 创建退出时的用户信息,时间等,写入表
            print('退出成功')
    
        except Exception as e:
            print('*** Caught exception: ' + str(e.__class__) + ': ' + str(e))
            traceback.print_exc()
            try:
                t.close()
            except:
                pass
            sys.exit(1)
    
    
    if __name__ == '__main__':
        hostname = '192.168.10.13'
        port = 22
        username = 'root'
        password = '123456'
        ssh_connect(hostname, port, username, password)
    View Code

    2)修改命令交互接口

    import socket
    import sys
    import time 
    from paramiko.py3compat import u
    
    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)
            cmd = [] 
            #f = open('ssh_test.log','w')   # 创建操作日志文件写入,后面也可用表
            while True:
                r, w, e = select.select([chan, sys.stdin], [], [])
                if chan in r:
                    try:
                        x = u(chan.recv(1024))
                        if len(x) == 0:
                            sys.stdout.write('
    *** 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
                    if x == '
    ':
                        print('input>',''.join(cmd))
                        #log = "%s   %s
    " %(time.strftime("%Y-%m-%d %X", time.gmtime()), ''.join(cmd))
                        #f.write(log)
                        # 或
                        # 记录操作日志表信息
                        cmd = []
                    else:
                        cmd.append(x)
                    chan.send(x)
    
        finally:
            termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
            #f.close()
        
    
    
    # windows_shell 该函数没有用
    def windows_shell(chan):
    
        print("window chan",chan.host_to_user_obj)
        print("window chan",chan.crazyeye_account)
        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

    执行效果。python ssh_connnect.py

    [root@jenkens tools]# python3 ssh_connnect.py 
    *** Unable to open host keys file
    *** WARNING: Unknown host key!
    *** Here we go!
    
    登录成功
    Last login: Thu Nov  1 20:45:51 2018 from 192.168.10.13
    hello centos7
  • 相关阅读:
    利用Python和webhook实现自动提交代码
    Python threading 单线程 timer重复调用函数
    Python requests 使用心得
    openresty实现接口签名安全认证
    使用jedis面临的非线程安全问题
    记一次线上升级openresty中kafka版本产生的多版本兼容问题
    mysql中走与不走索引的情况汇集(待全量实验)
    Elasticsearch深分页以及排序查询问题
    IO多路复用:Redis中经典的Reactor设计模式
    Netty在Dubbo中的使用过程源码分析
  • 原文地址:https://www.cnblogs.com/linu/p/9165235.html
Copyright © 2020-2023  润新知