blob: 8fc92cae5ba9143ede47cad2e4e9f793b5a18e72 [file] [log] [blame]
A R Karthick72fcbc52017-03-06 12:35:17 -08001#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07002# 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
A R Karthick72fcbc52017-03-06 12:35:17 -08007#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07008# http://www.apache.org/licenses/LICENSE-2.0
A R Karthick72fcbc52017-03-06 12:35:17 -08009#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070010# 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 " + \
A R Karthick72fcbc52017-03-06 12:35:17 -080065 self.ip_address + " port {}: Connection refused".format(self.port)
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -070066 if self.port:
A R Karthick72fcbc52017-03-06 12:35:17 -080067 if os.getuid() == 0:
68 ssh_hosts_file = '/root/.ssh/known_hosts'
69 else:
70 ssh_hosts_file = os.path.join(os.getenv('HOME'), '.ssh', 'known_hosts')
71 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 -070072 os.system(cmd_host_remove)
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -070073 #main.log.info('SSH host remove cmd: %s' %cmd_host_remove)
74 main.log.info('Spawning pexpect for ip %s' %self.ip_address)
75 self.handle = pexpect.spawn(
76 'ssh -p ' +
77 self.port +
78 ' ' +
A R Karthick72fcbc52017-03-06 12:35:17 -080079 '-o StrictHostKeyChecking=no ' +
Chetan Gaonker3ff8eae2016-04-12 14:50:26 -070080 self.user_name +
81 '@' +
82 self.ip_address,
83 env={ "TERM": "xterm-mono" },
84 maxread=50000 )
85 else:
86 self.handle = pexpect.spawn(
87 'ssh -X ' +
88 self.user_name +
89 '@' +
90 self.ip_address,
91 env={ "TERM": "xterm-mono" },
92 maxread=1000000,
93 timeout=60 )
94
95 self.handle.logfile = self.logfile_handler
96 i = 5
97 while i == 5:
98 i = self.handle.expect( [
99 ssh_newkey,
100 'password:|Password:',
101 pexpect.EOF,
102 pexpect.TIMEOUT,
103 refused,
104 'teston>',
105 '>|#|\$' ],
106 120 )
107 if i == 0: # Accept key, then expect either a password prompt or access
108 main.log.info( "ssh key confirmation received, send yes" )
109 self.handle.sendline( 'yes' )
110 i = 5 # Run the loop again
111 continue
112 if i == 1: # Password required
113 if self.pwd:
114 main.log.info(
115 "ssh connection asked for password, gave password" )
116 else:
117 main.log.info( "Server asked for password, but none was "
118 "given in the .topo file. Trying "
119 "no password.")
120 self.pwd = ""
121 self.handle.sendline( self.pwd )
122 j = self.handle.expect( [
123 '>|#|\$',
124 'password:|Password:',
125 pexpect.EOF,
126 pexpect.TIMEOUT ],
127 120 )
128 if j != 0:
129 main.log.error( "Incorrect Password" )
130 return main.FALSE
131 elif i == 2:
132 main.log.error( "Connection timeout" )
133 return main.FALSE
134 elif i == 3: # timeout
135 main.log.error(
136 "No route to the Host " +
137 self.user_name +
138 "@" +
139 self.ip_address )
140 return main.FALSE
141 elif i == 4:
142 main.log.error(
143 "ssh: connect to host " +
144 self.ip_address +
145 " port 22: Connection refused" )
146 return main.FALSE
147 elif i == 6:
148 main.log.info( "Password not required logged in" )
149
150 self.handle.sendline( "" )
151 self.handle.expect( '>|#|\$' )
152 return self.handle
153
154 def disconnect( self ):
155 result = super( CLI, self ).disconnect( self )
156 result = main.TRUE
157 # self.execute( cmd="exit",timeout=120,prompt="(.*)" )
158
159 def execute( self, **execparams ):
160 """
161 It facilitates the command line execution of a given command. It has arguments as :
162 cmd => represents command to be executed,
163 prompt => represents expect command prompt or output,
164 timeout => timeout for command execution,
165 more => to provide a key press if it is on.
166
167 It will return output of command exection.
168 """
169 result = super( CLI, self ).execute( self )
170 defaultPrompt = '.*[$>\#]'
171 args = utilities.parse_args( [ "CMD",
172 "TIMEOUT",
173 "PROMPT",
174 "MORE" ],
175 **execparams )
176
177 expectPrompt = args[ "PROMPT" ] if args[ "PROMPT" ] else defaultPrompt
178 self.LASTRSP = ""
179 timeoutVar = args[ "TIMEOUT" ] if args[ "TIMEOUT" ] else 10
180 cmd = ''
181 if args[ "CMD" ]:
182 cmd = args[ "CMD" ]
183 else:
184 return 0
185 if args[ "MORE" ] is None:
186 args[ "MORE" ] = " "
187 self.handle.sendline( cmd )
188 self.lastCommand = cmd
189 index = self.handle.expect( [ expectPrompt,
190 "--More--",
191 'Command not found.',
192 pexpect.TIMEOUT,
193 "^:$" ],
194 timeout=timeoutVar )
195 if index == 0:
196 self.LASTRSP = self.LASTRSP + \
197 self.handle.before + self.handle.after
198 main.log.info( "Executed :" + str(cmd ) +
199 " \t\t Expected Prompt '" + str( expectPrompt) +
200 "' Found" )
201 elif index == 1:
202 self.LASTRSP = self.LASTRSP + self.handle.before
203 self.handle.send( args[ "MORE" ] )
204 main.log.info(
205 "Found More screen to go , Sending a key to proceed" )
206 indexMore = self.handle.expect(
207 [ "--More--", expectPrompt ], timeout=timeoutVar )
208 while indexMore == 0:
209 main.log.info(
210 "Found anoother More screen to go , Sending a key to proceed" )
211 self.handle.send( args[ "MORE" ] )
212 indexMore = self.handle.expect(
213 [ "--More--", expectPrompt ], timeout=timeoutVar )
214 self.LASTRSP = self.LASTRSP + self.handle.before
215 elif index == 2:
216 main.log.error( "Command not found" )
217 self.LASTRSP = self.LASTRSP + self.handle.before
218 elif index == 3:
219 main.log.error( "Expected Prompt not found, Time Out!!" )
220 main.log.error( expectPrompt )
221 self.LASTRSP = self.LASTRSP + self.handle.before
222 return self.LASTRSP
223 elif index == 4:
224 self.LASTRSP = self.LASTRSP + self.handle.before
225 # self.handle.send( args[ "MORE" ] )
226 self.handle.sendcontrol( "D" )
227 main.log.info(
228 "Found More screen to go, Sending a key to proceed" )
229 indexMore = self.handle.expect(
230 [ "^:$", expectPrompt ], timeout=timeoutVar )
231 while indexMore == 0:
232 main.log.info(
233 "Found another More screen to go, Sending a key to proceed" )
234 self.handle.sendcontrol( "D" )
235 indexMore = self.handle.expect(
236 [ "^:$", expectPrompt ], timeout=timeoutVar )
237 self.LASTRSP = self.LASTRSP + self.handle.before
238 main.last_response = self.remove_contol_chars( self.LASTRSP )
239 return self.LASTRSP
240
241 def remove_contol_chars( self, response ):
242 # 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 ) )
243 # response = re.sub( RE_XML_ILLEGAL, "\n", response )
244 response = re.sub( r"[\x01-\x1F\x7F]", "", response )
245 # response = re.sub( r"\[\d+\;1H", "\n", response )
246 response = re.sub( r"\[\d+\;\d+H", "", response )
247 return response
248
249 def runAsSudoUser( self, handle, pwd, default ):
250
251 i = handle.expect( [ ".ssword:*", default, pexpect.EOF ] )
252 if i == 0:
253 handle.sendline( pwd )
254 handle.sendline( "\n" )
255
256 if i == 1:
257 handle.expect( default )
258
259 if i == 2:
260 main.log.error( "Unable to run as Sudo user" )
261
262 return handle
263
264 def onfail( self ):
265 if 'onfail' in main.componentDictionary[ self.name ]:
266 commandList = main.componentDictionary[
267 self.name ][ 'onfail' ].split( "," )
268 for command in commandList:
269 response = self.execute(
270 cmd=command,
271 prompt="(.*)",
272 timeout=120 )
273
274 def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
275 direction="from" ):
276 """
277 Definition:
278 Execute scp command in linux to copy to/from a remote host
279 Required:
280 str userName - User name of the remote host
281 str ipAddress - IP address of the remote host
282 str filePath - File path including the file it self
283 str dstPath - Destination path
284 Optional:
285 str pwd - Password of the host
286 str direction - Direction of the scp, default to "from" which means
287 copy "from" the remote machine to local machine,
288 while "to" means copy "to" the remote machine from
289 local machine
290 """
291 returnVal = main.TRUE
292 ssh_newkey = 'Are you sure you want to continue connecting'
293 refused = "ssh: connect to host " + \
294 ipAddress + " port 22: Connection refused"
295
296 if direction == "from":
297 cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
298 str( filePath ) + ' ' + str( dstPath )
299 elif direction == "to":
300 cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
301 '@' + str( ipAddress ) + ':' + str( dstPath )
302 else:
303 main.log.debug( "Wrong direction using secure copy command!" )
304 return main.FALSE
305
306 main.log.info( "Sending: " + cmd )
307 self.handle.sendline( cmd )
308 i = 0
309 while i < 2:
310 i = self.handle.expect( [
311 ssh_newkey,
312 'password:',
313 "100%",
314 refused,
315 "No such file or directory",
316 pexpect.EOF,
317 pexpect.TIMEOUT ],
318 120 )
319 if i == 0: # ask for ssh key confirmation
320 main.log.info( "ssh key confirmation received, sending yes" )
321 self.handle.sendline( 'yes' )
322 elif i == 1: # Asked for ssh password
323 main.log.info( "ssh connection asked for password, gave password" )
324 self.handle.sendline( pwd )
325 elif i == 2: # File finished transfering
326 main.log.info( "Secure copy successful" )
327 returnVal = main.TRUE
328 elif i == 3: # Connection refused
329 main.log.error(
330 "ssh: connect to host " +
331 ipAddress +
332 " port 22: Connection refused" )
333 returnVal = main.FALSE
334 elif i == 4: # File Not found
335 main.log.error( "No such file found" )
336 returnVal = main.FALSE
337 elif i == 5: # EOF
338 main.log.error( "Pexpect.EOF found!!!" )
339 main.cleanup()
340 main.exit()
341 elif i == 6: # timeout
342 main.log.error(
343 "No route to the Host " +
344 userName +
345 "@" +
346 ipAddress )
347 returnVal = main.FALSE
348 self.handle.expect( "\$" )
349 return returnVal
350
351 def scp( self, remoteHost, filePath, dstPath, direction="from" ):
352 """
353 Definition:
354 Execute scp command in linux to copy to/from a remote host
355 Required:
356 * remoteHost - Test ON component to be parsed
357 str filePath - File path including the file it self
358 str dstPath - Destination path
359 Optional:
360 str direction - Direction of the scp, default to "from" which means
361 copy "from" the remote machine to local machine,
362 while "to" means copy "to" the remote machine from
363 local machine
364 """
365 return self.secureCopy( remoteHost.user_name,
366 remoteHost.ip_address,
367 filePath,
368 dstPath,
369 pwd=remoteHost.pwd,
370 direction=direction )