blob: 493836953909d065182484ff7ff1918b4dcce889 [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__()
36 def checkPrompt(self):
37 for key in self.options:
38 if key == "prompt" and self.options['prompt'] is not None:
39 self.prompt = self.options['prompt']
40 break
kelvin8ec71442015-01-15 16:57:00 -080041
42 def connect( self, **connectargs ):
43 """
adminbae64d82013-08-01 10:50:15 -070044 Connection will establish to the remote host using ssh.
45 It will take user_name ,ip_address and password as arguments<br>
kelvin8ec71442015-01-15 16:57:00 -080046 and will return the handle.
47 """
adminbae64d82013-08-01 10:50:15 -070048 for key in connectargs:
kelvin8ec71442015-01-15 16:57:00 -080049 vars( self )[ key ] = connectargs[ key ]
Devin Limdc78e202017-06-09 18:30:07 -070050 self.checkPrompt()
adminbae64d82013-08-01 10:50:15 -070051
kelvin8ec71442015-01-15 16:57:00 -080052 connect_result = super( CLI, self ).connect()
adminbae64d82013-08-01 10:50:15 -070053 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -080054 refused = "ssh: connect to host " + \
55 self.ip_address + " port 22: Connection refused"
adminbae64d82013-08-01 10:50:15 -070056 if self.port:
kelvin8ec71442015-01-15 16:57:00 -080057 self.handle = pexpect.spawn(
58 'ssh -p ' +
59 self.port +
60 ' ' +
61 self.user_name +
62 '@' +
63 self.ip_address,
Jon Hall9aaba882015-01-19 15:05:15 -080064 env={ "TERM": "xterm-mono" },
kelvin8ec71442015-01-15 16:57:00 -080065 maxread=50000 )
66 else:
67 self.handle = pexpect.spawn(
68 'ssh -X ' +
69 self.user_name +
70 '@' +
71 self.ip_address,
Jon Hall9aaba882015-01-19 15:05:15 -080072 env={ "TERM": "xterm-mono" },
kelvin8ec71442015-01-15 16:57:00 -080073 maxread=1000000,
74 timeout=60 )
adminbae64d82013-08-01 10:50:15 -070075
Jon Hall73057ee2016-08-23 09:57:26 -070076 # set tty window size
77 self.handle.setwinsize( 24, 250 )
78
adminbae64d82013-08-01 10:50:15 -070079 self.handle.logfile = self.logfile_handler
kelvin8ec71442015-01-15 16:57:00 -080080 i = 5
81 while i == 5:
82 i = self.handle.expect( [
acsmarse2be32c2015-06-29 16:16:28 -070083 ssh_newkey,
Jon Hall05f88682015-06-09 14:57:53 -070084 'password:|Password:',
kelvin8ec71442015-01-15 16:57:00 -080085 pexpect.EOF,
86 pexpect.TIMEOUT,
87 refused,
88 'teston>',
Devin Limdc78e202017-06-09 18:30:07 -070089 self.prompt ],
acsmars07f9d392015-07-15 10:30:58 -070090 120 )
acsmars32de0bc2015-06-30 09:57:12 -070091 if i == 0: # Accept key, then expect either a password prompt or access
kelvin8ec71442015-01-15 16:57:00 -080092 main.log.info( "ssh key confirmation received, send yes" )
93 self.handle.sendline( 'yes' )
acsmars32de0bc2015-06-30 09:57:12 -070094 i = 5 # Run the loop again
acsmars07f9d392015-07-15 10:30:58 -070095 continue
96 if i == 1: # Password required
Jon Hall63604932015-02-26 17:09:50 -080097 if self.pwd:
98 main.log.info(
acsmars07f9d392015-07-15 10:30:58 -070099 "ssh connection asked for password, gave password" )
Jon Hall63604932015-02-26 17:09:50 -0800100 else:
acsmars07f9d392015-07-15 10:30:58 -0700101 main.log.info( "Server asked for password, but none was "
102 "given in the .topo file. Trying "
103 "no password.")
104 self.pwd = ""
105 self.handle.sendline( self.pwd )
106 j = self.handle.expect( [
Devin Limdc78e202017-06-09 18:30:07 -0700107 self.prompt,
acsmars07f9d392015-07-15 10:30:58 -0700108 'password:|Password:',
109 pexpect.EOF,
110 pexpect.TIMEOUT ],
111 120 )
112 if j != 0:
113 main.log.error( "Incorrect Password" )
114 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800115 elif i == 2:
116 main.log.error( "Connection timeout" )
117 return main.FALSE
118 elif i == 3: # timeout
119 main.log.error(
120 "No route to the Host " +
121 self.user_name +
122 "@" +
123 self.ip_address )
124 return main.FALSE
125 elif i == 4:
126 main.log.error(
127 "ssh: connect to host " +
128 self.ip_address +
129 " port 22: Connection refused" )
130 return main.FALSE
131 elif i == 6:
132 main.log.info( "Password not required logged in" )
adminbae64d82013-08-01 10:50:15 -0700133
kelvin8ec71442015-01-15 16:57:00 -0800134 self.handle.sendline( "" )
Devin Limdc78e202017-06-09 18:30:07 -0700135 self.handle.expect( self.prompt )
Jeremy Ronquillo0f2008a2017-06-23 15:32:51 -0700136 self.handle.sendline( "cd" )
137 self.handle.expect( self.prompt )
adminbae64d82013-08-01 10:50:15 -0700138 return self.handle
139
kelvin8ec71442015-01-15 16:57:00 -0800140 def disconnect( self ):
141 result = super( CLI, self ).disconnect( self )
adminbae64d82013-08-01 10:50:15 -0700142 result = main.TRUE
kelvin8ec71442015-01-15 16:57:00 -0800143 # self.execute( cmd="exit",timeout=120,prompt="(.*)" )
144
145 def execute( self, **execparams ):
146 """
adminbae64d82013-08-01 10:50:15 -0700147 It facilitates the command line execution of a given command. It has arguments as :
148 cmd => represents command to be executed,
149 prompt => represents expect command prompt or output,
150 timeout => timeout for command execution,
151 more => to provide a key press if it is on.
152
153 It will return output of command exection.
kelvin8ec71442015-01-15 16:57:00 -0800154 """
155 result = super( CLI, self ).execute( self )
adminaef00552014-05-08 09:18:36 -0700156 defaultPrompt = '.*[$>\#]'
Jon Hall3b489db2015-10-05 14:38:37 -0700157 args = utilities.parse_args( [ "CMD",
158 "TIMEOUT",
159 "PROMPT",
160 "MORE" ],
161 **execparams )
kelvin8ec71442015-01-15 16:57:00 -0800162
163 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
adminbae64d82013-08-01 10:50:15 -0700164 self.LASTRSP = ""
kelvin8ec71442015-01-15 16:57:00 -0800165 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
adminbae64d82013-08-01 10:50:15 -0700166 cmd = ''
kelvin8ec71442015-01-15 16:57:00 -0800167 if args[ "CMD" ]:
168 cmd = args[ "CMD" ]
169 else:
adminbae64d82013-08-01 10:50:15 -0700170 return 0
kelvin8ec71442015-01-15 16:57:00 -0800171 if args[ "MORE" ] is None:
172 args[ "MORE" ] = " "
173 self.handle.sendline( cmd )
adminbae64d82013-08-01 10:50:15 -0700174 self.lastCommand = cmd
Jon Hall3b489db2015-10-05 14:38:37 -0700175 index = self.handle.expect( [ expectPrompt,
176 "--More--",
177 'Command not found.',
178 pexpect.TIMEOUT,
179 "^:$" ],
180 timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700181 if index == 0:
kelvin8ec71442015-01-15 16:57:00 -0800182 self.LASTRSP = self.LASTRSP + \
183 self.handle.before + self.handle.after
Jon Hall3b489db2015-10-05 14:38:37 -0700184 main.log.info( "Executed :" + str(cmd ) +
185 " \t\t Expected Prompt '" + str( expectPrompt) +
186 "' Found" )
adminbae64d82013-08-01 10:50:15 -0700187 elif index == 1:
188 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800189 self.handle.send( args[ "MORE" ] )
190 main.log.info(
191 "Found More screen to go , Sending a key to proceed" )
192 indexMore = self.handle.expect(
193 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700194 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800195 main.log.info(
196 "Found anoother More screen to go , Sending a key to proceed" )
197 self.handle.send( args[ "MORE" ] )
198 indexMore = self.handle.expect(
199 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700200 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800201 elif index == 2:
202 main.log.error( "Command not found" )
adminbae64d82013-08-01 10:50:15 -0700203 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800204 elif index == 3:
Jon Hall3b489db2015-10-05 14:38:37 -0700205 main.log.error( "Expected Prompt not found, Time Out!!" )
kelvin8ec71442015-01-15 16:57:00 -0800206 main.log.error( expectPrompt )
Jon Hall3b489db2015-10-05 14:38:37 -0700207 self.LASTRSP = self.LASTRSP + self.handle.before
208 return self.LASTRSP
adminbae64d82013-08-01 10:50:15 -0700209 elif index == 4:
210 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800211 # self.handle.send( args[ "MORE" ] )
212 self.handle.sendcontrol( "D" )
213 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700214 "Found More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800215 indexMore = self.handle.expect(
216 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700217 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800218 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700219 "Found another More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800220 self.handle.sendcontrol( "D" )
221 indexMore = self.handle.expect(
222 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700223 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800224 main.last_response = self.remove_contol_chars( self.LASTRSP )
adminbae64d82013-08-01 10:50:15 -0700225 return self.LASTRSP
kelvin8ec71442015-01-15 16:57:00 -0800226
227 def remove_contol_chars( self, response ):
228 # 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 ) )
229 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
230 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
231 # response = re.sub( r"\[\d+\;1H", "\n", response )
232 response = re.sub( r"\[\d+\;\d+H", "", response )
adminbae64d82013-08-01 10:50:15 -0700233 return response
adminbae64d82013-08-01 10:50:15 -0700234
kelvin8ec71442015-01-15 16:57:00 -0800235 def runAsSudoUser( self, handle, pwd, default ):
236
237 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
238 if i == 0:
239 handle.sendline( pwd )
Jon Hall5ec6b1b2015-09-17 18:20:14 -0700240 handle.sendline( "\n" )
kelvin8ec71442015-01-15 16:57:00 -0800241
242 if i == 1:
243 handle.expect( default )
244
245 if i == 2:
246 main.log.error( "Unable to run as Sudo user" )
247
adminbae64d82013-08-01 10:50:15 -0700248 return handle
adminbae64d82013-08-01 10:50:15 -0700249
kelvin8ec71442015-01-15 16:57:00 -0800250 def onfail( self ):
251 if 'onfail' in main.componentDictionary[ self.name ]:
252 commandList = main.componentDictionary[
253 self.name ][ 'onfail' ].split( "," )
254 for command in commandList:
255 response = self.execute(
256 cmd=command,
257 prompt="(.*)",
258 timeout=120 )
adminbae64d82013-08-01 10:50:15 -0700259
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700260 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
261 direction="from" ):
kelvin8ec71442015-01-15 16:57:00 -0800262 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700263 Definition:
264 Execute scp command in linux to copy to/from a remote host
265 Required:
266 str userName - User name of the remote host
267 str ipAddress - IP address of the remote host
268 str filePath - File path including the file it self
269 str dstPath - Destination path
270 Optional:
271 str pwd - Password of the host
272 str direction - Direction of the scp, default to "from" which means
273 copy "from" the remote machine to local machine,
274 while "to" means copy "to" the remote machine from
275 local machine
kelvin8ec71442015-01-15 16:57:00 -0800276 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700277 returnVal = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700278 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -0800279 refused = "ssh: connect to host " + \
Jon Hall547e0582015-09-21 17:35:40 -0700280 ipAddress + " port 22: Connection refused"
acsmars07f9d392015-07-15 10:30:58 -0700281
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700282 if direction == "from":
283 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
Jon Hall547e0582015-09-21 17:35:40 -0700284 str( filePath ) + ' ' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700285 elif direction == "to":
286 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
Jon Hall547e0582015-09-21 17:35:40 -0700287 '@' + str( ipAddress ) + ':' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700288 else:
289 main.log.debug( "Wrong direction using secure copy command!" )
290 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800291
292 main.log.info( "Sending: " + cmd )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700293 self.handle.sendline( cmd )
Jon Hall547e0582015-09-21 17:35:40 -0700294 i = 0
295 while i < 2:
296 i = self.handle.expect( [
297 ssh_newkey,
298 'password:',
299 "100%",
300 refused,
301 "No such file or directory",
Jon Hall53c5e662016-04-13 16:06:56 -0700302 "Permission denied",
Devin Limdc78e202017-06-09 18:30:07 -0700303 self.prompt,
Jon Hall547e0582015-09-21 17:35:40 -0700304 pexpect.EOF,
305 pexpect.TIMEOUT ],
306 120 )
Jon Hall547e0582015-09-21 17:35:40 -0700307 if i == 0: # ask for ssh key confirmation
308 main.log.info( "ssh key confirmation received, sending yes" )
309 self.handle.sendline( 'yes' )
310 elif i == 1: # Asked for ssh password
311 main.log.info( "ssh connection asked for password, gave password" )
312 self.handle.sendline( pwd )
313 elif i == 2: # File finished transfering
314 main.log.info( "Secure copy successful" )
315 returnVal = main.TRUE
316 elif i == 3: # Connection refused
317 main.log.error(
318 "ssh: connect to host " +
319 ipAddress +
320 " port 22: Connection refused" )
321 returnVal = main.FALSE
322 elif i == 4: # File Not found
323 main.log.error( "No such file found" )
324 returnVal = main.FALSE
Jon Hall53c5e662016-04-13 16:06:56 -0700325 elif i == 5: # Permission denied
326 main.log.error( "Permission denied. Check folder permissions" )
327 returnVal = main.FALSE
328 elif i == 6: # prompt returned
329 return returnVal
330 elif i == 7: # EOF
Jon Hall547e0582015-09-21 17:35:40 -0700331 main.log.error( "Pexpect.EOF found!!!" )
332 main.cleanup()
333 main.exit()
Jon Hall53c5e662016-04-13 16:06:56 -0700334 elif i == 8: # timeout
Jon Hall547e0582015-09-21 17:35:40 -0700335 main.log.error(
336 "No route to the Host " +
337 userName +
338 "@" +
339 ipAddress )
340 returnVal = main.FALSE
Devin Limdc78e202017-06-09 18:30:07 -0700341 self.handle.expect( self.prompt )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700342 return returnVal
343
344 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
345 """
346 Definition:
347 Execute scp command in linux to copy to/from a remote host
348 Required:
349 * remoteHost - Test ON component to be parsed
350 str filePath - File path including the file it self
351 str dstPath - Destination path
352 Optional:
353 str direction - Direction of the scp, default to "from" which means
354 copy "from" the remote machine to local machine,
355 while "to" means copy "to" the remote machine from
356 local machine
357 """
358 return self.secureCopy( remoteHost.user_name,
359 remoteHost.ip_address,
360 filePath,
361 dstPath,
362 pwd=remoteHost.pwd,
363 direction=direction )