Source code for cup.shell.expect

#!/usr/bin/python
# -*- coding: utf-8 -*
# #############################################################################
#
#  Copyright (c) 2014 Baidu.com,  Inc. All Rights Reserved
#
# #############################################################################
"""
:author:
    Guannan Ma
:create_date:
    2013
:last_date:
    2014
:descrition:
    **Guannan just made a wraper out of pexpect.**
    The original copyright belongs to the author of pexpect module.
    See it at http://pexpect.sourceforge.net/pexpect.html

"""
import os
import sys

import cup
from cup.thirdp import pexpect


def _do_expect_ex(passwd, command, timeout=100, b_print_stdout=True):
    # ret 0 success 1 timeout others -1
    ret = 0
    try:
        pobj = pexpect.spawn('/bin/bash', ['-c', command], timeout=timeout)
        if b_print_stdout:
            pobj.logfile = sys.stdout
        i = pobj.expect(
            ['password:', 'continue connecting (yes/no)?'], timeout=timeout
        )
        if i == 0:
            pobj.sendline(passwd)
        elif i == 1:
            pobj.sendline("yes")
            pobj.expect(['password:'])
            pobj.sendline(passwd)
        ret = pobj.expect(pexpect.EOF)
    except pexpect.TIMEOUT:
        print 'Connection timeout'
        ret = 1
    except pexpect.EOF:
        print 'Connection exit'
        pobj.close()
        ret = pobj.exitstatus
    except Exception as error:
        print "Connection close", error
        ret = -1
    ret = {
        'exitstatus': ret,
        'remote_exitstatus': pobj.exitstatus,
        'result': pobj.before
    }
    if ret['exitstatus'] is None:
        if ret['remote_exitstatus'] == 0 or ret['remote_exitstatus'] is None:
            ret['exitstatus'] = 0
        else:
            ret['exitstatus'] = ret['remote_exitstatus']
    if ret['remote_exitstatus'] is None:
        if ret['exitstatus'] == 0 or ret['exitstatus'] is None:
            ret['remote_exitstatus'] = 0
        else:
            ret['remote_exitstatus'] = ret['exitstatus']

    return ret


def _do_expect(passwd, command, timeout=100, b_print_stdout=True):
    ret = _do_expect_ex(passwd, command, timeout, b_print_stdout)
    return (ret['exitstatus'], ret['result'])


[docs]def checkssh(hostname, username, passwd): """ 判断ssh的连通性, 成功的话返回True, 否则False """ ret, rev = go( hostname, username, passwd, 'echo "testSSH"', timeout=8, b_print_stdout=False ) if str(rev).strip().find('testSSH') >= 0: return True else: return False
[docs]def go( hostname, username, passwd, command='', timeout=800, b_print_stdout=True ): """ 回返在hostname机器上执行的shell命令结果信息 历史兼容函数。 推荐使用go_ex command 有较多转义字符的,不推荐使用go,推荐使用go_witch_scp :return: 类型tuple: (ret, return_string) ret 是本机执行远程命令的返回值 return_string 是远程执行这条shell的输出值 """ cmd = """ssh %s@%s '%s'""" % (username, hostname, command) return _do_expect(passwd, cmd, timeout, b_print_stdout)
def _judge_ret(ret, msg=''): print ret if not (ret['exitstatus'] and ret['remote_exitstatus']): return True ret['result'] = msg + ' \n ' + ret['result'] return False
[docs]def go_witch_scp( hostname, username, passwd, command='', host_tmp='/tmp/', remote_tmp='/tmp/', timeout=8000, b_print_stdout=True ): """ 回返在hostname机器上执行的shell命令结果信息, 方式是:把command 写入本机文件,然后scp到远端机器,然后到远端执行此文件 相比go_ex 和 go 而言,多了如下参数 :param host_tmp: 本次保存command内容的文件目录 :param remote_tmp: 远端保持command内容的文件目录 :return: dict.有 'exitstatus' 'remote_exitstatus' 'result' 三项输出内容 """ ret = { 'exitstatus': -1, 'remote_exitstatus': -1, 'result': 'write host file fail' } tmp_filename = cup.util.CGeneratorMan().get_uniqname() host_file = host_tmp + '/' + tmp_filename remote_file = remote_tmp + '/' + tmp_filename with open(host_file, 'w') as fd: fd.write(command) if not os.path.exists(host_file): return ret ret = lscp(host_file, hostname, username, passwd, remote_file, timeout) if not _judge_ret(ret, 'scp ret:'): return ret cmd = ' sh %s ' % remote_file ret = go_ex(hostname, username, passwd, cmd, timeout, b_print_stdout) cmd = ' rm %s ' % host_file res = cup.shell.execshell(cmd) if not res: ret['result'] = 'rm host_file fail, ret:%s' % res return ret cmd = ' rm %s ' % remote_file res = go_ex(hostname, username, passwd, cmd, 10) if not _judge_ret(res, 'rm remote_file ret:'): return res return ret
[docs]def go_ex( hostname, username, passwd, command='', timeout=800, b_print_stdout=True ): """ 回返在hostname机器上执行的shell命令结果信息, 相比go而言, 回返信息更丰富,且按照dict方式回返. command 有较多转义字符的,不推荐使用go,推荐使用go_witch_scp :return: dict.有 'exitstatus' 'remote_exitstatus' 'result' 三项输出内容 """ cmd = """ssh %s@%s '%s'""" % (username, hostname, command) ret = _do_expect_ex(passwd, cmd, timeout, b_print_stdout) return ret
[docs]def lscp( src, hostname, username, passwd, dst, timeout=800, b_print_stdout=True ): """ 拷贝src到hostname的dst目录下。 :return: dict.有 'exitstatus' 'remote_exitstatus' 'result' 三项输出内容 """ cmd = 'scp -r %s %s@%s:%s' % (src, username, hostname, dst) return _do_expect_ex(passwd, cmd, timeout, b_print_stdout)
[docs]def lscp_prod(scpstr, passwd, dst_path, timeout=800, b_print_stdout=True): """ 兼容过去版本函数, 不推荐使用。 """ cmd = 'scp -r ' + scpstr + ' ' + dst_path return _do_expect(passwd, cmd, timeout, b_print_stdout)
[docs]def dscp( hostname, username, passwd, src, dst, timeout=9000, b_print_stdout=False ): """ 拷贝hostname, src目录到本地的dst目录。 采取scp -r的模式。 :return: dict.有 'exitstatus' 'remote_exitstatus' 'result' 三项输出内容 """ cmd = 'scp -r %s@%s:%s %s' % (username, hostname, src, dst) return _do_expect_ex(passwd, cmd, timeout, b_print_stdout)