blob: 81b33b2c60c884314479be3d53d52db9b5445fc8 [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.
159
160 It will return output of command exection.
kelvin8ec71442015-01-15 16:57:00 -0800161 """
162 result = super( CLI, self ).execute( self )
adminaef00552014-05-08 09:18:36 -0700163 defaultPrompt = '.*[$>\#]'
Jon Hall3b489db2015-10-05 14:38:37 -0700164 args = utilities.parse_args( [ "CMD",
165 "TIMEOUT",
166 "PROMPT",
167 "MORE" ],
168 **execparams )
kelvin8ec71442015-01-15 16:57:00 -0800169
170 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
adminbae64d82013-08-01 10:50:15 -0700171 self.LASTRSP = ""
kelvin8ec71442015-01-15 16:57:00 -0800172 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
adminbae64d82013-08-01 10:50:15 -0700173 cmd = ''
kelvin8ec71442015-01-15 16:57:00 -0800174 if args[ "CMD" ]:
175 cmd = args[ "CMD" ]
176 else:
adminbae64d82013-08-01 10:50:15 -0700177 return 0
kelvin8ec71442015-01-15 16:57:00 -0800178 if args[ "MORE" ] is None:
179 args[ "MORE" ] = " "
180 self.handle.sendline( cmd )
adminbae64d82013-08-01 10:50:15 -0700181 self.lastCommand = cmd
Jon Hall3b489db2015-10-05 14:38:37 -0700182 index = self.handle.expect( [ expectPrompt,
183 "--More--",
184 'Command not found.',
185 pexpect.TIMEOUT,
186 "^:$" ],
187 timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700188 if index == 0:
kelvin8ec71442015-01-15 16:57:00 -0800189 self.LASTRSP = self.LASTRSP + \
190 self.handle.before + self.handle.after
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700191 main.log.info( "Executed :" + str( cmd ) +
192 " \t\t Expected Prompt '" + str( expectPrompt ) +
Jon Hall3b489db2015-10-05 14:38:37 -0700193 "' Found" )
adminbae64d82013-08-01 10:50:15 -0700194 elif index == 1:
195 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800196 self.handle.send( args[ "MORE" ] )
197 main.log.info(
198 "Found More screen to go , Sending a key to proceed" )
199 indexMore = self.handle.expect(
200 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700201 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800202 main.log.info(
203 "Found anoother More screen to go , Sending a key to proceed" )
204 self.handle.send( args[ "MORE" ] )
205 indexMore = self.handle.expect(
206 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700207 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800208 elif index == 2:
209 main.log.error( "Command not found" )
adminbae64d82013-08-01 10:50:15 -0700210 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800211 elif index == 3:
Jon Hall3b489db2015-10-05 14:38:37 -0700212 main.log.error( "Expected Prompt not found, Time Out!!" )
kelvin8ec71442015-01-15 16:57:00 -0800213 main.log.error( expectPrompt )
Jon Hall3b489db2015-10-05 14:38:37 -0700214 self.LASTRSP = self.LASTRSP + self.handle.before
215 return self.LASTRSP
adminbae64d82013-08-01 10:50:15 -0700216 elif index == 4:
217 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800218 # self.handle.send( args[ "MORE" ] )
219 self.handle.sendcontrol( "D" )
220 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700221 "Found More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800222 indexMore = self.handle.expect(
223 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700224 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800225 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700226 "Found another More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800227 self.handle.sendcontrol( "D" )
228 indexMore = self.handle.expect(
229 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700230 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800231 main.last_response = self.remove_contol_chars( self.LASTRSP )
adminbae64d82013-08-01 10:50:15 -0700232 return self.LASTRSP
kelvin8ec71442015-01-15 16:57:00 -0800233
234 def remove_contol_chars( self, response ):
235 # 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 ) )
236 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
237 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
238 # response = re.sub( r"\[\d+\;1H", "\n", response )
239 response = re.sub( r"\[\d+\;\d+H", "", response )
adminbae64d82013-08-01 10:50:15 -0700240 return response
adminbae64d82013-08-01 10:50:15 -0700241
kelvin8ec71442015-01-15 16:57:00 -0800242 def runAsSudoUser( self, handle, pwd, default ):
243
244 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
245 if i == 0:
246 handle.sendline( pwd )
Jon Hall5ec6b1b2015-09-17 18:20:14 -0700247 handle.sendline( "\n" )
kelvin8ec71442015-01-15 16:57:00 -0800248
249 if i == 1:
250 handle.expect( default )
251
252 if i == 2:
253 main.log.error( "Unable to run as Sudo user" )
254
adminbae64d82013-08-01 10:50:15 -0700255 return handle
adminbae64d82013-08-01 10:50:15 -0700256
kelvin8ec71442015-01-15 16:57:00 -0800257 def onfail( self ):
258 if 'onfail' in main.componentDictionary[ self.name ]:
259 commandList = main.componentDictionary[
260 self.name ][ 'onfail' ].split( "," )
261 for command in commandList:
262 response = self.execute(
263 cmd=command,
264 prompt="(.*)",
265 timeout=120 )
adminbae64d82013-08-01 10:50:15 -0700266
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700267 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
268 direction="from" ):
kelvin8ec71442015-01-15 16:57:00 -0800269 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700270 Definition:
271 Execute scp command in linux to copy to/from a remote host
272 Required:
273 str userName - User name of the remote host
274 str ipAddress - IP address of the remote host
275 str filePath - File path including the file it self
276 str dstPath - Destination path
277 Optional:
278 str pwd - Password of the host
279 str direction - Direction of the scp, default to "from" which means
280 copy "from" the remote machine to local machine,
281 while "to" means copy "to" the remote machine from
282 local machine
kelvin8ec71442015-01-15 16:57:00 -0800283 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700284 returnVal = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700285 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -0800286 refused = "ssh: connect to host " + \
Jon Hall547e0582015-09-21 17:35:40 -0700287 ipAddress + " port 22: Connection refused"
acsmars07f9d392015-07-15 10:30:58 -0700288
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700289 if direction == "from":
290 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
Jon Hall547e0582015-09-21 17:35:40 -0700291 str( filePath ) + ' ' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700292 elif direction == "to":
293 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
Jon Hall547e0582015-09-21 17:35:40 -0700294 '@' + str( ipAddress ) + ':' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700295 else:
296 main.log.debug( "Wrong direction using secure copy command!" )
297 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800298
299 main.log.info( "Sending: " + cmd )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700300 self.handle.sendline( cmd )
Jon Hall547e0582015-09-21 17:35:40 -0700301 i = 0
302 while i < 2:
303 i = self.handle.expect( [
304 ssh_newkey,
305 'password:',
306 "100%",
307 refused,
308 "No such file or directory",
Jon Hall53c5e662016-04-13 16:06:56 -0700309 "Permission denied",
Devin Limdc78e202017-06-09 18:30:07 -0700310 self.prompt,
Jon Hall547e0582015-09-21 17:35:40 -0700311 pexpect.EOF,
312 pexpect.TIMEOUT ],
313 120 )
Jon Hall547e0582015-09-21 17:35:40 -0700314 if i == 0: # ask for ssh key confirmation
315 main.log.info( "ssh key confirmation received, sending yes" )
316 self.handle.sendline( 'yes' )
317 elif i == 1: # Asked for ssh password
318 main.log.info( "ssh connection asked for password, gave password" )
319 self.handle.sendline( pwd )
320 elif i == 2: # File finished transfering
321 main.log.info( "Secure copy successful" )
322 returnVal = main.TRUE
323 elif i == 3: # Connection refused
324 main.log.error(
325 "ssh: connect to host " +
326 ipAddress +
327 " port 22: Connection refused" )
328 returnVal = main.FALSE
329 elif i == 4: # File Not found
330 main.log.error( "No such file found" )
331 returnVal = main.FALSE
Jon Hall53c5e662016-04-13 16:06:56 -0700332 elif i == 5: # Permission denied
333 main.log.error( "Permission denied. Check folder permissions" )
334 returnVal = main.FALSE
335 elif i == 6: # prompt returned
Jon Hall4173b242017-09-12 17:04:38 -0700336 return returnVal
Jon Hall53c5e662016-04-13 16:06:56 -0700337 elif i == 7: # EOF
Jon Hall547e0582015-09-21 17:35:40 -0700338 main.log.error( "Pexpect.EOF found!!!" )
Devin Lim44075962017-08-11 10:56:37 -0700339 main.cleanAndExit()
Jon Hall53c5e662016-04-13 16:06:56 -0700340 elif i == 8: # timeout
Jon Hall547e0582015-09-21 17:35:40 -0700341 main.log.error(
342 "No route to the Host " +
343 userName +
344 "@" +
345 ipAddress )
346 returnVal = main.FALSE
Devin Limdc78e202017-06-09 18:30:07 -0700347 self.handle.expect( self.prompt )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700348 return returnVal
349
350 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
351 """
352 Definition:
353 Execute scp command in linux to copy to/from a remote host
354 Required:
355 * remoteHost - Test ON component to be parsed
356 str filePath - File path including the file it self
357 str dstPath - Destination path
358 Optional:
359 str direction - Direction of the scp, default to "from" which means
360 copy "from" the remote machine to local machine,
361 while "to" means copy "to" the remote machine from
362 local machine
363 """
364 return self.secureCopy( remoteHost.user_name,
365 remoteHost.ip_address,
366 filePath,
367 dstPath,
368 pwd=remoteHost.pwd,
369 direction=direction )
Devin Lim142b5342017-07-20 15:22:39 -0700370
371 def sshToNode( self, ipAddress, uName="sdn", pwd="rocks" ):
372 ssh_newkey = 'Are you sure you want to continue connecting'
373 refused = "ssh: connect to host " + ipAddress + " port 22: Connection refused"
374 handle = pexpect.spawn( 'ssh -X ' +
375 uName +
376 '@' +
377 ipAddress,
Jon Hall6c9e2da2018-11-06 12:01:23 -0800378 env={ "TERM": "vt100" },
Devin Lim142b5342017-07-20 15:22:39 -0700379 maxread=1000000,
380 timeout=60 )
381
382 # set tty window size
383 handle.setwinsize( 24, 250 )
384
385 i = 5
386 while i == 5:
Jon Hall4173b242017-09-12 17:04:38 -0700387 i = handle.expect( [ ssh_newkey,
388 'password:|Password:',
389 pexpect.EOF,
390 pexpect.TIMEOUT,
391 refused,
392 'teston>',
393 self.prompt ],
394 120 )
Devin Lim142b5342017-07-20 15:22:39 -0700395 if i == 0: # Accept key, then expect either a password prompt or access
396 main.log.info( "ssh key confirmation received, send yes" )
397 handle.sendline( 'yes' )
398 i = 5 # Run the loop again
399 continue
400 if i == 1: # Password required
401 if pwd:
402 main.log.info(
Jon Hall4173b242017-09-12 17:04:38 -0700403 "ssh connection asked for password, gave password" )
Devin Lim142b5342017-07-20 15:22:39 -0700404 else:
405 main.log.info( "Server asked for password, but none was "
406 "given in the .topo file. Trying "
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700407 "no password." )
Devin Lim142b5342017-07-20 15:22:39 -0700408 pwd = ""
409 handle.sendline( pwd )
410 j = handle.expect( [ self.prompt,
411 'password:|Password:',
412 pexpect.EOF,
413 pexpect.TIMEOUT ],
414 120 )
415 if j != 0:
416 main.log.error( "Incorrect Password" )
Devin Lim44075962017-08-11 10:56:37 -0700417 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700418 elif i == 2:
419 main.log.error( "Connection timeout" )
Devin Lim44075962017-08-11 10:56:37 -0700420 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700421 elif i == 3: # timeout
422 main.log.error(
423 "No route to the Host " +
424 uName +
425 "@" +
426 ipAddress )
Devin Lim44075962017-08-11 10:56:37 -0700427 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700428 elif i == 4:
429 main.log.error(
430 "ssh: connect to host " +
431 ipAddress +
432 " port 22: Connection refused" )
Devin Lim44075962017-08-11 10:56:37 -0700433 main.cleanAndExit()
Devin Lim142b5342017-07-20 15:22:39 -0700434 elif i == 6:
435 main.log.info( "Password not required logged in" )
436
437 handle.sendline( "" )
438 handle.expect( self.prompt )
439 handle.sendline( "cd" )
440 handle.expect( self.prompt )
441
Jon Hall4173b242017-09-12 17:04:38 -0700442 main.log.info( "Successfully ssh to " + ipAddress + "." )
Devin Lim142b5342017-07-20 15:22:39 -0700443 return handle
444
445 def exitFromSsh( self, handle, ipAddress ):
Devin Lim142b5342017-07-20 15:22:39 -0700446 try:
Jon Hall4f360bc2017-09-07 10:19:52 -0700447 handle.sendline( "logout" )
Devin Lim142b5342017-07-20 15:22:39 -0700448 handle.expect( "closed." )
Jon Hall4173b242017-09-12 17:04:38 -0700449 main.log.info( "Successfully closed ssh connection from " + ipAddress )
Devin Lim142b5342017-07-20 15:22:39 -0700450 except pexpect.EOF:
451 main.log.error( "Failed to close the connection from " + ipAddress )
Jon Hall4f360bc2017-09-07 10:19:52 -0700452 try:
453 # check that this component handle still works
454 self.handle.sendline( "" )
455 self.handle.expect( self.prompt )
456 except pexpect.EOF:
457 main.log.error( self.handle.before )
458 main.log.error( "EOF after closing ssh connection" )
Jon Hall4173b242017-09-12 17:04:38 -0700459
460 def folderSize( self, path, size='10', unit='M', ignoreRoot=True ):
461 """
462 Run `du -h` on the folder path and verifies the folder(s) size is
463 less than the given size. Note that if multiple subdirectories are
464 present, the result will be the OR of all the individual subdirectories.
465
466 Arguments:
467 path - A string containing the path supplied to the du command
468 size - The number portion of the file size that the results will be compared to
469 unit - The unit portion of the file size that the results will be compared to
470 ignoreRoot - If True, will ignore the "root" of the path supplied to du. I.E. will ignore `.`
471
472 Returns True if the folder(s) size(s) are less than SIZE UNITS, else returns False
473 """
474 sizeRe = r'(?P<number>\d+\.*\d*)(?P<unit>\D)'
475 unitsList = [ 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ]
476 try:
477 # make sure we convert units if size is too big
478 size = float( size )
479 if size >= 1000:
480 size = size / 1000
481 unit = unitsList[ unitsList.index( unit + 1 ) ]
482 cmdStr = "du -h " + path
483 self.handle.sendline( cmdStr )
484 self.handle.expect( self.prompt )
485 output = self.handle.before
486 assert "cannot access" not in output
487 assert "command not found" not in output
488 main.log.debug( output )
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700489 lines = [ line for line in output.split( '\r\n' ) ]
Jon Hall4173b242017-09-12 17:04:38 -0700490 retValue = True
491 if ignoreRoot:
492 lastIndex = -2
493 else:
494 lastIndex = -1
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700495 for line in lines[ 1:lastIndex ]:
Jon Hall4173b242017-09-12 17:04:38 -0700496 parsed = line.split()
Jeremy Ronquillo82705492017-10-18 14:19:55 -0700497 sizeMatch = parsed[ 0 ]
498 folder = parsed[ 1 ]
Jon Hall4173b242017-09-12 17:04:38 -0700499 match = re.search( sizeRe, sizeMatch )
500 num = match.group( 'number' )
501 unitMatch = match.group( 'unit' )
502 if unitsList.index( unitMatch ) < unitsList.index( unit ):
503 retValue &= True
504 elif unitsList.index( unitMatch ) == unitsList.index( unit ):
505 if float( num ) < float( size ):
506 retValue &= True
507 else:
508 retValue &= False
509 elif unitsList.index( unitMatch ) > unitsList.index( unit ):
510 retValue &= False
511 return retValue
512 except AssertionError:
513 main.log.error( self.name + ": Could not execute command: " + output )
514 return False
515 except pexpect.TIMEOUT:
516 main.log.exception( self.name + ": TIMEOUT exception found" )
517 main.log.error( self.name + ": " + self.handle.before )
518 return False
519 except pexpect.EOF:
520 main.log.error( self.name + ": EOF exception found" )
521 main.log.error( self.name + ": " + self.handle.before )
522 main.cleanAndExit()
Jon Hall0e240372018-05-02 11:21:57 -0700523
524 def setEnv( self, variable, value=None ):
525 """
526 Sets the environment variable to the given value for the current shell session.
527 If value is None, will unset the variable.
528
529 Required Arguments:
530 variable - The name of the environment variable to set.
531
532 Optional Arguments:
533 value - The value to set the variable to. ( Defaults to None, which unsets the variable )
534
535 Returns True if no errors are detected else returns False
536 """
537 try:
538 if value:
539 cmd = "export {}={}".format( variable, value )
540 else:
541 cmd = "unset {}".format( variable )
542 self.handle.sendline( cmd )
543 self.handle.expect( self.prompt )
544 main.log.debug( self.handle.before )
545 return True
546 except AssertionError:
547 main.log.error( self.name + ": Could not execute command: " + output )
548 return False
549 except pexpect.TIMEOUT:
550 main.log.exception( self.name + ": TIMEOUT exception found" )
551 main.log.error( self.name + ": " + self.handle.before )
552 return False
553 except pexpect.EOF:
554 main.log.error( self.name + ": EOF exception found" )
555 main.log.error( self.name + ": " + self.handle.before )
556 main.cleanAndExit()
You Wangb65d2372018-08-17 15:37:59 -0700557
558 def exitFromCmd( self, expect, retry=10 ):
559 """
560 Call this function when sending ctrl+c is required to kill the current
561 command. It will retry multiple times until the running command is
562 completely killed and expected string is returned from the handle.
563 Required:
You Wangd4fae5c2018-08-22 13:56:49 -0700564 expect: expected string or list of strings which indicates that the
565 previous command was killed successfully.
You Wangb65d2372018-08-17 15:37:59 -0700566 Optional:
567 retry: maximum number of ctrl+c that will be sent.
568 """
You Wangd4fae5c2018-08-22 13:56:49 -0700569 expect = [ expect ] if isinstance( expect, str ) else expect
You Wangb65d2372018-08-17 15:37:59 -0700570 try:
571 while retry >= 0:
572 main.log.debug( self.name + ": sending ctrl+c to kill the command" )
573 self.handle.send( "\x03" )
You Wangd4fae5c2018-08-22 13:56:49 -0700574 i = self.handle.expect( expect + [ pexpect.TIMEOUT ], timeout=3 )
You Wangb65d2372018-08-17 15:37:59 -0700575 main.log.debug( self.handle.before )
You Wangd4fae5c2018-08-22 13:56:49 -0700576 if i < len( expect ):
You Wangb65d2372018-08-17 15:37:59 -0700577 main.log.debug( self.name + ": successfully killed the command" )
578 return main.TRUE
579 retry -= 1
580 main.log.warn( self.name + ": failed to kill the command" )
581 return main.FALSE
582 except pexpect.EOF:
583 main.log.error( self.name + ": EOF exception found" )
584 main.log.error( self.name + ": " + self.handle.before )
585 return main.FALSE
586 except Exception:
587 main.log.exception( self.name + ": Uncaught exception!" )
588 return main.FALSE