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