blob: aa8a12e0fe3665605b9f3849f31257c2de417f6e [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 Ronquillob27ce4c2017-07-17 12:41:28 -07004Copyright 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
kelvin8ec71442015-01-15 16:57:00 -080013 ( 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
Devin Limdc78e202017-06-09 18:30:07 -070037 def checkPrompt(self):
38 for key in self.options:
39 if key == "prompt" and self.options['prompt'] is not None:
40 self.prompt = self.options['prompt']
41 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(
59 'ssh -p ' +
60 self.port +
61 ' ' +
62 self.user_name +
63 '@' +
64 self.ip_address,
Jon Hall9aaba882015-01-19 15:05:15 -080065 env={ "TERM": "xterm-mono" },
kelvin8ec71442015-01-15 16:57:00 -080066 maxread=50000 )
67 else:
68 self.handle = pexpect.spawn(
69 'ssh -X ' +
70 self.user_name +
71 '@' +
72 self.ip_address,
Jon Hall9aaba882015-01-19 15:05:15 -080073 env={ "TERM": "xterm-mono" },
kelvin8ec71442015-01-15 16:57:00 -080074 maxread=1000000,
75 timeout=60 )
adminbae64d82013-08-01 10:50:15 -070076
Jon Hall73057ee2016-08-23 09:57:26 -070077 # set tty window size
78 self.handle.setwinsize( 24, 250 )
79
adminbae64d82013-08-01 10:50:15 -070080 self.handle.logfile = self.logfile_handler
kelvin8ec71442015-01-15 16:57:00 -080081 i = 5
82 while i == 5:
83 i = self.handle.expect( [
acsmarse2be32c2015-06-29 16:16:28 -070084 ssh_newkey,
Jon Hall05f88682015-06-09 14:57:53 -070085 'password:|Password:',
kelvin8ec71442015-01-15 16:57:00 -080086 pexpect.EOF,
87 pexpect.TIMEOUT,
88 refused,
89 'teston>',
Devin Limdc78e202017-06-09 18:30:07 -070090 self.prompt ],
acsmars07f9d392015-07-15 10:30:58 -070091 120 )
acsmars32de0bc2015-06-30 09:57:12 -070092 if i == 0: # Accept key, then expect either a password prompt or access
kelvin8ec71442015-01-15 16:57:00 -080093 main.log.info( "ssh key confirmation received, send yes" )
94 self.handle.sendline( 'yes' )
acsmars32de0bc2015-06-30 09:57:12 -070095 i = 5 # Run the loop again
acsmars07f9d392015-07-15 10:30:58 -070096 continue
97 if i == 1: # Password required
Jon Hall63604932015-02-26 17:09:50 -080098 if self.pwd:
99 main.log.info(
acsmars07f9d392015-07-15 10:30:58 -0700100 "ssh connection asked for password, gave password" )
Jon Hall63604932015-02-26 17:09:50 -0800101 else:
acsmars07f9d392015-07-15 10:30:58 -0700102 main.log.info( "Server asked for password, but none was "
103 "given in the .topo file. Trying "
104 "no password.")
105 self.pwd = ""
106 self.handle.sendline( self.pwd )
107 j = self.handle.expect( [
Devin Limdc78e202017-06-09 18:30:07 -0700108 self.prompt,
acsmars07f9d392015-07-15 10:30:58 -0700109 'password:|Password:',
110 pexpect.EOF,
111 pexpect.TIMEOUT ],
112 120 )
113 if j != 0:
114 main.log.error( "Incorrect Password" )
115 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800116 elif i == 2:
117 main.log.error( "Connection timeout" )
118 return main.FALSE
119 elif i == 3: # timeout
120 main.log.error(
121 "No route to the Host " +
122 self.user_name +
123 "@" +
124 self.ip_address )
125 return main.FALSE
126 elif i == 4:
127 main.log.error(
128 "ssh: connect to host " +
129 self.ip_address +
130 " port 22: Connection refused" )
131 return main.FALSE
132 elif i == 6:
133 main.log.info( "Password not required logged in" )
adminbae64d82013-08-01 10:50:15 -0700134
kelvin8ec71442015-01-15 16:57:00 -0800135 self.handle.sendline( "" )
Devin Limdc78e202017-06-09 18:30:07 -0700136 self.handle.expect( self.prompt )
Jeremy Ronquillo0f2008a2017-06-23 15:32:51 -0700137 self.handle.sendline( "cd" )
138 self.handle.expect( self.prompt )
adminbae64d82013-08-01 10:50:15 -0700139 return self.handle
140
kelvin8ec71442015-01-15 16:57:00 -0800141 def disconnect( self ):
142 result = super( CLI, self ).disconnect( self )
adminbae64d82013-08-01 10:50:15 -0700143 result = main.TRUE
kelvin8ec71442015-01-15 16:57:00 -0800144 # self.execute( cmd="exit",timeout=120,prompt="(.*)" )
145
146 def execute( self, **execparams ):
147 """
adminbae64d82013-08-01 10:50:15 -0700148 It facilitates the command line execution of a given command. It has arguments as :
149 cmd => represents command to be executed,
150 prompt => represents expect command prompt or output,
151 timeout => timeout for command execution,
152 more => to provide a key press if it is on.
153
154 It will return output of command exection.
kelvin8ec71442015-01-15 16:57:00 -0800155 """
156 result = super( CLI, self ).execute( self )
adminaef00552014-05-08 09:18:36 -0700157 defaultPrompt = '.*[$>\#]'
Jon Hall3b489db2015-10-05 14:38:37 -0700158 args = utilities.parse_args( [ "CMD",
159 "TIMEOUT",
160 "PROMPT",
161 "MORE" ],
162 **execparams )
kelvin8ec71442015-01-15 16:57:00 -0800163
164 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
adminbae64d82013-08-01 10:50:15 -0700165 self.LASTRSP = ""
kelvin8ec71442015-01-15 16:57:00 -0800166 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
adminbae64d82013-08-01 10:50:15 -0700167 cmd = ''
kelvin8ec71442015-01-15 16:57:00 -0800168 if args[ "CMD" ]:
169 cmd = args[ "CMD" ]
170 else:
adminbae64d82013-08-01 10:50:15 -0700171 return 0
kelvin8ec71442015-01-15 16:57:00 -0800172 if args[ "MORE" ] is None:
173 args[ "MORE" ] = " "
174 self.handle.sendline( cmd )
adminbae64d82013-08-01 10:50:15 -0700175 self.lastCommand = cmd
Jon Hall3b489db2015-10-05 14:38:37 -0700176 index = self.handle.expect( [ expectPrompt,
177 "--More--",
178 'Command not found.',
179 pexpect.TIMEOUT,
180 "^:$" ],
181 timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700182 if index == 0:
kelvin8ec71442015-01-15 16:57:00 -0800183 self.LASTRSP = self.LASTRSP + \
184 self.handle.before + self.handle.after
Jon Hall3b489db2015-10-05 14:38:37 -0700185 main.log.info( "Executed :" + str(cmd ) +
186 " \t\t Expected Prompt '" + str( expectPrompt) +
187 "' Found" )
adminbae64d82013-08-01 10:50:15 -0700188 elif index == 1:
189 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800190 self.handle.send( args[ "MORE" ] )
191 main.log.info(
192 "Found More screen to go , Sending a key to proceed" )
193 indexMore = self.handle.expect(
194 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700195 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800196 main.log.info(
197 "Found anoother More screen to go , Sending a key to proceed" )
198 self.handle.send( args[ "MORE" ] )
199 indexMore = self.handle.expect(
200 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700201 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800202 elif index == 2:
203 main.log.error( "Command not found" )
adminbae64d82013-08-01 10:50:15 -0700204 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800205 elif index == 3:
Jon Hall3b489db2015-10-05 14:38:37 -0700206 main.log.error( "Expected Prompt not found, Time Out!!" )
kelvin8ec71442015-01-15 16:57:00 -0800207 main.log.error( expectPrompt )
Jon Hall3b489db2015-10-05 14:38:37 -0700208 self.LASTRSP = self.LASTRSP + self.handle.before
209 return self.LASTRSP
adminbae64d82013-08-01 10:50:15 -0700210 elif index == 4:
211 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800212 # self.handle.send( args[ "MORE" ] )
213 self.handle.sendcontrol( "D" )
214 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700215 "Found More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800216 indexMore = self.handle.expect(
217 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700218 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800219 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700220 "Found another More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800221 self.handle.sendcontrol( "D" )
222 indexMore = self.handle.expect(
223 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700224 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800225 main.last_response = self.remove_contol_chars( self.LASTRSP )
adminbae64d82013-08-01 10:50:15 -0700226 return self.LASTRSP
kelvin8ec71442015-01-15 16:57:00 -0800227
228 def remove_contol_chars( self, response ):
229 # 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 ) )
230 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
231 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
232 # response = re.sub( r"\[\d+\;1H", "\n", response )
233 response = re.sub( r"\[\d+\;\d+H", "", response )
adminbae64d82013-08-01 10:50:15 -0700234 return response
adminbae64d82013-08-01 10:50:15 -0700235
kelvin8ec71442015-01-15 16:57:00 -0800236 def runAsSudoUser( self, handle, pwd, default ):
237
238 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
239 if i == 0:
240 handle.sendline( pwd )
Jon Hall5ec6b1b2015-09-17 18:20:14 -0700241 handle.sendline( "\n" )
kelvin8ec71442015-01-15 16:57:00 -0800242
243 if i == 1:
244 handle.expect( default )
245
246 if i == 2:
247 main.log.error( "Unable to run as Sudo user" )
248
adminbae64d82013-08-01 10:50:15 -0700249 return handle
adminbae64d82013-08-01 10:50:15 -0700250
kelvin8ec71442015-01-15 16:57:00 -0800251 def onfail( self ):
252 if 'onfail' in main.componentDictionary[ self.name ]:
253 commandList = main.componentDictionary[
254 self.name ][ 'onfail' ].split( "," )
255 for command in commandList:
256 response = self.execute(
257 cmd=command,
258 prompt="(.*)",
259 timeout=120 )
adminbae64d82013-08-01 10:50:15 -0700260
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700261 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
262 direction="from" ):
kelvin8ec71442015-01-15 16:57:00 -0800263 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700264 Definition:
265 Execute scp command in linux to copy to/from a remote host
266 Required:
267 str userName - User name of the remote host
268 str ipAddress - IP address of the remote host
269 str filePath - File path including the file it self
270 str dstPath - Destination path
271 Optional:
272 str pwd - Password of the host
273 str direction - Direction of the scp, default to "from" which means
274 copy "from" the remote machine to local machine,
275 while "to" means copy "to" the remote machine from
276 local machine
kelvin8ec71442015-01-15 16:57:00 -0800277 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700278 returnVal = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700279 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -0800280 refused = "ssh: connect to host " + \
Jon Hall547e0582015-09-21 17:35:40 -0700281 ipAddress + " port 22: Connection refused"
acsmars07f9d392015-07-15 10:30:58 -0700282
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700283 if direction == "from":
284 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
Jon Hall547e0582015-09-21 17:35:40 -0700285 str( filePath ) + ' ' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700286 elif direction == "to":
287 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
Jon Hall547e0582015-09-21 17:35:40 -0700288 '@' + str( ipAddress ) + ':' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700289 else:
290 main.log.debug( "Wrong direction using secure copy command!" )
291 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800292
293 main.log.info( "Sending: " + cmd )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700294 self.handle.sendline( cmd )
Jon Hall547e0582015-09-21 17:35:40 -0700295 i = 0
296 while i < 2:
297 i = self.handle.expect( [
298 ssh_newkey,
299 'password:',
300 "100%",
301 refused,
302 "No such file or directory",
Jon Hall53c5e662016-04-13 16:06:56 -0700303 "Permission denied",
Devin Limdc78e202017-06-09 18:30:07 -0700304 self.prompt,
Jon Hall547e0582015-09-21 17:35:40 -0700305 pexpect.EOF,
306 pexpect.TIMEOUT ],
307 120 )
Jon Hall547e0582015-09-21 17:35:40 -0700308 if i == 0: # ask for ssh key confirmation
309 main.log.info( "ssh key confirmation received, sending yes" )
310 self.handle.sendline( 'yes' )
311 elif i == 1: # Asked for ssh password
312 main.log.info( "ssh connection asked for password, gave password" )
313 self.handle.sendline( pwd )
314 elif i == 2: # File finished transfering
315 main.log.info( "Secure copy successful" )
316 returnVal = main.TRUE
317 elif i == 3: # Connection refused
318 main.log.error(
319 "ssh: connect to host " +
320 ipAddress +
321 " port 22: Connection refused" )
322 returnVal = main.FALSE
323 elif i == 4: # File Not found
324 main.log.error( "No such file found" )
325 returnVal = main.FALSE
Jon Hall53c5e662016-04-13 16:06:56 -0700326 elif i == 5: # Permission denied
327 main.log.error( "Permission denied. Check folder permissions" )
328 returnVal = main.FALSE
329 elif i == 6: # prompt returned
330 return returnVal
331 elif i == 7: # EOF
Jon Hall547e0582015-09-21 17:35:40 -0700332 main.log.error( "Pexpect.EOF found!!!" )
333 main.cleanup()
334 main.exit()
Jon Hall53c5e662016-04-13 16:06:56 -0700335 elif i == 8: # timeout
Jon Hall547e0582015-09-21 17:35:40 -0700336 main.log.error(
337 "No route to the Host " +
338 userName +
339 "@" +
340 ipAddress )
341 returnVal = main.FALSE
Devin Limdc78e202017-06-09 18:30:07 -0700342 self.handle.expect( self.prompt )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700343 return returnVal
344
345 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
346 """
347 Definition:
348 Execute scp command in linux to copy to/from a remote host
349 Required:
350 * remoteHost - Test ON component to be parsed
351 str filePath - File path including the file it self
352 str dstPath - Destination path
353 Optional:
354 str direction - Direction of the scp, default to "from" which means
355 copy "from" the remote machine to local machine,
356 while "to" means copy "to" the remote machine from
357 local machine
358 """
359 return self.secureCopy( remoteHost.user_name,
360 remoteHost.ip_address,
361 filePath,
362 dstPath,
363 pwd=remoteHost.pwd,
364 direction=direction )
Devin Lim142b5342017-07-20 15:22:39 -0700365
366 def sshToNode( self, ipAddress, uName="sdn", pwd="rocks" ):
367 ssh_newkey = 'Are you sure you want to continue connecting'
368 refused = "ssh: connect to host " + ipAddress + " port 22: Connection refused"
369 handle = pexpect.spawn( 'ssh -X ' +
370 uName +
371 '@' +
372 ipAddress,
373 env={ "TERM": "xterm-mono" },
374 maxread=1000000,
375 timeout=60 )
376
377 # set tty window size
378 handle.setwinsize( 24, 250 )
379
380 i = 5
381 while i == 5:
382 i = handle.expect( [
383 ssh_newkey,
384 'password:|Password:',
385 pexpect.EOF,
386 pexpect.TIMEOUT,
387 refused,
388 'teston>',
389 self.prompt ],
390 120 )
391 if i == 0: # Accept key, then expect either a password prompt or access
392 main.log.info( "ssh key confirmation received, send yes" )
393 handle.sendline( 'yes' )
394 i = 5 # Run the loop again
395 continue
396 if i == 1: # Password required
397 if pwd:
398 main.log.info(
399 "ssh connection asked for password, gave password" )
400 else:
401 main.log.info( "Server asked for password, but none was "
402 "given in the .topo file. Trying "
403 "no password.")
404 pwd = ""
405 handle.sendline( pwd )
406 j = handle.expect( [ self.prompt,
407 'password:|Password:',
408 pexpect.EOF,
409 pexpect.TIMEOUT ],
410 120 )
411 if j != 0:
412 main.log.error( "Incorrect Password" )
413 main.cleanup()
414 main.exit()
415 elif i == 2:
416 main.log.error( "Connection timeout" )
417 main.cleanup()
418 main.exit()
419 elif i == 3: # timeout
420 main.log.error(
421 "No route to the Host " +
422 uName +
423 "@" +
424 ipAddress )
425 main.cleanup()
426 main.exit()
427 elif i == 4:
428 main.log.error(
429 "ssh: connect to host " +
430 ipAddress +
431 " port 22: Connection refused" )
432 main.cleanup()
433 main.exit()
434 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
442 main.log.info ( "Successfully ssh to " + ipAddress + "." )
443 return handle
444
445 def exitFromSsh( self, handle, ipAddress ):
446 handle.sendline( "logout" )
447 try:
448 handle.expect( "closed." )
449 main.log.info ( "Successfully closed ssh connection from " + ipAddress )
450 except pexpect.EOF:
451 main.log.error( "Failed to close the connection from " + ipAddress )
452 handle.sendline( "" )
453 handle.expect( self.prompt )