blob: a7404fa35ceb4cdb2e2ed3645b67928d1d733212 [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",
Jon Hall53c5e662016-04-13 16:06:56 -0700293 "Permission denied",
294 "\$",
Jon Hall547e0582015-09-21 17:35:40 -0700295 pexpect.EOF,
296 pexpect.TIMEOUT ],
297 120 )
Jon Hall547e0582015-09-21 17:35:40 -0700298 if i == 0: # ask for ssh key confirmation
299 main.log.info( "ssh key confirmation received, sending yes" )
300 self.handle.sendline( 'yes' )
301 elif i == 1: # Asked for ssh password
302 main.log.info( "ssh connection asked for password, gave password" )
303 self.handle.sendline( pwd )
304 elif i == 2: # File finished transfering
305 main.log.info( "Secure copy successful" )
306 returnVal = main.TRUE
307 elif i == 3: # Connection refused
308 main.log.error(
309 "ssh: connect to host " +
310 ipAddress +
311 " port 22: Connection refused" )
312 returnVal = main.FALSE
313 elif i == 4: # File Not found
314 main.log.error( "No such file found" )
315 returnVal = main.FALSE
Jon Hall53c5e662016-04-13 16:06:56 -0700316 elif i == 5: # Permission denied
317 main.log.error( "Permission denied. Check folder permissions" )
318 returnVal = main.FALSE
319 elif i == 6: # prompt returned
320 return returnVal
321 elif i == 7: # EOF
Jon Hall547e0582015-09-21 17:35:40 -0700322 main.log.error( "Pexpect.EOF found!!!" )
323 main.cleanup()
324 main.exit()
Jon Hall53c5e662016-04-13 16:06:56 -0700325 elif i == 8: # timeout
Jon Hall547e0582015-09-21 17:35:40 -0700326 main.log.error(
327 "No route to the Host " +
328 userName +
329 "@" +
330 ipAddress )
331 returnVal = main.FALSE
Jon Hall3b489db2015-10-05 14:38:37 -0700332 self.handle.expect( "\$" )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700333 return returnVal
334
335 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
336 """
337 Definition:
338 Execute scp command in linux to copy to/from a remote host
339 Required:
340 * remoteHost - Test ON component to be parsed
341 str filePath - File path including the file it self
342 str dstPath - Destination path
343 Optional:
344 str direction - Direction of the scp, default to "from" which means
345 copy "from" the remote machine to local machine,
346 while "to" means copy "to" the remote machine from
347 local machine
348 """
349 return self.secureCopy( remoteHost.user_name,
350 remoteHost.ip_address,
351 filePath,
352 dstPath,
353 pwd=remoteHost.pwd,
354 direction=direction )