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