blob: 0202a15e8575edab292e2c8811266e8afe53c11a [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
kelvin8ec71442015-01-15 16:57:00 -08004
5author:s: Anil Kumar ( anilkumar.s@paxterrasolutions.com ),
6 Raghav Kashyap( raghavkashyap@paxterrasolutions.com )
adminbae64d82013-08-01 10:50:15 -07007
8
9 TestON is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 2 of the License, or
kelvin8ec71442015-01-15 16:57:00 -080012 ( at your option ) any later version.
adminbae64d82013-08-01 10:50:15 -070013
14 TestON is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
kelvin8ec71442015-01-15 16:57:00 -080020 along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070021
22
kelvin8ec71442015-01-15 16:57:00 -080023
24"""
adminbae64d82013-08-01 10:50:15 -070025import pexpect
kelvin8ec71442015-01-15 16:57:00 -080026import re
adminbae64d82013-08-01 10:50:15 -070027
28from drivers.component import Component
kelvin8ec71442015-01-15 16:57:00 -080029
30
31class CLI( Component ):
32
33 """
adminbae64d82013-08-01 10:50:15 -070034 This will define common functions for CLI included.
kelvin8ec71442015-01-15 16:57:00 -080035 """
36 def __init__( self ):
37 super( Component, self ).__init__()
38
39 def connect( self, **connectargs ):
40 """
adminbae64d82013-08-01 10:50:15 -070041 Connection will establish to the remote host using ssh.
42 It will take user_name ,ip_address and password as arguments<br>
kelvin8ec71442015-01-15 16:57:00 -080043 and will return the handle.
44 """
adminbae64d82013-08-01 10:50:15 -070045 for key in connectargs:
kelvin8ec71442015-01-15 16:57:00 -080046 vars( self )[ key ] = connectargs[ key ]
adminbae64d82013-08-01 10:50:15 -070047
kelvin8ec71442015-01-15 16:57:00 -080048 connect_result = super( CLI, self ).connect()
adminbae64d82013-08-01 10:50:15 -070049 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -080050 refused = "ssh: connect to host " + \
51 self.ip_address + " port 22: Connection refused"
adminbae64d82013-08-01 10:50:15 -070052 if self.port:
kelvin8ec71442015-01-15 16:57:00 -080053 self.handle = pexpect.spawn(
54 'ssh -p ' +
55 self.port +
56 ' ' +
57 self.user_name +
58 '@' +
59 self.ip_address,
Jon Hall9aaba882015-01-19 15:05:15 -080060 env={ "TERM": "xterm-mono" },
kelvin8ec71442015-01-15 16:57:00 -080061 maxread=50000 )
62 else:
63 self.handle = pexpect.spawn(
64 'ssh -X ' +
65 self.user_name +
66 '@' +
67 self.ip_address,
Jon Hall9aaba882015-01-19 15:05:15 -080068 env={ "TERM": "xterm-mono" },
kelvin8ec71442015-01-15 16:57:00 -080069 maxread=1000000,
70 timeout=60 )
adminbae64d82013-08-01 10:50:15 -070071
72 self.handle.logfile = self.logfile_handler
kelvin8ec71442015-01-15 16:57:00 -080073 i = 5
74 while i == 5:
75 i = self.handle.expect( [
acsmarse2be32c2015-06-29 16:16:28 -070076 ssh_newkey,
Jon Hall05f88682015-06-09 14:57:53 -070077 'password:|Password:',
kelvin8ec71442015-01-15 16:57:00 -080078 pexpect.EOF,
79 pexpect.TIMEOUT,
80 refused,
81 'teston>',
82 '>|#|\$' ],
acsmars07f9d392015-07-15 10:30:58 -070083 120 )
acsmars32de0bc2015-06-30 09:57:12 -070084 if i == 0: # Accept key, then expect either a password prompt or access
kelvin8ec71442015-01-15 16:57:00 -080085 main.log.info( "ssh key confirmation received, send yes" )
86 self.handle.sendline( 'yes' )
acsmars32de0bc2015-06-30 09:57:12 -070087 i = 5 # Run the loop again
acsmars07f9d392015-07-15 10:30:58 -070088 continue
89 if i == 1: # Password required
Jon Hall63604932015-02-26 17:09:50 -080090 if self.pwd:
91 main.log.info(
acsmars07f9d392015-07-15 10:30:58 -070092 "ssh connection asked for password, gave password" )
Jon Hall63604932015-02-26 17:09:50 -080093 else:
acsmars07f9d392015-07-15 10:30:58 -070094 main.log.info( "Server asked for password, but none was "
95 "given in the .topo file. Trying "
96 "no password.")
97 self.pwd = ""
98 self.handle.sendline( self.pwd )
99 j = self.handle.expect( [
100 '>|#|\$',
101 'password:|Password:',
102 pexpect.EOF,
103 pexpect.TIMEOUT ],
104 120 )
105 if j != 0:
106 main.log.error( "Incorrect Password" )
107 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800108 elif i == 2:
109 main.log.error( "Connection timeout" )
110 return main.FALSE
111 elif i == 3: # timeout
112 main.log.error(
113 "No route to the Host " +
114 self.user_name +
115 "@" +
116 self.ip_address )
117 return main.FALSE
118 elif i == 4:
119 main.log.error(
120 "ssh: connect to host " +
121 self.ip_address +
122 " port 22: Connection refused" )
123 return main.FALSE
124 elif i == 6:
125 main.log.info( "Password not required logged in" )
adminbae64d82013-08-01 10:50:15 -0700126
kelvin8ec71442015-01-15 16:57:00 -0800127 self.handle.sendline( "" )
128 self.handle.expect( '>|#|\$' )
adminbae64d82013-08-01 10:50:15 -0700129 return self.handle
130
kelvin8ec71442015-01-15 16:57:00 -0800131 def disconnect( self ):
132 result = super( CLI, self ).disconnect( self )
adminbae64d82013-08-01 10:50:15 -0700133 result = main.TRUE
kelvin8ec71442015-01-15 16:57:00 -0800134 # self.execute( cmd="exit",timeout=120,prompt="(.*)" )
135
136 def execute( self, **execparams ):
137 """
adminbae64d82013-08-01 10:50:15 -0700138 It facilitates the command line execution of a given command. It has arguments as :
139 cmd => represents command to be executed,
140 prompt => represents expect command prompt or output,
141 timeout => timeout for command execution,
142 more => to provide a key press if it is on.
143
144 It will return output of command exection.
kelvin8ec71442015-01-15 16:57:00 -0800145 """
146 result = super( CLI, self ).execute( self )
adminaef00552014-05-08 09:18:36 -0700147 defaultPrompt = '.*[$>\#]'
kelvin8ec71442015-01-15 16:57:00 -0800148 args = utilities.parse_args( [
acsmars07f9d392015-07-15 10:30:58 -0700149 "CMD",
kelvin8ec71442015-01-15 16:57:00 -0800150 "TIMEOUT",
151 "PROMPT",
152 "MORE" ],
acsmars07f9d392015-07-15 10:30:58 -0700153 **execparams )
kelvin8ec71442015-01-15 16:57:00 -0800154
155 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
adminbae64d82013-08-01 10:50:15 -0700156 self.LASTRSP = ""
kelvin8ec71442015-01-15 16:57:00 -0800157 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
adminbae64d82013-08-01 10:50:15 -0700158 cmd = ''
kelvin8ec71442015-01-15 16:57:00 -0800159 if args[ "CMD" ]:
160 cmd = args[ "CMD" ]
161 else:
adminbae64d82013-08-01 10:50:15 -0700162 return 0
kelvin8ec71442015-01-15 16:57:00 -0800163 if args[ "MORE" ] is None:
164 args[ "MORE" ] = " "
165 self.handle.sendline( cmd )
adminbae64d82013-08-01 10:50:15 -0700166 self.lastCommand = cmd
kelvin8ec71442015-01-15 16:57:00 -0800167 index = self.handle.expect( [
acsmars07f9d392015-07-15 10:30:58 -0700168 expectPrompt,
kelvin8ec71442015-01-15 16:57:00 -0800169 "--More--",
170 'Command not found.',
171 pexpect.TIMEOUT,
172 "^:$" ],
acsmars07f9d392015-07-15 10:30:58 -0700173 timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700174 if index == 0:
kelvin8ec71442015-01-15 16:57:00 -0800175 self.LASTRSP = self.LASTRSP + \
176 self.handle.before + self.handle.after
177 main.log.info(
178 "Executed :" + str(
179 cmd ) + " \t\t Expected Prompt '" + str(
180 expectPrompt) + "' Found" )
adminbae64d82013-08-01 10:50:15 -0700181 elif index == 1:
182 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800183 self.handle.send( args[ "MORE" ] )
184 main.log.info(
185 "Found More screen to go , Sending a key to proceed" )
186 indexMore = self.handle.expect(
187 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700188 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800189 main.log.info(
190 "Found anoother More screen to go , Sending a key to proceed" )
191 self.handle.send( args[ "MORE" ] )
192 indexMore = self.handle.expect(
193 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700194 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800195 elif index == 2:
196 main.log.error( "Command not found" )
adminbae64d82013-08-01 10:50:15 -0700197 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800198 elif index == 3:
199 main.log.error( "Expected Prompt not found , Time Out!!" )
200 main.log.error( expectPrompt )
adminbae64d82013-08-01 10:50:15 -0700201 return "Expected Prompt not found , Time Out!!"
kelvin8ec71442015-01-15 16:57:00 -0800202
adminbae64d82013-08-01 10:50:15 -0700203 elif index == 4:
204 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800205 # self.handle.send( args[ "MORE" ] )
206 self.handle.sendcontrol( "D" )
207 main.log.info(
208 "Found More screen to go , Sending a key to proceed" )
209 indexMore = self.handle.expect(
210 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700211 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800212 main.log.info(
213 "Found another More screen to go , Sending a key to proceed" )
214 self.handle.sendcontrol( "D" )
215 indexMore = self.handle.expect(
216 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700217 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800218
219 main.last_response = self.remove_contol_chars( self.LASTRSP )
adminbae64d82013-08-01 10:50:15 -0700220 return self.LASTRSP
kelvin8ec71442015-01-15 16:57:00 -0800221
222 def remove_contol_chars( self, response ):
223 # 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 ) )
224 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
225 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
226 # response = re.sub( r"\[\d+\;1H", "\n", response )
227 response = re.sub( r"\[\d+\;\d+H", "", response )
adminbae64d82013-08-01 10:50:15 -0700228 return response
adminbae64d82013-08-01 10:50:15 -0700229
kelvin8ec71442015-01-15 16:57:00 -0800230 def runAsSudoUser( self, handle, pwd, default ):
231
232 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
233 if i == 0:
234 handle.sendline( pwd )
Jon Hall5ec6b1b2015-09-17 18:20:14 -0700235 handle.sendline( "\n" )
kelvin8ec71442015-01-15 16:57:00 -0800236
237 if i == 1:
238 handle.expect( default )
239
240 if i == 2:
241 main.log.error( "Unable to run as Sudo user" )
242
adminbae64d82013-08-01 10:50:15 -0700243 return handle
adminbae64d82013-08-01 10:50:15 -0700244
kelvin8ec71442015-01-15 16:57:00 -0800245 def onfail( self ):
246 if 'onfail' in main.componentDictionary[ self.name ]:
247 commandList = main.componentDictionary[
248 self.name ][ 'onfail' ].split( "," )
249 for command in commandList:
250 response = self.execute(
251 cmd=command,
252 prompt="(.*)",
253 timeout=120 )
adminbae64d82013-08-01 10:50:15 -0700254
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700255 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
256 direction="from" ):
kelvin8ec71442015-01-15 16:57:00 -0800257 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700258 Definition:
259 Execute scp command in linux to copy to/from a remote host
260 Required:
261 str userName - User name of the remote host
262 str ipAddress - IP address of the remote host
263 str filePath - File path including the file it self
264 str dstPath - Destination path
265 Optional:
266 str pwd - Password of the host
267 str direction - Direction of the scp, default to "from" which means
268 copy "from" the remote machine to local machine,
269 while "to" means copy "to" the remote machine from
270 local machine
kelvin8ec71442015-01-15 16:57:00 -0800271 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700272 returnVal = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700273 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -0800274 refused = "ssh: connect to host " + \
Jon Hall547e0582015-09-21 17:35:40 -0700275 ipAddress + " port 22: Connection refused"
acsmars07f9d392015-07-15 10:30:58 -0700276
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700277 if direction == "from":
278 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
Jon Hall547e0582015-09-21 17:35:40 -0700279 str( filePath ) + ' ' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700280 elif direction == "to":
281 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
Jon Hall547e0582015-09-21 17:35:40 -0700282 '@' + str( ipAddress ) + ':' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700283 else:
284 main.log.debug( "Wrong direction using secure copy command!" )
285 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800286
287 main.log.info( "Sending: " + cmd )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700288 self.handle.sendline( cmd )
Jon Hall547e0582015-09-21 17:35:40 -0700289 i = 0
290 while i < 2:
291 i = self.handle.expect( [
292 ssh_newkey,
293 'password:',
294 "100%",
295 refused,
296 "No such file or directory",
297 pexpect.EOF,
298 pexpect.TIMEOUT ],
299 120 )
kelvin8ec71442015-01-15 16:57:00 -0800300
Jon Hall547e0582015-09-21 17:35:40 -0700301 if i == 0: # ask for ssh key confirmation
302 main.log.info( "ssh key confirmation received, sending yes" )
303 self.handle.sendline( 'yes' )
304 elif i == 1: # Asked for ssh password
305 main.log.info( "ssh connection asked for password, gave password" )
306 self.handle.sendline( pwd )
307 elif i == 2: # File finished transfering
308 main.log.info( "Secure copy successful" )
309 returnVal = main.TRUE
310 elif i == 3: # Connection refused
311 main.log.error(
312 "ssh: connect to host " +
313 ipAddress +
314 " port 22: Connection refused" )
315 returnVal = main.FALSE
316 elif i == 4: # File Not found
317 main.log.error( "No such file found" )
318 returnVal = main.FALSE
319 elif i == 5: # EOF
320 main.log.error( "Pexpect.EOF found!!!" )
321 main.cleanup()
322 main.exit()
323 elif i == 6: # timeout
324 main.log.error(
325 "No route to the Host " +
326 userName +
327 "@" +
328 ipAddress )
329 returnVal = main.FALSE
adminbae64d82013-08-01 10:50:15 -0700330
kelvin8ec71442015-01-15 16:57:00 -0800331 self.handle.sendline( "" )
332 self.handle.expect( "$" )
kelvin8ec71442015-01-15 16:57:00 -0800333
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700334 return returnVal
335
336 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
337 """
338 Definition:
339 Execute scp command in linux to copy to/from a remote host
340 Required:
341 * remoteHost - Test ON component to be parsed
342 str filePath - File path including the file it self
343 str dstPath - Destination path
344 Optional:
345 str direction - Direction of the scp, default to "from" which means
346 copy "from" the remote machine to local machine,
347 while "to" means copy "to" the remote machine from
348 local machine
349 """
350 return self.secureCopy( remoteHost.user_name,
351 remoteHost.ip_address,
352 filePath,
353 dstPath,
354 pwd=remoteHost.pwd,
355 direction=direction )