-
Notifications
You must be signed in to change notification settings - Fork 196
/
expect.py
210 lines (178 loc) · 6.19 KB
/
expect.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env python
# -*- coding: utf-8 -*
# Copyright: [CUP] - See LICENSE for details.
# Authors: Guannan Ma (@mythmgn),
"""
:description:
**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
"""
from __future__ import print_function
import os
import sys
import cup
from cup import log
from cup.thirdp import pexpect
__all__ = [
'go', 'go_ex', 'checkssh', 'go_with_scp', 'lscp', 'dscp'
]
def _do_expect_ex(passwd, command, timeout=100, b_print_stdout=True):
"""ret 0 success 1 timeout others -1"""
retcode = 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)
retcode = pobj.expect(pexpect.EOF)
except pexpect.TIMEOUT:
sys.stderr.write('Connection timeout\n')
retcode = 1
except pexpect.EOF:
pobj.close()
retcode = pobj.exitstatus
except Exception as error:
sys.stderr.write('Connection close, error:%s\n' % error)
retcode = -1
ret = {
'exitstatus': retcode,
'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):
""" invoke _do_expect_ex"""
ret = _do_expect_ex(passwd, command, timeout, b_print_stdout)
return (ret['exitstatus'], ret['result'])
def checkssh(hostname, username, passwd):
"""
check if we can ssh to hostname. Return True if succeed, False otherwise.
"""
_, 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
def go(
hostname, username, passwd, command='', timeout=800, b_print_stdout=True
):
"""
deprecated, recommand using go_ex or go_with_scp
"""
cmd = """ssh %s@%s '%s'""" % (username, hostname, command)
return _do_expect(passwd, cmd, timeout, b_print_stdout)
def _judge_ret(ret, msg=''):
if not (ret['exitstatus'] and ret['remote_exitstatus']):
return True
ret['result'] = msg + ' \n ' + str(ret['result'])
return False
def go_with_scp(
hostname, username, passwd, command='',
host_tmp='/tmp/', remote_tmp='/tmp/',
timeout=800, b_print_stdout=True
):
"""
Recommand using this function to remotely execute cmds.
go_witch_scp will write a temp script file and scp to hostname:[host_tmp].
Then execute it and get the result back.
:param host_tmp:
temp folder for keeping the temporary script file (contains the cmd)
:param remote_tmp:
remote temp folder for keeping the temporary script file
:param timeout:
timeout
:return:
a dict with keys ('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 fhandle:
fhandle.write(command)
if not os.path.exists(host_file):
return ret
ret = lscp(host_file, hostname, username, passwd, remote_file, timeout, b_print_stdout)
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 -f %s ' % host_file
res = cup.shell.execshell(cmd, b_print_stdout)
if res:
ret['result'] = 'rm -f host_file fail, ret:%s' % res
return ret
cmd = ' rm -f %s ' % remote_file
res = go_ex(hostname, username, passwd, cmd, 10, b_print_stdout)
if not _judge_ret(res, 'rm -f remote_file ret:'):
return res
return ret
def go_ex(
hostname, username, passwd, command='', timeout=800, b_print_stdout=True
):
"""
Run [command] on remote [hostname] and return result. If you have a lot
of escape sign in the command, recommand using go_with_scp
:param timeout:
execution timeout, by default 800 seconds
:return:
return a dict with keys ('exitstatus' 'remote_exitstatus' 'result')
"""
cmd = """ssh %s@%s '%s'""" % (username, hostname, command)
log.info('go_ex {0}'.format(cmd))
ret = _do_expect_ex(passwd, cmd, timeout, b_print_stdout)
return ret
def lscp(
src, hostname, username, passwd, dst,
timeout=800, b_print_stdout=True
):
"""
copy [localhost]:src to [hostname]:[dst]
:return:
return a dict with keys ('exitstatus' 'remote_exitstatus' 'result')
"""
cmd = 'scp -r %s %s@%s:%s' % (src, username, hostname, dst)
log.info('{0}'.format(cmd))
return _do_expect_ex(passwd, cmd, timeout, b_print_stdout)
def lscp_prod(scpstr, passwd, dst_path, timeout=800, b_print_stdout=True):
"""
deprecated. Kept here for compatibility only.
"""
cmd = 'scp -r ' + scpstr + ' ' + dst_path
return _do_expect(passwd, cmd, timeout, b_print_stdout)
def dscp(
hostname, username, passwd, src, dst, timeout=9000, b_print_stdout=False
):
"""
copy [hostname]:[src] to [localhost]:[dst].
:return:
return a dict with keys ('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)