day13 使用sqlalchemy和paramiko实现一个简单的跳板机

代码如下(未使用sqlalchemy版本):

#!/bin/env python

import paramiko
import sys
import os
import socket
import getpass

from paramiko.py3compat import u

import termios    #Windows下无此模块
import tty
import select


'''
有关终端模式的解释
终端最常用的模式是Cooked模式,在该模式下删除键和终止键能正常地工作,CTRL_S和 CTRL_Q用来停止和恢复终端输出,
CTRL_D为文件结束符,按DEL键产生一个中断信号,而CTRL-产生一个退出信号并强制进行核心映像转储。

在raw模式下,所有这些功能都被取消,每个字符都被不加处理地送给程序,而且不等一行结束就将从终端读到每一个字符
发送给程序。与此不同的是在Cooked模式下,终端输入的数据等到一行结束才送给程序。

Cbreak模式介于上述两者之间,用作编辑的删除键和终止键,以及CTRL_D被屏蔽,但CTRL_S,CTRL_Q,DEL和CTRL_则仍然
有效,与raw模式一样,单个字符不等一行结束就送给程序(如果禁止行内编辑功能,则没必要等待接收到完整的一行,因为
用户不可能象在cooked模式下那样改变主意并删除它)。
'''


def posix_shell(chan):

    oldtty = termios.tcgetattr(sys.stdin)   #获取当前终端的模式
    try:
        tty.setraw(sys.stdin.fileno())    #设置终端模式为raw模式
        tty.setcbreak(sys.stdin.fileno())   #设置终端模式为cbreak模式
        chan.settimeout(0.0)     #不对chan超时时间做限制
        log = open('handle.log', 'a+', encoding='utf-8')    #open一个文件,用来记录历史命令
        flag = False
        #当用户输入table键时,flag才为True,当有内容返回时,判断flag是否为True,如果为True,
        # 如果返回值.startswith('
')为空,不做任何操作,如果返回值不为空,将返回值加到temp_list列表
        # 中(因为返回值是用户敲命令是补全的命令后半截)
        temp_list = []   #用来存放用户输入,即记录历史命令
        while True:
            r, w, e = select.select([chan, sys.stdin], [], [])
            if chan in r:    #chan in  r时,说明有返回值
                try:
                    x = u(chan.recv(1024))   #获取返回内容
                    if len(x) == 0:   #如果返回值长度为0,代表用户输入exit退出了
                        sys.stdout.write('
*** EOF
')
                        break
                    if flag:     #上方定义flag时已解释
                        if x.startswith('
'):
                            pass
                        else:
                            temp_list.append(x)
                        flag = False  #最后将flag还原为False
                    sys.stdout.write(x)    #输出返回值到屏幕
                    sys.stdout.flush()
                except socket.timeout:
                    pass
            if sys.stdin in r:    #sys.stdin in r时,说明用户用输入内容
                x = sys.stdin.read(1)   #输出用户输入的内容到屏幕
                #说明,因为当前终端模式为cblock模式

                if len(x) == 0:
                    break

                if x == '	':     #这里将flag设置为True,具体以上定义flag时有解释
                    flag = True
                else:
                    temp_list.append(x)   #将用户的输入内容append到一个临时列表中
                if x == '
':    #代表用户输入回车
                    log.write(''.join(temp_list))   #''.join(temp_list)为用户敲的命令,将命令写入到日志文件中
                    log.flush()
                    temp_list.clear()   #清空临时列表
                chan.send(x)    #发送用户的输入内容到远程主机

    finally:
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)     #将终端模式还原为最初模式


def run():
    """
    让用户输入主机名,用户名并设置默认用户名等
    :return:
    """
    default_username = getpass.getuser()    #获取当前登录用户的用户名
    username = input('Username [%s]: ' % default_username)
    if len(username) == 0:
        username = default_username


    hostname = input('Hostname: ')
    if len(hostname) == 0:
        print('*** Hostname required.')
        sys.exit(1)

    tran = paramiko.Transport((hostname, 22,))       #创建一个连接
    tran.start_client()

    default_auth = "p"
    auth = input('Auth by (p)assword or (r)sa key[%s] ' % default_auth)
    if len(auth) == 0:
        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)
        tran.auth_publickey(username, key)
    else:
        pw = getpass.getpass('Password for %s@%s: ' % (username, hostname))
        tran.auth_password(username, pw)

    # 打开一个通道
    chan = tran.open_session()
    # 获取一个终端
    chan.get_pty()
    # 激活器
    chan.invoke_shell()

    posix_shell(chan)

    chan.close()
    tran.close()


if __name__ == '__main__':
    run()
原文地址:https://www.cnblogs.com/xuanouba/p/5742308.html