blob: fd1a401add510eab5745603b9bb04fcbad64713c [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 )
235 handle.sendline( "\r" )
236
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 " + \
kelvin-onlabd9e23de2015-08-06 10:34:44 -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 ) + ':' + \
279 str( filePath ) + ' ' + str( dstPath )
280 elif direction == "to":
281 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
282 '@' + str( ipAddress ) + ':' + str( dstPath )
283 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 )
kelvin8ec71442015-01-15 16:57:00 -0800289 i = self.handle.expect( [
acsmars07f9d392015-07-15 10:30:58 -0700290 ssh_newkey,
291 'password:',
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700292 "100%",
acsmars07f9d392015-07-15 10:30:58 -0700293 pexpect.EOF,
294 pexpect.TIMEOUT,
295 refused ],
296 120 )
kelvin8ec71442015-01-15 16:57:00 -0800297
298 if i == 0:
299 main.log.info( "ssh key confirmation received, send yes" )
300 self.handle.sendline( 'yes' )
301 i = self.handle.expect( [ ssh_newkey, 'password:', pexpect.EOF ] )
302 if i == 1:
303 main.log.info( "ssh connection asked for password, gave password" )
304 self.handle.sendline( pwd )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700305 # self.handle.expect( userName )
306 if i == 2:
307 main.log.info( "Secure copy successful\n" + self.handle.before )
308 returnVal = main.TRUE
309 elif i == 3:
310 main.log.error( "Pexpect.EOF found!!!" )
311 main.cleanup()
312 main.exit()
313 elif i == 4: # timeout
kelvin8ec71442015-01-15 16:57:00 -0800314 main.log.error(
315 "No route to the Host " +
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700316 userName +
kelvin8ec71442015-01-15 16:57:00 -0800317 "@" +
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700318 ipAddress )
319 returnVal = main.FALSE
320 elif i == 5:
kelvin8ec71442015-01-15 16:57:00 -0800321 main.log.error(
322 "ssh: connect to host " +
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700323 ipAddress +
kelvin8ec71442015-01-15 16:57:00 -0800324 " port 22: Connection refused" )
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700325 returnVal = main.FALSE
adminbae64d82013-08-01 10:50:15 -0700326
kelvin8ec71442015-01-15 16:57:00 -0800327 self.handle.sendline( "" )
328 self.handle.expect( "$" )
kelvin8ec71442015-01-15 16:57:00 -0800329
kelvin-onlabd9e23de2015-08-06 10:34:44 -0700330 return returnVal
331
332 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
333 """
334 Definition:
335 Execute scp command in linux to copy to/from a remote host
336 Required:
337 * remoteHost - Test ON component to be parsed
338 str filePath - File path including the file it self
339 str dstPath - Destination path
340 Optional:
341 str direction - Direction of the scp, default to "from" which means
342 copy "from" the remote machine to local machine,
343 while "to" means copy "to" the remote machine from
344 local machine
345 """
346 return self.secureCopy( remoteHost.user_name,
347 remoteHost.ip_address,
348 filePath,
349 dstPath,
350 pwd=remoteHost.pwd,
351 direction=direction )