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