1
2
3
4
5
6
7
8
9
10
11 __doc__="""CollectorClient
12
13 Base class for client collectors
14
15 zCommandLoginTries - number of times to attempt to login
16 zCommandPathList - list of paths to check for a command
17 zCommandExistanceCheck - shell command issued to look for an executable
18 must echo succ if the executable is found
19 default: test -f executable
20
21 """
22
23 import os, sys
24 import logging
25 log = logging.getLogger("zen.CmdClient")
26
27 from twisted.internet import protocol
28
29 from BaseClient import BaseClient
30
32 """
33 Data collector client class to be subclassed by different types
34 collector protocols
35 """
36
37 maintainConnection = False
38 cmdindex = 0
39
40 - def __init__(self, hostname, ip, port, plugins=None, options=None,
41 device=None, datacollector=None, alog=None):
42 """
43 Gather our required zProperties
44
45 @param hostname: name of the remote device
46 @type hostname: string
47 @param ip: IP address of the remote device
48 @type ip: string
49 @param port: IP port number to listen on
50 @type port: integer
51 @param plugins: plugins to run
52 @type plugins: list
53 @param options: optparse options
54 @type options: optparse options object
55 @param device: DMD device object
56 @type device: device object
57 @param datacollector: datacollector
58 @type datacollector: datacollector object
59 @param alog: Python logging class object
60 @type alog: Python logging class object
61 """
62 BaseClient.__init__(self, device, datacollector)
63 from Products.ZenUtils.Utils import unused
64 unused(alog)
65 self.hostname = hostname
66 self.ip = ip
67 self.port = port
68 plugins = plugins or []
69 self.cmdmap = {}
70 self._commands = []
71 for plugin in plugins:
72 self.cmdmap[plugin.command] = plugin
73 self._commands.append(plugin.command)
74 self.results = []
75 self.protocol = None
76
77 if options:
78 defaultUsername = options.username
79 defaultPassword = options.password
80 defaultLoginTries = options.loginTries
81 defaultLoginTimeout = options.loginTimeout
82 defaultCommandTimeout = options.commandTimeout
83 defaultKeyPath = options.keyPath
84 defaultConcurrentSessions = options.concurrentSessions
85 defaultSearchPath = options.searchPath
86 defaultExistanceTest = options.existenceTest
87
88 if device:
89 self.username = getattr(device,
90 'zCommandUsername', defaultUsername)
91 self.password = getattr(device,
92 'zCommandPassword', defaultPassword)
93 self.loginTries = getattr(device,
94 'zCommandLoginTries', defaultLoginTries)
95 self.loginTimeout = getattr(device,
96 'zCommandLoginTimeout', defaultLoginTimeout)
97 self.commandTimeout = getattr(device,
98 'zCommandCommandTimeout', defaultCommandTimeout)
99 self.keyPath = getattr(device,
100 'zKeyPath', defaultKeyPath)
101 self.concurrentSessions = getattr(device,
102 'zSshConcurrentSessions', defaultConcurrentSessions)
103 self.port = getattr(device, 'zCommandPort', self.port)
104 self.searchPath = getattr(device,
105 'zCommandSearchPath', defaultSearchPath)
106 self.existenceTest = getattr(device,
107 'zCommandExistanceTest', defaultExistanceTest)
108 else:
109 self.username = defaultUsername
110 self.password = defaultPassword
111 self.loginTries = defaultLoginTries
112 self.loginTimeout = defaultLoginTimeout
113 self.commandTimeout = defaultCommandTimeout
114 self.keyPath = defaultKeyPath
115 self.concurrentSessions = defaultConcurrentSessions
116 self.searchPath = defaultSearchPath
117 self.existenceTest = defaultExistanceTest
118
119
121 """
122 Add a command to the list of commands to gather data
123
124 @param command: command
125 @type command: string
126 """
127 if isinstance(command, basestring):
128 self._commands.append(command)
129 else:
130 self._commands.extend(command)
131
132
133 - def addResult(self, command, data, exitCode):
134 """
135 Add a result pair to the results store
136
137 @param command: command
138 @type command: string
139 @param data: results of running the command
140 @type data: string
141 @param exitCode: exit code from executing the command
142 @type exitCode: integer
143 """
144 plugin = self.cmdmap.get(command, None)
145 self.results.append((plugin, data))
146
147
149 """
150 The commands which we will use to collect data
151
152 @return: commands
153 @rtype: list of strings
154 """
155 return self._commands
156
157
159 """
160 Return all of the results we have collected so far
161
162 @return: results
163 @rtype: list of strings
164 """
165 return self.results
166
167
169 """
170 Called by protocol to see if all commands have been run
171 """
172 return len(self.results) == len(self._commands)
173
174
176 """
177 Tell the datacollector that we are all done
178 """
179 log.info("command client finished collection for %s",self.hostname)
180 self.cmdindex = 0
181 if self.datacollector:
182 self.datacollector.clientFinished(self)
183
185 """
186 Clear out all member variables that are collections to avoid memory
187 leaks.
188 """
189 self.cmdmap = {}
190 self._commands = []
191 self.results = []
192
193
195 """
196 Build a list of command-line options we will accept
197
198 @param parser: optparse parser
199 @type parser: optparse object
200 @param usage: description of how to use the program
201 @type usage: string
202 @return: optparse parser
203 @rtype: optparse object
204 """
205
206
207
208 defaultUsername = os.environ.get('USER', '')
209 defaultPassword = ""
210 defaultLoginTries = 1
211 defaultLoginTimeout = 10
212 defaultCommandTimeout = 10
213 defaultKeyPath = '~/.ssh/id_dsa'
214 defaultConcurrentSessions = 10
215 defaultSearchPath = []
216 defaultExistanceTest = 'test -f %s'
217
218 if not usage:
219 usage = "%prog [options] hostname[:port] command"
220
221 if not parser:
222 from optparse import OptionParser
223 parser = OptionParser(usage=usage, )
224
225 parser.add_option('-u', '--user',
226 dest='username',
227 default=defaultUsername,
228 help='Login username')
229 parser.add_option('-P', '--password',
230 dest='password',
231 default=defaultPassword,
232 help='Login password')
233 parser.add_option('-t', '--loginTries',
234 dest='loginTries',
235 default=defaultLoginTries,
236 type = 'int',
237 help='Number of times to attempt to login')
238 parser.add_option('-L', '--loginTimeout',
239 dest='loginTimeout',
240 type = 'float',
241 default = defaultLoginTimeout,
242 help='Timeout period (secs) to find login expect statments')
243 parser.add_option('-T', '--commandTimeout',
244 dest='commandTimeout',
245 type = 'float',
246 default = defaultCommandTimeout,
247 help='Timeout period (secs) after issuing a command')
248 parser.add_option('-K', '--keyPath',
249 dest='keyPath',
250 default = defaultKeyPath,
251 help='Path to use when looking for SSH keys')
252 parser.add_option('-S', '--concurrentSessions',
253 dest='concurrentSessions',
254 type='int',
255 default = defaultConcurrentSessions,
256 help='Allowable number of concurrent SSH sessions')
257 parser.add_option('-s', '--searchPath',
258 dest='searchPath',
259 default=defaultSearchPath,
260 help='Path to use when looking for commands')
261 parser.add_option('-e', '--existenceTest',
262 dest='existenceTest',
263 default=defaultExistanceTest,
264 help='How to check if a command is available or not')
265 if not parser.has_option('-v'):
266 parser.add_option('-v', '--logseverity',
267 dest='logseverity',
268 default=logging.INFO,
269 type='int',
270 help='Logging severity threshold')
271 return parser
272
273
275 """
276 Command-line option parser
277
278 @param parser: optparse parser
279 @type parser: optparse object
280 @param port: IP port number to listen on
281 @type port: integer
282 @return: parsed options
283 @rtype: object
284 """
285 options, args = parser.parse_args()
286 if len(args) < 2:
287 parser.print_help()
288 sys.exit(1)
289 if args[0].find(':') > -1:
290 hostname,port = args[0].rsplit(':', 1)
291 else:
292 hostname = args[0]
293 options.hostname = hostname
294 options.port = port
295 options.commands = args[1:]
296 return options
297