blob: 7d6ef0bb13675dc258a3fcc6d994823003397947 [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 = '.*[$>\#]'
Jon Hall3b489db2015-10-05 14:38:37 -0700148 args = utilities.parse_args( [ "CMD",
149 "TIMEOUT",
150 "PROMPT",
151 "MORE" ],
152 **execparams )
kelvin8ec71442015-01-15 16:57:00 -0800153
154 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
adminbae64d82013-08-01 10:50:15 -0700155 self.LASTRSP = ""
kelvin8ec71442015-01-15 16:57:00 -0800156 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
adminbae64d82013-08-01 10:50:15 -0700157 cmd = ''
kelvin8ec71442015-01-15 16:57:00 -0800158 if args[ "CMD" ]:
159 cmd = args[ "CMD" ]
160 else:
adminbae64d82013-08-01 10:50:15 -0700161 return 0
kelvin8ec71442015-01-15 16:57:00 -0800162 if args[ "MORE" ] is None:
163 args[ "MORE" ] = " "
164 self.handle.sendline( cmd )
adminbae64d82013-08-01 10:50:15 -0700165 self.lastCommand = cmd
Jon Hall3b489db2015-10-05 14:38:37 -0700166 index = self.handle.expect( [ expectPrompt,
167 "--More--",
168 'Command not found.',
169 pexpect.TIMEOUT,
170 "^:$" ],
171 timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700172 if index == 0:
kelvin8ec71442015-01-15 16:57:00 -0800173 self.LASTRSP = self.LASTRSP + \
174 self.handle.before + self.handle.after
Jon Hall3b489db2015-10-05 14:38:37 -0700175 main.log.info( "Executed :" + str(cmd ) +
176 " \t\t Expected Prompt '" + str( expectPrompt) +
177 "' Found" )
adminbae64d82013-08-01 10:50:15 -0700178 elif index == 1:
179 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800180 self.handle.send( args[ "MORE" ] )
181 main.log.info(
182 "Found More screen to go , Sending a key to proceed" )
183 indexMore = self.handle.expect(
184 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700185 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800186 main.log.info(
187 "Found anoother More screen to go , Sending a key to proceed" )
188 self.handle.send( args[ "MORE" ] )
189 indexMore = self.handle.expect(
190 [ "--More--", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700191 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800192 elif index == 2:
193 main.log.error( "Command not found" )
adminbae64d82013-08-01 10:50:15 -0700194 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800195 elif index == 3:
Jon Hall3b489db2015-10-05 14:38:37 -0700196 main.log.error( "Expected Prompt not found, Time Out!!" )
kelvin8ec71442015-01-15 16:57:00 -0800197 main.log.error( expectPrompt )
Jon Hall3b489db2015-10-05 14:38:37 -0700198 self.LASTRSP = self.LASTRSP + self.handle.before
199 return self.LASTRSP
adminbae64d82013-08-01 10:50:15 -0700200 elif index == 4:
201 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800202 # self.handle.send( args[ "MORE" ] )
203 self.handle.sendcontrol( "D" )
204 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700205 "Found More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800206 indexMore = self.handle.expect(
207 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700208 while indexMore == 0:
kelvin8ec71442015-01-15 16:57:00 -0800209 main.log.info(
Jon Hall3b489db2015-10-05 14:38:37 -0700210 "Found another More screen to go, Sending a key to proceed" )
kelvin8ec71442015-01-15 16:57:00 -0800211 self.handle.sendcontrol( "D" )
212 indexMore = self.handle.expect(
213 [ "^:$", expectPrompt ], timeout=timeoutVar )
adminbae64d82013-08-01 10:50:15 -0700214 self.LASTRSP = self.LASTRSP + self.handle.before
kelvin8ec71442015-01-15 16:57:00 -0800215 main.last_response = self.remove_contol_chars( self.LASTRSP )
adminbae64d82013-08-01 10:50:15 -0700216 return self.LASTRSP
kelvin8ec71442015-01-15 16:57:00 -0800217
218 def remove_contol_chars( self, response ):
219 # 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 ) )
220 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
221 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
222 # response = re.sub( r"\[\d+\;1H", "\n", response )
223 response = re.sub( r"\[\d+\;\d+H", "", response )
adminbae64d82013-08-01 10:50:15 -0700224 return response
adminbae64d82013-08-01 10:50:15 -0700225
kelvin8ec71442015-01-15 16:57:00 -0800226 def runAsSudoUser( self, handle, pwd, default ):
227
228 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
229 if i == 0:
230 handle.sendline( pwd )
Jon Hall5ec6b1b2015-09-17 18:20:14 -0700231 handle.sendline( "\n" )
kelvin8ec71442015-01-15 16:57:00 -0800232
233 if i == 1:
234 handle.expect( default )
235
236 if i == 2:
237 main.log.error( "Unable to run as Sudo user" )
238
adminbae64d82013-08-01 10:50:15 -0700239 return handle
adminbae64d82013-08-01 10:50:15 -0700240
kelvin8ec71442015-01-15 16:57:00 -0800241 def onfail( self ):
242 if 'onfail' in main.componentDictionary[ self.name ]:
243 commandList = main.componentDictionary[
244 self.name ][ 'onfail' ].split( "," )
245 for command in commandList:
246 response = self.execute(
247 cmd=command,
248 prompt="(.*)",
249 timeout=120 )
adminbae64d82013-08-01 10:50:15 -0700250
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700251 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
252 direction="from" ):
kelvin8ec71442015-01-15 16:57:00 -0800253 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700254 Definition:
255 Execute scp command in linux to copy to/from a remote host
256 Required:
257 str userName - User name of the remote host
258 str ipAddress - IP address of the remote host
259 str filePath - File path including the file it self
260 str dstPath - Destination path
261 Optional:
262 str pwd - Password of the host
263 str direction - Direction of the scp, default to "from" which means
264 copy "from" the remote machine to local machine,
265 while "to" means copy "to" the remote machine from
266 local machine
kelvin8ec71442015-01-15 16:57:00 -0800267 """
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700268 returnVal = main.TRUE
adminbae64d82013-08-01 10:50:15 -0700269 ssh_newkey = 'Are you sure you want to continue connecting'
kelvin8ec71442015-01-15 16:57:00 -0800270 refused = "ssh: connect to host " + \
Jon Hall547e0582015-09-21 17:35:40 -0700271 ipAddress + " port 22: Connection refused"
acsmars07f9d392015-07-15 10:30:58 -0700272
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700273 if direction == "from":
274 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
Jon Hall547e0582015-09-21 17:35:40 -0700275 str( filePath ) + ' ' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700276 elif direction == "to":
277 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
Jon Hall547e0582015-09-21 17:35:40 -0700278 '@' + str( ipAddress ) + ':' + str( dstPath )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700279 else:
280 main.log.debug( "Wrong direction using secure copy command!" )
281 return main.FALSE
kelvin8ec71442015-01-15 16:57:00 -0800282
283 main.log.info( "Sending: " + cmd )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700284 self.handle.sendline( cmd )
Jon Hall547e0582015-09-21 17:35:40 -0700285 i = 0
286 while i < 2:
287 i = self.handle.expect( [
288 ssh_newkey,
289 'password:',
290 "100%",
291 refused,
292 "No such file or directory",
293 pexpect.EOF,
294 pexpect.TIMEOUT ],
295 120 )
Jon Hall547e0582015-09-21 17:35:40 -0700296 if i == 0: # ask for ssh key confirmation
297 main.log.info( "ssh key confirmation received, sending yes" )
298 self.handle.sendline( 'yes' )
299 elif i == 1: # Asked for ssh password
300 main.log.info( "ssh connection asked for password, gave password" )
301 self.handle.sendline( pwd )
302 elif i == 2: # File finished transfering
303 main.log.info( "Secure copy successful" )
304 returnVal = main.TRUE
305 elif i == 3: # Connection refused
306 main.log.error(
307 "ssh: connect to host " +
308 ipAddress +
309 " port 22: Connection refused" )
310 returnVal = main.FALSE
311 elif i == 4: # File Not found
312 main.log.error( "No such file found" )
313 returnVal = main.FALSE
314 elif i == 5: # EOF
315 main.log.error( "Pexpect.EOF found!!!" )
316 main.cleanup()
317 main.exit()
318 elif i == 6: # timeout
319 main.log.error(
320 "No route to the Host " +
321 userName +
322 "@" +
323 ipAddress )
324 returnVal = main.FALSE
Jon Hall3b489db2015-10-05 14:38:37 -0700325 self.handle.expect( "\$" )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700326 return returnVal
327
328 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
329 """
330 Definition:
331 Execute scp command in linux to copy to/from a remote host
332 Required:
333 * remoteHost - Test ON component to be parsed
334 str filePath - File path including the file it self
335 str dstPath - Destination path
336 Optional:
337 str direction - Direction of the scp, default to "from" which means
338 copy "from" the remote machine to local machine,
339 while "to" means copy "to" the remote machine from
340 local machine
341 """
342 return self.secureCopy( remoteHost.user_name,
343 remoteHost.ip_address,
344 filePath,
345 dstPath,
346 pwd=remoteHost.pwd,
347 direction=direction )