| Trees | Indices | Help |
|
|---|
|
|
1 ###########################################################################
2 #
3 # This program is part of Zenoss Core, an open source monitoring platform.
4 # Copyright (C) 2007, Zenoss Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License version 2 as published by
8 # the Free Software Foundation.
9 #
10 # For complete information please visit: http://www.zenoss.com/oss/
11 #
12 ###########################################################################
13
14 __doc__="""TelnetSession
15
16 TelnetSession is used by TelnetSession to issue commands to a machine
17 and return their output over the telnet protocol.
18
19 Device Tree Parameters are:
20
21 zTelnetLoginTries - number of times to try login default: 1
22 zTelnetLoginTimeout - timeout for expect statements during login default: 2
23 zTelnetPromptTimeout - pause used during prompt discovery default: 0.2
24 zTelnetCommandTimeout - default timeout when executing a command default: 5
25 zTelnetLoginRegex - regex to match the login prompt default: 'ogin:.$'
26 zTelnetPasswordRegex - regext to match the password prompt default: 'assword:.$'
27
28 Other Parameters that are used by both TelnetSession and SshTransport:
29 zCommandPathList - list of path to check for a command
30 zCommandExistanceCheck - shell command issued to look for executible
31 must echo succ if executible is found
32 default: test -f executible
33
34 $Id: TelnetClient.py,v 1.15 2004/04/05 02:05:30 edahl Exp $"""
35
36 __version__ = "$Revision: 1.15 $"[11:-2]
37
38 import Globals
39
40 #FIXME take away except when we are totally migrated
41 try:
42 from twisted.conch import telnet
43 except:
44 from twisted.protocols import telnet
45
46 from twisted.internet import protocol, reactor
47
48 import re
49 import logging
50 log = logging.getLogger("zen.TelnetClient")
51
52 import CollectorClient
53 from Exceptions import *
54
55 defaultPromptTimeout = 10
56 defaultCommandTimeout = 20
57 defaultLoginRegex = 'ogin:.$'
58 defaultPasswordRegex = 'assword:'
59 defaultEnable = False
60 defaultTermLength = False
61
62
63 responceMap = ("WILL", "WONT", "DO", "DONT")
64
66 "check to see if a device supports telnet"
67 from telnetlib import Telnet
68 import socket
69 try:
70 tn = Telnet(hostname)
71 tn.close()
72 return 1
73 except socket.error:
74 return 0
75
76
78 mode = 'Login'
79
80 timeout = 0
81 timeoutID = None
82 p1 = ""
83 p2 = ""
84 commandPrompt = ""
85 command = ''
86 enabled = -1
87 scCallLater = None
88 bytes = ''
89 lastwrite = ''
90 result = ''
91 buffer = ""
92
94 self.factory.myprotocol = self #bogus hack
95 self.hostname = self.factory.hostname
96 log.info("connected to device %s" % self.hostname)
97 self.startTimeout(self.factory.loginTimeout, self.loginTimeout)
98 self.protocol = telnet.TelnetProtocol()
99
100 # the following functions turn off all telnet options
102 log.debug("received telnet DO feature %s" % ord(feature))
103 if ord(feature) == 1:
104 self._iac_responce(telnet.WILL, feature)
105 else:
106 self._iac_responce(telnet.WONT, feature)
107
109 log.debug("received telnet DONT feature %s" % ord(feature))
110 self._iac_responce(telnet.WONT, feature)
111
113 log.debug("received telnet WILL feature %s" % ord(feature))
114 self._iac_responce(telnet.DONT, feature)
115
117 log.debug("received telnet WONT feature %s" % ord(feature))
118 self._iac_responce(telnet.DONT, feature)
119
121 log.debug("sending telnet action %s feature %s" %
122 (responceMap[ord(action)-251], ord(feature)))
123 self.write(telnet.IAC+action+feature)
124
125
127 "save the last bit of data that we wrote"
128 self.lastwrite = data
129 self.transport.write(data)
130
132 self.buffer = self.buffer + chunk
133 regex = None
134 if self.factory.modeRegex.has_key(self.mode):
135 regex = self.factory.modeRegex[self.mode]
136 log.debug("mode '%s' regex = %s" % (self.mode, regex))
137 log.debug("chunk received = '%s'" % chunk)
138 if regex and re.search(regex, chunk):
139 self.processLine(self.buffer)
140 self.buffer = ""
141
143 """I call a method that looks like 'telnet_*' where '*' is filled
144 in by the current mode. telnet_* methods should return a string which
145 will become the new mode."""
146 line = re.sub("\r\n|\r", "\n", line) #convert \r\n to \n
147 #if server is echoing take it out
148 if self.lastwrite.startswith(line):
149 self.lastwrite = self.lastwrite[len(line):]
150 line = ''
151 elif line.find(self.lastwrite) == 0:
152 line = line[len(self.lastwrite):]
153 log.debug("mode = %s", self.mode)
154 self.mode = getattr(self, "telnet_"+self.mode)(line)
155
157 telnet.Telnet.dataReceived(self, data)
158 log.debug('line %r', self.bytes)
159 if self.bytes:
160 self.processLine(self.bytes)
161 self.bytes = ''
162
165
166
168 self.cancelTimeout()
169 if timeoutfunc is None: timeoutfunc = self.defaultTimeout
170 self.timeoutID = reactor.callLater(timeout, timeoutfunc)
171
172
176
177
179 self.transport.loseConnection()
180 if self.factory.commandsFinished():
181 self.factory.clientFinished()
182 regex = self.factory.modeRegex.get(self.mode, "")
183 log.warn("dropping connection to %s: "
184 "state '%s' timeout %.1f seconds regex '%s' buffer '%s'",
185 self.factory.hostname, self.mode, self.timeout,regex,self.buffer)
186
187
188
190 if loginTries == 0:
191 loginTries = self.factory.loginTries
192 elif loginTries == 1:
193 self.transport.loseConnection()
194 self.factory.clientFinished()
195 log.warn("login to device %s failed" % self.hostname)
196 return "Done"
197 else:
198 self.factory.loginTries -= 1
199 return "Login"
200
201
203 "Called when login prompt is received"
204 log.debug('Search finds: %r', re.search(self.factory.loginRegex, data))
205 if not re.search(self.factory.loginRegex, data): # login failed
206 return 'Login'
207 log.debug("login tries=%s" % self.factory.loginTries)
208 if not self.factory.loginTries:
209 self.transport.loseConnection()
210 log.warn("login to %s with username %s failed" % (
211 self.factory.hostname, self.factory.username))
212 else:
213 self.factory.loginTries -= 1
214 log.debug("sending username %s" % self.factory.username)
215 self.write(self.factory.username + '\n')
216 return 'Password'
217
218
220 "Called when the password prompt is received"
221 if not re.search(self.factory.passwordRegex, data): # look for pw prompt
222 return 'Password'
223 log.debug("sending password %s" % self.factory.password)
224 self.write(self.factory.password + '\n')
225 self.startTimeout(self.factory.promptTimeout)
226 return 'FindPrompt'
227
228
230 "change to enable mode on cisco"
231 self.write('enable\n')
232 self.startTimeout(self.factory.loginTimeout, self.loginTimeout)
233 return "Password"
234
235
237 "Called after login to figure out the command prompt"
238 if not data.strip(): return 'FindPrompt'
239 if re.search(self.factory.loginRegex, data): # login failed
240 return self.telnet_Login(data)
241 self.p1 = data
242 if self.p1 == self.p2:
243 self.cancelTimeout() # promptTimeout
244 self.commandPrompt = self.p1
245 log.debug("found command prompt '%s'" % self.p1)
246 self.factory.modeRegex['Command'] = re.escape(self.p1) + "$"
247 self.factory.modeRegex['SendCommand'] = re.escape(self.p1) + "$"
248 if self.factory.enable:
249 self.factory.enable = False
250 return self.telnet_Enable("")
251 else:
252 self.scCallLater = reactor.callLater(1.0,
253 self.telnet_SendCommand, "")
254 return "ClearPromptData"
255 self.p2 = self.p1
256 self.p1 = ""
257 log.debug("sending \\n")
258 reactor.callLater(.1, self.write, "\n")
259 return 'FindPrompt'
260
262 if self.scCallLater: self.scCallLater.cancel()
263 self.scCallLater = reactor.callLater(1.0, self.telnet_SendCommand, "")
264 return "ClearPromptData"
265
267 "Get a command of the command stack and send it"
268 if self.scCallLater and self.scCallLater.active():
269 self.scCallLater.cancel()
270 log.debug("sending command '%s'" % self.curCommand())
271 self.write(self.curCommand() + '\n')
272 self.startTimeout(self.factory.commandTimeout)
273 self.mode = 'Command'
274 return 'Command'
275
276
278 """process the data from a sent command
279 if there are no more commands move to final state"""
280 self.result += data
281 if not self.result.endswith(self.commandPrompt):
282 log.debug("prompt '%s' not found", self.commandPrompt)
283 log.debug("line ends wth '%s'", data[-5:])
284 return 'Command'
285 self.cancelTimeout()
286 data, self.result = self.result, ''
287 log.debug("command = %s" % self.curCommand())
288 log.debug("data=%s" % data)
289 self.factory.addResult(self.curCommand(), data[0:-len(self.p1)], None)
290 self.factory.cmdindex += 1
291 if self.factory.commandsFinished():
292 self.factory.clientFinished()
293 if not self.factory.maintainConnection:
294 self.transport.loseConnection()
295 return 'Done'
296 else:
297 return self.telnet_SendCommand("")
298
299
302
303
305
306 - def __init__(self, hostname, ip, port, commands=[], options=None,
307 device=None, datacollector=None):
308 CollectorClient.CollectorClient.__init__(self, hostname, ip, port,
309 commands, options, device, datacollector)
310 self.protocol = TelnetClientProtocol
311 self.modeRegex = {
312 'FindPrompt' : '.*',
313 'WasteTime' : '.*',
314 'Done' : '',
315 }
316 self.promptPause = 1
317
318 if options:
319 defaultPromptTimeout = options.promptTimeout
320 defaultCommandTimeout = options.commandTimeout
321 defaultLoginRegex = options.loginRegex
322 defaultPasswordRegex = options.passwordRegex
323 defaultEnable = options.enable
324 defaultTermLength = options.termlen
325
326 if device: # if we are in zope look for parameters in aq path
327 self.promptTimeout = getattr(device,
328 'zTelnetPromptTimeout', defaultPromptTimeout)
329 self.loginRegex = getattr(device,
330 'zTelnetLoginRegex', defaultLoginRegex)
331 self.passwordRegex = getattr(device,
332 'zTelnetPasswordRegex', defaultPasswordRegex)
333 self.enable = getattr(device,
334 'zTelnetEnable', defaultEnable)
335 self.termlen = getattr(device,
336 'zTelnetTermLength', defaultTermLength)
337 else:
338 self.promptTimeout = defaultPromptTimeout
339 self.loginRegex = defaultLoginRegex
340 self.passwordRegex = defaultPasswordRegex
341 self.enable = defaultEnable
342 self.termlen = defaultTermLength
343
344 self.modeRegex['Login'] = self.loginRegex
345 self.modeRegex['Password'] = self.passwordRegex
346
347
349 """Start telnet collection.
350 """
351 if self.termlen:
352 self._commands.insert(0, "terminal length 0")
353 reactor.connectTCP(self.ip, self.port, self)
354
355
357 """add new commands to be run reset cmdindex to 0"""
358 CollectorClient.CollectorClient.addCommand(self, commands)
359 if self.myprotocol.mode != "Command":
360 self.myprotocol.telnet_SendCommand("")
361
362
364 """if we don't connect let the modeler know"""
365 log.warn(reason.getErrorMessage())
366 self.clientFinished()
367
368
370 CollectorClient.CollectorClient.clientFinished(self)
371 if __name__ == "__main__":
372 reactor.stop()
373
374
376 parser = CollectorClient.buildOptions(parser,usage)
377 parser.add_option('-r', '--promptTimeout',
378 dest='promptTimeout',
379 type = 'float',
380 default = defaultPromptTimeout,
381 help='timeout when discovering prompt')
382 parser.add_option('-x', '--loginRegex',
383 dest='loginRegex',
384 default = defaultLoginRegex,
385 help='regex that will find the login prompt')
386 parser.add_option('-w', '--passwordRegex',
387 dest='passwordRegex',
388 default = defaultPasswordRegex,
389 help='regex that will find the password prompt')
390 parser.add_option('--enable',
391 dest='enable', action='store_true', default=False,
392 help='enter enable mode on a cisco device')
393 parser.add_option('--termlen',
394 dest='termlen', action='store_true', default=False,
395 help='enter send terminal length 0 on a cisco device')
396 return parser
397
398
400 import socket
401 import getpass
402 parser = buildOptions()
403 options = CollectorClient.parseOptions(parser, 23)
404 if not options.password:
405 options.password = getpass.getpass("%s@%s's password: " %
406 (options.username, options.hostname))
407 logging.basicConfig(level=10)
408 commands = [("test", c) for c in options.commands]
409 client = TelnetClient(options.hostname,
410 socket.gethostbyname(options.hostname),
411 options.port,
412 commands=commands, options=options)
413 client.run()
414 def stop():
415 if client.commandsFinished():
416 reactor.stop()
417 else:
418 reactor.callLater(1, stop)
419 stop()
420 reactor.run()
421 import pprint
422 pprint.pprint(client.getResults())
423
424 if __name__ == '__main__':
425 main()
426
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Thu Oct 25 16:28:36 2007 | http://epydoc.sourceforge.net |