blob: 2db391498ce67cf63714dd8e1de4e55b3cab5d7f [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
kelvin8ec71442015-01-15 16:57:00 -08002"""
adminbae64d82013-08-01 10:50:15 -07003Created on 24-Oct-2012
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00004Copyright 2012 Open Networking Foundation (ONF)
kelvin8ec71442015-01-15 16:57:00 -08005
Jeremy Songsterae01bba2016-07-11 15:39:17 -07006Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
7the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
8or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
adminbae64d82013-08-01 10:50:15 -07009
10 TestON is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
Jeremy Ronquillo82705492017-10-18 14:19:55 -070013 (at your option) any later version.
adminbae64d82013-08-01 10:50:15 -070014
15 TestON is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
kelvin8ec71442015-01-15 16:57:00 -080021 along with TestON. If not, see <http://www.gnu.org/licenses/>.
kelvin8ec71442015-01-15 16:57:00 -080022"""
adminbae64d82013-08-01 10:50:15 -070023import pexpect
kelvin8ec71442015-01-15 16:57:00 -080024import re
adminbae64d82013-08-01 10:50:15 -070025
26from drivers.component import Component
kelvin8ec71442015-01-15 16:57:00 -080027
28
29class CLI( Component ):
30
31 """
adminbae64d82013-08-01 10:50:15 -070032 This will define common functions for CLI included.
kelvin8ec71442015-01-15 16:57:00 -080033 """
34 def __init__( self ):
Devin Limdc78e202017-06-09 18:30:07 -070035 super( CLI, self ).__init__()
Jon Hallca319892017-06-15 15:25:22 -070036
Jeremy Ronquillo82705492017-10-18 14:19:55 -070037 def checkPrompt( self ):
Devin Limdc78e202017-06-09 18:30:07 -070038 for key in self.options:
Jeremy Ronquillo82705492017-10-18 14:19:55 -070039 if key == "prompt" and self.options[ 'prompt' ] is not None:
40 self.prompt = self.options[ 'prompt' ]
Devin Limdc78e202017-06-09 18:30:07 -070041 break
kelvin8ec71442015-01-15 16:57:00 -080042
43 def connect( self, **connectargs ):
44 """
adminbae64d82013-08-01 10:50:15 -070045 Connection will establish to the remote host using ssh.
46 It will take user_name ,ip_address and password as arguments<br>
kelvin8ec71442015-01-15 16:57:00 -080047 and will return the handle.
48 """
adminbae64d82013-08-01 10:50:15 -070049 for key in connectargs:
kelvin8ec71442015-01-15 16:57:00 -080050 vars( self )[ key ] = connectargs[ key ]
Devin Limdc78e202017-06-09 18:30:07 -070051 self.checkPrompt()
adminbae64d82013-08-01 10:50:15 -070052
kelvin8ec71442015-01-15 16:57:00 -080053 connect_result = super( CLI, self ).connect()
adminbae64d82013-08-01 10:50:15 -070054 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -080055 refused = "ssh: connect to host " + \
56 self.ip_address + " port 22: Connection refused"
adminbae64d82013-08-01 10:50:15 -070057 if self.port:
kelvin8ec71442015-01-15 16:57:00 -080058 self.handle = pexpect.spawn(
Jon Hall7a5e0a22017-12-11 10:35:50 -080059 'ssh -X -p ' +
kelvin8ec71442015-01-15 16:57:00 -080060 self.port +
61 ' ' +
62 self.user_name +
63 '@' +
Jon Hall7a5e0a22017-12-11 10:35:50 -080064 self.ip_address +
65 ' -o ServerAliveInterval=120 -o TCPKeepAlive=yes',
Jon Hall6c9e2da2018-11-06 12:01:23 -080066 env={ "TERM": "vt100" },
Jon Hall7a5e0a22017-12-11 10:35:50 -080067 maxread=1000000 )
kelvin8ec71442015-01-15 16:57:00 -080068 else:
69 self.handle = pexpect.spawn(
70 'ssh -X ' +
71 self.user_name +
72 '@' +
Jon Hall7a5e0a22017-12-11 10:35:50 -080073 self.ip_address +
74 ' -o ServerAliveInterval=120 -o TCPKeepAlive=yes',
Jon Hall6c9e2da2018-11-06 12:01:23 -080075 env={ "TERM": "vt100" },
kelvin8ec71442015-01-15 16:57:00 -080076 maxread=1000000,
77 timeout=60 )
adminbae64d82013-08-01 10:50:15 -070078
Jon Hall73057ee2016-08-23 09:57:26 -070079 # set tty window size
80 self.handle.setwinsize( 24, 250 )
81
adminbae64d82013-08-01 10:50:15 -070082 self.handle.logfile = self.logfile_handler
kelvin8ec71442015-01-15 16:57:00 -080083 i = 5
84 while i == 5:
Jon Hall4173b242017-09-12 17:04:38 -070085 i = self.handle.expect( [ ssh_newkey,
86 'password:|Password:',
87 pexpect.EOF,
88 pexpect.TIMEOUT,
89 refused,
90 'teston>',
Jon Halld9066132018-03-01 14:52:53 -080091 'Permission denied, please try again.',
Jon Hall4173b242017-09-12 17:04:38 -070092 self.prompt ],
93 120 )
acsmars32de0bc2015-06-30 09:57:12 -070094 if i == 0: # Accept key, then expect either a password prompt or access
kelvin8ec71442015-01-15 16:57:00 -080095 main.log.info( "ssh key confirmation received, send yes" )
96 self.handle.sendline( 'yes' )
acsmars32de0bc2015-06-30 09:57:12 -070097 i = 5 # Run the loop again
acsmars07f9d392015-07-15 10:30:58 -070098 continue
99 if i == 1: # Password required
Jon Hall63604932015-02-26 17:09:50 -0800100 if self.pwd:
101 main.log.info(
Jon Hall4173b242017-09-12 17:04:38 -0700102 "ssh connection asked for password, gave password" )
Jon Hall63604932015-02-26 17:09:50 -0800103 else:
acsmars07f9d392015-07-15 10:30:58 -0700104 main.log.info( "Server asked for password, but none was "
105 "given in the .topo file. Trying "
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700106 "no password." )
acsmars07f9d392015-07-15 10:30:58 -0700107 self.pwd = ""
108 self.handle.sendline( self.pwd )
109 j = self.handle.expect( [
acsmars07f9d392015-07-15 10:30:58 -0700110 'password:|Password:',
Jon Halld9066132018-03-01 14:52:53 -0800111 'Permission denied, please try again.',
112 self.prompt,
acsmars07f9d392015-07-15 10:30:58 -0700113 pexpect.EOF,
114 pexpect.TIMEOUT ],
115 120 )
Jon Halld9066132018-03-01 14:52:53 -0800116 if j != 2:
acsmars07f9d392015-07-15 10:30:58 -0700117 main.log.error( "Incorrect Password" )
118 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800119 elif i == 2:
120 main.log.error( "Connection timeout" )
121 return main.FALSE
122 elif i == 3: # timeout
123 main.log.error(
124 "No route to the Host " +
125 self.user_name +
126 "@" +
127 self.ip_address )
128 return main.FALSE
129 elif i == 4:
130 main.log.error(
131 "ssh: connect to host " +
132 self.ip_address +
133 " port 22: Connection refused" )
134 return main.FALSE
Jon Halld9066132018-03-01 14:52:53 -0800135 elif i == 6: # Incorrect Password
136 main.log.error( "Incorrect Password" )
137 return main.FALSE
138 elif i == 7: # Prompt
kelvin8ec71442015-01-15 16:57:00 -0800139 main.log.info( "Password not required logged in" )
adminbae64d82013-08-01 10:50:15 -0700140
kelvin8ec71442015-01-15 16:57:00 -0800141 self.handle.sendline( "" )
Devin Limdc78e202017-06-09 18:30:07 -0700142 self.handle.expect( self.prompt )
Jeremy Ronquillo0f2008a2017-06-23 15:32:51 -0700143 self.handle.sendline( "cd" )
144 self.handle.expect( self.prompt )
adminbae64d82013-08-01 10:50:15 -0700145 return self.handle
146
kelvin8ec71442015-01-15 16:57:00 -0800147 def disconnect( self ):
148 result = super( CLI, self ).disconnect( self )
adminbae64d82013-08-01 10:50:15 -0700149 result = main.TRUE
kelvin8ec71442015-01-15 16:57:00 -0800150 # self.execute( cmd="exit",timeout=120,prompt="(.*)" )
151
152 def execute( self, **execparams ):
153 """
adminbae64d82013-08-01 10:50:15 -0700154 It facilitates the command line execution of a given command. It has arguments as :
155 cmd => represents command to be executed,
156 prompt => represents expect command prompt or output,
157 timeout => timeout for command execution,
158 more => to provide a key press if it is on.
You Wang7d14d642019-01-23 15:10:08 -0800159 logCmd => log the command executed if True
adminbae64d82013-08-01 10:50:15 -0700160
161 It will return output of command exection.
kelvin8ec71442015-01-15 16:57:00 -0800162 """
163 result = super( CLI, self ).execute( self )
adminaef00552014-05-08 09:18:36 -0700164 defaultPrompt = '.*[$>\#]'
Jon Hall3b489db2015-10-05 14:38:37 -0700165 args = utilities.parse_args( [ "CMD",
166 "TIMEOUT",
167 "PROMPT",
You Wang7d14d642019-01-23 15:10:08 -0800168 "MORE",
169 "LOGCMD" ],
Jon Hall3b489db2015-10-05 14:38:37 -0700170 **execparams )
kelvin8ec71442015-01-15 16:57:00 -0800171
172 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
adminbae64d82013-08-01 10:50:15 -0700173 self.LASTRSP = ""
kelvin8ec71442015-01-15 16:57:00 -0800174 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
adminbae64d82013-08-01 10:50:15 -0700175 cmd = ''
kelvin8ec71442015-01-15 16:57:00 -0800176 if args[ "CMD" ]:
177 cmd = args[ "CMD" ]
178 else:
adminbae64d82013-08-01 10:50:15 -0700179 return 0
kelvin8ec71442015-01-15 16:57:00 -0800180 if args[ "MORE" ] is None:
181 args[ "MORE" ] = " "
182 self.handle.sendline( cmd )
adminbae64d82013-08-01 10:50:15 -0700183 self.lastCommand = cmd
Jon Hall3b489db2015-10-05 14:38:37 -0700184 index = self.handle.expect( [ expectPrompt,
185 "--More--",
186 'Command not found.',
187 pexpect.TIMEOUT,
188 "^:$" ],
189 timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700190 if index == 0:
kelvin8ec71442015-01-15 16:57:00 -0800191 self.LASTRSP = self.LASTRSP + \
192 self.handle.before + self.handle.after
You Wang7d14d642019-01-23 15:10:08 -0800193 if not args[ "LOGCMD" ] is False:
194 main.log.info( "Executed :" + str( cmd ) +
195 " \t\t Expected Prompt '" + str( expectPrompt ) +
196 "' Found" )
adminbae64d82013-08-01 10:50:15 -0700197 elif index == 1:
198 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800199 self.handle.send( args[ "MORE" ] )
200 main.log.info(
201 "Found More screen to go , Sending a key to proceed" )
202 indexMore = self.handle.expect(
203 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700204 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800205 main.log.info(
206 "Found anoother More screen to go , Sending a key to proceed" )
207 self.handle.send( args[ "MORE" ] )
208 indexMore = self.handle.expect(
209 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700210 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800211 elif index == 2:
212 main.log.error( "Command not found" )
adminbae64d82013-08-01 10:50:15 -0700213 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800214 elif index == 3:
Jon Hall3b489db2015-10-05 14:38:37 -0700215 main.log.error( "Expected Prompt not found, Time Out!!" )
kelvin8ec71442015-01-15 16:57:00 -0800216 main.log.error( expectPrompt )
Jon Hall3b489db2015-10-05 14:38:37 -0700217 self.LASTRSP = self.LASTRSP + self.handle.before
218 return self.LASTRSP
adminbae64d82013-08-01 10:50:15 -0700219 elif index == 4:
220 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800221 # self.handle.send( args[ "MORE" ] )
222 self.handle.sendcontrol( "D" )
223 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700224 "Found More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800225 indexMore = self.handle.expect(
226 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700227 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800228 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700229 "Found another More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800230 self.handle.sendcontrol( "D" )
231 indexMore = self.handle.expect(
232 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700233 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800234 main.last_response = self.remove_contol_chars( self.LASTRSP )
adminbae64d82013-08-01 10:50:15 -0700235 return self.LASTRSP
kelvin8ec71442015-01-15 16:57:00 -0800236
237 def remove_contol_chars( self, response ):
238 # RE_XML_ILLEGAL = '([\u0000-\u0008\u000b-\u000c\u000e-\u001f\ufffe-\uffff])|([%s-%s][^%s-%s])|([^%s-%s][%s-%s])|([%s-%s]$)|(^[%s-%s])'%( unichr( 0xd800 ),unichr( 0xdbff ),unichr( 0xdc00 ),unichr( 0xdfff ),unichr( 0xd800 ),unichr( 0xdbff ),unichr( 0xdc00 ),unichr( 0xdfff ),unichr( 0xd800 ),unichr( 0xdbff ),unichr( 0xdc00 ),unichr( 0xdfff ) )
239 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
240 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
241 # response = re.sub( r"\[\d+\;1H", "\n", response )
242 response = re.sub( r"\[\d+\;\d+H", "", response )
adminbae64d82013-08-01 10:50:15 -0700243 return response
adminbae64d82013-08-01 10:50:15 -0700244
kelvin8ec71442015-01-15 16:57:00 -0800245 def runAsSudoUser( self, handle, pwd, default ):
246
247 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
248 if i == 0:
249 handle.sendline( pwd )
Jon Hall5ec6b1b2015-09-17 18:20:14 -0700250 handle.sendline( "\n" )
kelvin8ec71442015-01-15 16:57:00 -0800251
252 if i == 1:
253 handle.expect( default )
254
255 if i == 2:
256 main.log.error( "Unable to run as Sudo user" )
257
adminbae64d82013-08-01 10:50:15 -0700258 return handle
adminbae64d82013-08-01 10:50:15 -0700259
kelvin8ec71442015-01-15 16:57:00 -0800260 def onfail( self ):
261 if 'onfail' in main.componentDictionary[ self.name ]:
262 commandList = main.componentDictionary[
263 self.name ][ 'onfail' ].split( "," )
264 for command in commandList:
265 response = self.execute(
266 cmd=command,
267 prompt="(.*)",
268 timeout=120 )
adminbae64d82013-08-01 10:50:15 -0700269
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700270 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
271 direction="from" ):
kelvin8ec71442015-01-15 16:57:00 -0800272 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700273 Definition:
274 Execute scp command in linux to copy to/from a remote host
275 Required:
276 str userName - User name of the remote host
277 str ipAddress - IP address of the remote host
278 str filePath - File path including the file it self
279 str dstPath - Destination path
280 Optional:
281 str pwd - Password of the host
282 str direction - Direction of the scp, default to "from" which means
283 copy "from" the remote machine to local machine,
284 while "to" means copy "to" the remote machine from
285 local machine
kelvin8ec71442015-01-15 16:57:00 -0800286 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700287 returnVal = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700288 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -0800289 refused = "ssh: connect to host " + \
Jon Hall547e0582015-09-21 17:35:40 -0700290 ipAddress + " port 22: Connection refused"
acsmars07f9d392015-07-15 10:30:58 -0700291
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700292 if direction == "from":
293 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
Jon Hall547e0582015-09-21 17:35:40 -0700294 str( filePath ) + ' ' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700295 elif direction == "to":
296 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
Jon Hall547e0582015-09-21 17:35:40 -0700297 '@' + str( ipAddress ) + ':' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700298 else:
299 main.log.debug( "Wrong direction using secure copy command!" )
300 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800301
302 main.log.info( "Sending: " + cmd )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700303 self.handle.sendline( cmd )
Jon Hall547e0582015-09-21 17:35:40 -0700304 i = 0
305 while i < 2:
306 i = self.handle.expect( [
307 ssh_newkey,
308 'password:',
309 "100%",
310 refused,
311 "No such file or directory",
Jon Hall53c5e662016-04-13 16:06:56 -0700312 "Permission denied",
Devin Limdc78e202017-06-09 18:30:07 -0700313 self.prompt,
Jon Hall547e0582015-09-21 17:35:40 -0700314 pexpect.EOF,
315 pexpect.TIMEOUT ],
316 120 )
Jon Hall547e0582015-09-21 17:35:40 -0700317 if i == 0: # ask for ssh key confirmation
318 main.log.info( "ssh key confirmation received, sending yes" )
319 self.handle.sendline( 'yes' )
320 elif i == 1: # Asked for ssh password
321 main.log.info( "ssh connection asked for password, gave password" )
322 self.handle.sendline( pwd )
323 elif i == 2: # File finished transfering
324 main.log.info( "Secure copy successful" )
325 returnVal = main.TRUE
326 elif i == 3: # Connection refused
327 main.log.error(
328 "ssh: connect to host " +
329 ipAddress +
330 " port 22: Connection refused" )
331 returnVal = main.FALSE
332 elif i == 4: # File Not found
333 main.log.error( "No such file found" )
334 returnVal = main.FALSE
Jon Hall53c5e662016-04-13 16:06:56 -0700335 elif i == 5: # Permission denied
336 main.log.error( "Permission denied. Check folder permissions" )
337 returnVal = main.FALSE
338 elif i == 6: # prompt returned
Jon Hall4173b242017-09-12 17:04:38 -0700339 return returnVal
Jon Hall53c5e662016-04-13 16:06:56 -0700340 elif i == 7: # EOF
Jon Hall547e0582015-09-21 17:35:40 -0700341 main.log.error( "Pexpect.EOF found!!!" )
Devin Lim44075962017-08-11 10:56:37 -0700342 main.cleanAndExit()
Jon Hall53c5e662016-04-13 16:06:56 -0700343 elif i == 8: # timeout
Jon Hall547e0582015-09-21 17:35:40 -0700344 main.log.error(
345 "No route to the Host " +
346 userName +
347 "@" +
348 ipAddress )
349 returnVal = main.FALSE
Devin Limdc78e202017-06-09 18:30:07 -0700350 self.handle.expect( self.prompt )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700351 return returnVal
352
353 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
354 """
355 Definition:
356 Execute scp command in linux to copy to/from a remote host
357 Required:
358 * remoteHost - Test ON component to be parsed
359 str filePath - File path including the file it self
360 str dstPath - Destination path
361 Optional:
362 str direction - Direction of the scp, default to "from" which means
363 copy "from" the remote machine to local machine,
364 while "to" means copy "to" the remote machine from
365 local machine
366 """
367 return self.secureCopy( remoteHost.user_name,
368 remoteHost.ip_address,
369 filePath,
370 dstPath,
371 pwd=remoteHost.pwd,
372 direction=direction )
Devin Lim142b5342017-07-20 15:22:39 -0700373
374 def sshToNode( self, ipAddress, uName="sdn", pwd="rocks" ):
375 ssh_newkey = 'Are you sure you want to continue connecting'
376 refused = "ssh: connect to host " + ipAddress + " port 22: Connection refused"
377 handle = pexpect.spawn( 'ssh -X ' +
378 uName +
379 '@' +
380 ipAddress,
Jon Hall6c9e2da2018-11-06 12:01:23 -0800381 env={ "TERM": "vt100" },
Devin Lim142b5342017-07-20 15:22:39 -0700382 maxread=1000000,
383 timeout=60 )
384
385 # set tty window size
386 handle.setwinsize( 24, 250 )
387
388 i = 5
389 while i == 5:
Jon Hall4173b242017-09-12 17:04:38 -0700390 i = handle.expect( [ ssh_newkey,
391 'password:|Password:',
392 pexpect.EOF,
393 pexpect.TIMEOUT,
394 refused,
395 'teston>',
396 self.prompt ],
397 120 )
Devin Lim142b5342017-07-20 15:22:39 -0700398 if i == 0: # Accept key, then expect either a password prompt or access
399 main.log.info( "ssh key confirmation received, send yes" )
400 handle.sendline( 'yes' )
401 i = 5 # Run the loop again
402 continue
403 if i == 1: # Password required
404 if pwd:
405 main.log.info(
Jon Hall4173b242017-09-12 17:04:38 -0700406 "ssh connection asked for password, gave password" )
Devin Lim142b5342017-07-20 15:22:39 -0700407 else:
408 main.log.info( "Server asked for password, but none was "
409 "given in the .topo file. Trying "
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700410 "no password." )
Devin Lim142b5342017-07-20 15:22:39 -0700411 pwd = ""
412 handle.sendline( pwd )
413 j = handle.expect( [ self.prompt,
414 'password:|Password:',
415 pexpect.EOF,
416 pexpect.TIMEOUT ],
417 120 )
418 if j != 0:
419 main.log.error( "Incorrect Password" )
Devin Lim44075962017-08-11 10:56:37 -0700420 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700421 elif i == 2:
422 main.log.error( "Connection timeout" )
Devin Lim44075962017-08-11 10:56:37 -0700423 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700424 elif i == 3: # timeout
425 main.log.error(
426 "No route to the Host " +
427 uName +
428 "@" +
429 ipAddress )
Devin Lim44075962017-08-11 10:56:37 -0700430 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700431 elif i == 4:
432 main.log.error(
433 "ssh: connect to host " +
434 ipAddress +
435 " port 22: Connection refused" )
Devin Lim44075962017-08-11 10:56:37 -0700436 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700437 elif i == 6:
438 main.log.info( "Password not required logged in" )
439
440 handle.sendline( "" )
441 handle.expect( self.prompt )
442 handle.sendline( "cd" )
443 handle.expect( self.prompt )
444
Jon Hall4173b242017-09-12 17:04:38 -0700445 main.log.info( "Successfully ssh to " + ipAddress + "." )
Devin Lim142b5342017-07-20 15:22:39 -0700446 return handle
447
448 def exitFromSsh( self, handle, ipAddress ):
Devin Lim142b5342017-07-20 15:22:39 -0700449 try:
Jon Hall4f360bc2017-09-07 10:19:52 -0700450 handle.sendline( "logout" )
Devin Lim142b5342017-07-20 15:22:39 -0700451 handle.expect( "closed." )
Jon Hall4173b242017-09-12 17:04:38 -0700452 main.log.info( "Successfully closed ssh connection from " + ipAddress )
Devin Lim142b5342017-07-20 15:22:39 -0700453 except pexpect.EOF:
454 main.log.error( "Failed to close the connection from " + ipAddress )
Jon Hall4f360bc2017-09-07 10:19:52 -0700455 try:
456 # check that this component handle still works
457 self.handle.sendline( "" )
458 self.handle.expect( self.prompt )
459 except pexpect.EOF:
460 main.log.error( self.handle.before )
461 main.log.error( "EOF after closing ssh connection" )
Jon Hall4173b242017-09-12 17:04:38 -0700462
463 def folderSize( self, path, size='10', unit='M', ignoreRoot=True ):
464 """
465 Run `du -h` on the folder path and verifies the folder(s) size is
466 less than the given size. Note that if multiple subdirectories are
467 present, the result will be the OR of all the individual subdirectories.
468
469 Arguments:
470 path - A string containing the path supplied to the du command
471 size - The number portion of the file size that the results will be compared to
472 unit - The unit portion of the file size that the results will be compared to
473 ignoreRoot - If True, will ignore the "root" of the path supplied to du. I.E. will ignore `.`
474
475 Returns True if the folder(s) size(s) are less than SIZE UNITS, else returns False
476 """
477 sizeRe = r'(?P<number>\d+\.*\d*)(?P<unit>\D)'
478 unitsList = [ 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ]
479 try:
480 # make sure we convert units if size is too big
481 size = float( size )
482 if size >= 1000:
483 size = size / 1000
484 unit = unitsList[ unitsList.index( unit + 1 ) ]
485 cmdStr = "du -h " + path
486 self.handle.sendline( cmdStr )
487 self.handle.expect( self.prompt )
488 output = self.handle.before
489 assert "cannot access" not in output
490 assert "command not found" not in output
491 main.log.debug( output )
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700492 lines = [ line for line in output.split( '\r\n' ) ]
Jon Hall4173b242017-09-12 17:04:38 -0700493 retValue = True
494 if ignoreRoot:
495 lastIndex = -2
496 else:
497 lastIndex = -1
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700498 for line in lines[ 1:lastIndex ]:
Jon Hall4173b242017-09-12 17:04:38 -0700499 parsed = line.split()
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700500 sizeMatch = parsed[ 0 ]
501 folder = parsed[ 1 ]
Jon Hall4173b242017-09-12 17:04:38 -0700502 match = re.search( sizeRe, sizeMatch )
503 num = match.group( 'number' )
504 unitMatch = match.group( 'unit' )
505 if unitsList.index( unitMatch ) < unitsList.index( unit ):
506 retValue &= True
507 elif unitsList.index( unitMatch ) == unitsList.index( unit ):
508 if float( num ) < float( size ):
509 retValue &= True
510 else:
511 retValue &= False
512 elif unitsList.index( unitMatch ) > unitsList.index( unit ):
513 retValue &= False
514 return retValue
515 except AssertionError:
516 main.log.error( self.name + ": Could not execute command: " + output )
517 return False
Jon Hall43060f62020-06-23 13:13:33 -0700518 except ValueError as e:
519 main.log.error( self.name + ": Error parsing output: " + output )
520 main.log.error( e )
521 return False
Jon Hall4173b242017-09-12 17:04:38 -0700522 except pexpect.TIMEOUT:
523 main.log.exception( self.name + ": TIMEOUT exception found" )
524 main.log.error( self.name + ": " + self.handle.before )
525 return False
526 except pexpect.EOF:
527 main.log.error( self.name + ": EOF exception found" )
528 main.log.error( self.name + ": " + self.handle.before )
529 main.cleanAndExit()
Jon Hall0e240372018-05-02 11:21:57 -0700530
531 def setEnv( self, variable, value=None ):
532 """
533 Sets the environment variable to the given value for the current shell session.
534 If value is None, will unset the variable.
535
536 Required Arguments:
537 variable - The name of the environment variable to set.
538
539 Optional Arguments:
540 value - The value to set the variable to. ( Defaults to None, which unsets the variable )
541
542 Returns True if no errors are detected else returns False
543 """
544 try:
545 if value:
546 cmd = "export {}={}".format( variable, value )
547 else:
548 cmd = "unset {}".format( variable )
549 self.handle.sendline( cmd )
550 self.handle.expect( self.prompt )
551 main.log.debug( self.handle.before )
552 return True
553 except AssertionError:
554 main.log.error( self.name + ": Could not execute command: " + output )
555 return False
556 except pexpect.TIMEOUT:
557 main.log.exception( self.name + ": TIMEOUT exception found" )
558 main.log.error( self.name + ": " + self.handle.before )
559 return False
560 except pexpect.EOF:
561 main.log.error( self.name + ": EOF exception found" )
562 main.log.error( self.name + ": " + self.handle.before )
563 main.cleanAndExit()
You Wangb65d2372018-08-17 15:37:59 -0700564
565 def exitFromCmd( self, expect, retry=10 ):
566 """
567 Call this function when sending ctrl+c is required to kill the current
568 command. It will retry multiple times until the running command is
569 completely killed and expected string is returned from the handle.
570 Required:
You Wangd4fae5c2018-08-22 13:56:49 -0700571 expect: expected string or list of strings which indicates that the
572 previous command was killed successfully.
You Wangb65d2372018-08-17 15:37:59 -0700573 Optional:
574 retry: maximum number of ctrl+c that will be sent.
575 """
You Wangd4fae5c2018-08-22 13:56:49 -0700576 expect = [ expect ] if isinstance( expect, str ) else expect
You Wangb65d2372018-08-17 15:37:59 -0700577 try:
578 while retry >= 0:
579 main.log.debug( self.name + ": sending ctrl+c to kill the command" )
580 self.handle.send( "\x03" )
You Wangd4fae5c2018-08-22 13:56:49 -0700581 i = self.handle.expect( expect + [ pexpect.TIMEOUT ], timeout=3 )
You Wangb65d2372018-08-17 15:37:59 -0700582 main.log.debug( self.handle.before )
You Wangd4fae5c2018-08-22 13:56:49 -0700583 if i < len( expect ):
You Wangb65d2372018-08-17 15:37:59 -0700584 main.log.debug( self.name + ": successfully killed the command" )
585 return main.TRUE
586 retry -= 1
587 main.log.warn( self.name + ": failed to kill the command" )
588 return main.FALSE
589 except pexpect.EOF:
590 main.log.error( self.name + ": EOF exception found" )
591 main.log.error( self.name + ": " + self.handle.before )
592 return main.FALSE
593 except Exception:
594 main.log.exception( self.name + ": Uncaught exception!" )
595 return main.FALSE
Jon Hall43060f62020-06-23 13:13:33 -0700596
597 def cleanOutput( self, output, debug=False ):
598 """
599 Clean ANSI characters from output
600 """
601 ansiEscape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
602 cleaned = ansiEscape.sub( '', output )
603 if debug:
604 main.log.debug( self.name + ": cleanOutput:" )
605 main.log.debug( self.name + ": " + repr( cleaned ) )
606 return cleaned