blob: a769bf10c97b3a57d62fd810e6896f286e97db99 [file] [log] [blame]
Chetan Gaonkercb122cc2016-05-10 10:58:34 -07001#!/usr/bin/env python
Chetan Gaonkercfcce782016-05-10 10:10:42 -07002#
3# Copyright 2016-present Ciena Corporation
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -070017"""
18Created on 24-Oct-2012
19
20author:s: Anil Kumar ( anilkumar.s@paxterrasolutions.com ),
21 Raghav Kashyap( raghavkashyap@paxterrasolutions.com )
22
23
24 TestON is free software: you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation, either version 2 of the License, or
27 ( at your option ) any later version.
28
29 TestON is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License
35 along with TestON. If not, see <http://www.gnu.org/licenses/>.
36
37
38
39"""
40import pexpect
41import re
42from component import Component
43from clicommon import *
44import os
45
46class CLI( Component ):
47
48 """
49 This will define common functions for CLI included.
50 """
51 def __init__( self ):
52 super( Component, self ).__init__()
53
54 def connect( self, **connectargs ):
55 """
56 Connection will establish to the remote host using ssh.
57 It will take user_name ,ip_address and password as arguments<br>
58 and will return the handle.
59 """
60 for key in connectargs:
61 vars( self )[ key ] = connectargs[ key ]
62
63 connect_result = super( CLI, self ).connect()
64 ssh_newkey = 'Are you sure you want to continue connecting'
65 refused = "ssh: connect to host " + \
66 self.ip_address + " port 22: Connection refused"
67 if self.port:
68 ssh_hosts_file = os.path.join(os.getenv('HOME'), '.ssh', 'known_hosts')
69 cmd_host_remove = 'ssh-keygen -f "%s" -R [%s]:8101' %(ssh_hosts_file, self.ip_address)
Chetan Gaonker3533faa2016-04-25 17:50:14 -070070 os.system(cmd_host_remove)
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -070071 #main.log.info('SSH host remove cmd: %s' %cmd_host_remove)
72 main.log.info('Spawning pexpect for ip %s' %self.ip_address)
73 self.handle = pexpect.spawn(
74 'ssh -p ' +
75 self.port +
76 ' ' +
77 '-o StrictHostKeyChecking=no ' +
78 self.user_name +
79 '@' +
80 self.ip_address,
81 env={ "TERM": "xterm-mono" },
82 maxread=50000 )
83 else:
84 self.handle = pexpect.spawn(
85 'ssh -X ' +
86 self.user_name +
87 '@' +
88 self.ip_address,
89 env={ "TERM": "xterm-mono" },
90 maxread=1000000,
91 timeout=60 )
92
93 self.handle.logfile = self.logfile_handler
94 i = 5
95 while i == 5:
96 i = self.handle.expect( [
97 ssh_newkey,
98 'password:|Password:',
99 pexpect.EOF,
100 pexpect.TIMEOUT,
101 refused,
102 'teston>',
103 '>|#|\$' ],
104 120 )
105 if i == 0: # Accept key, then expect either a password prompt or access
106 main.log.info( "ssh key confirmation received, send yes" )
107 self.handle.sendline( 'yes' )
108 i = 5 # Run the loop again
109 continue
110 if i == 1: # Password required
111 if self.pwd:
112 main.log.info(
113 "ssh connection asked for password, gave password" )
114 else:
115 main.log.info( "Server asked for password, but none was "
116 "given in the .topo file. Trying "
117 "no password.")
118 self.pwd = ""
119 self.handle.sendline( self.pwd )
120 j = self.handle.expect( [
121 '>|#|\$',
122 'password:|Password:',
123 pexpect.EOF,
124 pexpect.TIMEOUT ],
125 120 )
126 if j != 0:
127 main.log.error( "Incorrect Password" )
128 return main.FALSE
129 elif i == 2:
130 main.log.error( "Connection timeout" )
131 return main.FALSE
132 elif i == 3: # timeout
133 main.log.error(
134 "No route to the Host " +
135 self.user_name +
136 "@" +
137 self.ip_address )
138 return main.FALSE
139 elif i == 4:
140 main.log.error(
141 "ssh: connect to host " +
142 self.ip_address +
143 " port 22: Connection refused" )
144 return main.FALSE
145 elif i == 6:
146 main.log.info( "Password not required logged in" )
147
148 self.handle.sendline( "" )
149 self.handle.expect( '>|#|\$' )
150 return self.handle
151
152 def disconnect( self ):
153 result = super( CLI, self ).disconnect( self )
154 result = main.TRUE
155 # self.execute( cmd="exit",timeout=120,prompt="(.*)" )
156
157 def execute( self, **execparams ):
158 """
159 It facilitates the command line execution of a given command. It has arguments as :
160 cmd => represents command to be executed,
161 prompt => represents expect command prompt or output,
162 timeout => timeout for command execution,
163 more => to provide a key press if it is on.
164
165 It will return output of command exection.
166 """
167 result = super( CLI, self ).execute( self )
168 defaultPrompt = '.*[$>\#]'
169 args = utilities.parse_args( [ "CMD",
170 "TIMEOUT",
171 "PROMPT",
172 "MORE" ],
173 **execparams )
174
175 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
176 self.LASTRSP = ""
177 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
178 cmd = ''
179 if args[ "CMD" ]:
180 cmd = args[ "CMD" ]
181 else:
182 return 0
183 if args[ "MORE" ] is None:
184 args[ "MORE" ] = " "
185 self.handle.sendline( cmd )
186 self.lastCommand = cmd
187 index = self.handle.expect( [ expectPrompt,
188 "--More--",
189 'Command not found.',
190 pexpect.TIMEOUT,
191 "^:$" ],
192 timeout=timeoutVar )
193 if index == 0:
194 self.LASTRSP = self.LASTRSP + \
195 self.handle.before + self.handle.after
196 main.log.info( "Executed :" + str(cmd ) +
197 " \t\t Expected Prompt '" + str( expectPrompt) +
198 "' Found" )
199 elif index == 1:
200 self.LASTRSP = self.LASTRSP + self.handle.before
201 self.handle.send( args[ "MORE" ] )
202 main.log.info(
203 "Found More screen to go , Sending a key to proceed" )
204 indexMore = self.handle.expect(
205 [ "--More--", expectPrompt ], timeout=timeoutVar )
206 while indexMore == 0:
207 main.log.info(
208 "Found anoother More screen to go , Sending a key to proceed" )
209 self.handle.send( args[ "MORE" ] )
210 indexMore = self.handle.expect(
211 [ "--More--", expectPrompt ], timeout=timeoutVar )
212 self.LASTRSP = self.LASTRSP + self.handle.before
213 elif index == 2:
214 main.log.error( "Command not found" )
215 self.LASTRSP = self.LASTRSP + self.handle.before
216 elif index == 3:
217 main.log.error( "Expected Prompt not found, Time Out!!" )
218 main.log.error( expectPrompt )
219 self.LASTRSP = self.LASTRSP + self.handle.before
220 return self.LASTRSP
221 elif index == 4:
222 self.LASTRSP = self.LASTRSP + self.handle.before
223 # self.handle.send( args[ "MORE" ] )
224 self.handle.sendcontrol( "D" )
225 main.log.info(
226 "Found More screen to go, Sending a key to proceed" )
227 indexMore = self.handle.expect(
228 [ "^:$", expectPrompt ], timeout=timeoutVar )
229 while indexMore == 0:
230 main.log.info(
231 "Found another More screen to go, Sending a key to proceed" )
232 self.handle.sendcontrol( "D" )
233 indexMore = self.handle.expect(
234 [ "^:$", expectPrompt ], timeout=timeoutVar )
235 self.LASTRSP = self.LASTRSP + self.handle.before
236 main.last_response = self.remove_contol_chars( self.LASTRSP )
237 return self.LASTRSP
238
239 def remove_contol_chars( self, response ):
240 # 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 ) )
241 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
242 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
243 # response = re.sub( r"\[\d+\;1H", "\n", response )
244 response = re.sub( r"\[\d+\;\d+H", "", response )
245 return response
246
247 def runAsSudoUser( self, handle, pwd, default ):
248
249 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
250 if i == 0:
251 handle.sendline( pwd )
252 handle.sendline( "\n" )
253
254 if i == 1:
255 handle.expect( default )
256
257 if i == 2:
258 main.log.error( "Unable to run as Sudo user" )
259
260 return handle
261
262 def onfail( self ):
263 if 'onfail' in main.componentDictionary[ self.name ]:
264 commandList = main.componentDictionary[
265 self.name ][ 'onfail' ].split( "," )
266 for command in commandList:
267 response = self.execute(
268 cmd=command,
269 prompt="(.*)",
270 timeout=120 )
271
272 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
273 direction="from" ):
274 """
275 Definition:
276 Execute scp command in linux to copy to/from a remote host
277 Required:
278 str userName - User name of the remote host
279 str ipAddress - IP address of the remote host
280 str filePath - File path including the file it self
281 str dstPath - Destination path
282 Optional:
283 str pwd - Password of the host
284 str direction - Direction of the scp, default to "from" which means
285 copy "from" the remote machine to local machine,
286 while "to" means copy "to" the remote machine from
287 local machine
288 """
289 returnVal = main.TRUE
290 ssh_newkey = 'Are you sure you want to continue connecting'
291 refused = "ssh: connect to host " + \
292 ipAddress + " port 22: Connection refused"
293
294 if direction == "from":
295 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
296 str( filePath ) + ' ' + str( dstPath )
297 elif direction == "to":
298 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
299 '@' + str( ipAddress ) + ':' + str( dstPath )
300 else:
301 main.log.debug( "Wrong direction using secure copy command!" )
302 return main.FALSE
303
304 main.log.info( "Sending: " + cmd )
305 self.handle.sendline( cmd )
306 i = 0
307 while i < 2:
308 i = self.handle.expect( [
309 ssh_newkey,
310 'password:',
311 "100%",
312 refused,
313 "No such file or directory",
314 pexpect.EOF,
315 pexpect.TIMEOUT ],
316 120 )
317 if i == 0: # ask for ssh key confirmation
318 main.log.info( "ssh key confirmation received, sending yes" )
319 self.handle.sendline( 'yes' )
320 elif i == 1: # Asked for ssh password
321 main.log.info( "ssh connection asked for password, gave password" )
322 self.handle.sendline( pwd )
323 elif i == 2: # File finished transfering
324 main.log.info( "Secure copy successful" )
325 returnVal = main.TRUE
326 elif i == 3: # Connection refused
327 main.log.error(
328 "ssh: connect to host " +
329 ipAddress +
330 " port 22: Connection refused" )
331 returnVal = main.FALSE
332 elif i == 4: # File Not found
333 main.log.error( "No such file found" )
334 returnVal = main.FALSE
335 elif i == 5: # EOF
336 main.log.error( "Pexpect.EOF found!!!" )
337 main.cleanup()
338 main.exit()
339 elif i == 6: # timeout
340 main.log.error(
341 "No route to the Host " +
342 userName +
343 "@" +
344 ipAddress )
345 returnVal = main.FALSE
346 self.handle.expect( "\$" )
347 return returnVal
348
349 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
350 """
351 Definition:
352 Execute scp command in linux to copy to/from a remote host
353 Required:
354 * remoteHost - Test ON component to be parsed
355 str filePath - File path including the file it self
356 str dstPath - Destination path
357 Optional:
358 str direction - Direction of the scp, default to "from" which means
359 copy "from" the remote machine to local machine,
360 while "to" means copy "to" the remote machine from
361 local machine
362 """
363 return self.secureCopy( remoteHost.user_name,
364 remoteHost.ip_address,
365 filePath,
366 dstPath,
367 pwd=remoteHost.pwd,
368 direction=direction )