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 type(command) == type(''):
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 if os.environ.has_key('USER'):
212 defaultUsername = os.environ['USER']
213 else:
214 defaultUsername = ""
215 defaultPassword = ""
216 defaultLoginTries = 1
217 defaultLoginTimeout = 10
218 defaultCommandTimeout = 10
219 defaultKeyPath = '~/.ssh/id_dsa'
220 defaultConcurrentSessions = 10
221 defaultSearchPath = []
222 defaultExistanceTest = 'test -f %s'
223
224 if not usage:
225 usage = "%prog [options] hostname[:port] command"
226
227 if not parser:
228 from optparse import OptionParser
229 parser = OptionParser(usage=usage, )
230
231 parser.add_option('-u', '--user',
232 dest='username',
233 default=defaultUsername,
234 help='Login username')
235 parser.add_option('-P', '--password',
236 dest='password',
237 default=defaultPassword,
238 help='Login password')
239 parser.add_option('-t', '--loginTries',
240 dest='loginTries',
241 default=defaultLoginTries,
242 type = 'int',
243 help='Number of times to attempt to login')
244 parser.add_option('-L', '--loginTimeout',
245 dest='loginTimeout',
246 type = 'float',
247 default = defaultLoginTimeout,
248 help='Timeout period (secs) to find login expect statments')
249 parser.add_option('-T', '--commandTimeout',
250 dest='commandTimeout',
251 type = 'float',
252 default = defaultCommandTimeout,
253 help='Timeout period (secs) after issuing a command')
254 parser.add_option('-K', '--keyPath',
255 dest='keyPath',
256 default = defaultKeyPath,
257 help='Path to use when looking for SSH keys')
258 parser.add_option('-S', '--concurrentSessions',
259 dest='concurrentSessions',
260 default = defaultConcurrentSessions,
261 help='Allowable number of concurrent SSH sessions')
262 parser.add_option('-s', '--searchPath',
263 dest='searchPath',
264 default=defaultSearchPath,
265 help='Path to use when looking for commands')
266 parser.add_option('-e', '--existenceTest',
267 dest='existenceTest',
268 default=defaultExistanceTest,
269 help='How to check if a command is available or not')
270 if not parser.has_option('-v'):
271 parser.add_option('-v', '--logseverity',
272 dest='logseverity',
273 default=logging.INFO,
274 type='int',
275 help='Logging severity threshold')
276 return parser
277
278
280 """
281 Command-line option parser
282
283 @param parser: optparse parser
284 @type parser: optparse object
285 @param port: IP port number to listen on
286 @type port: integer
287 @return: parsed options
288 @rtype: object
289 """
290 options, args = parser.parse_args()
291 if len(args) < 2:
292 parser.print_help()
293 sys.exit(1)
294 if args[0].find(':') > -1:
295 hostname,port = args[0].split(':')
296 else:
297 hostname = args[0]
298 options.hostname = hostname
299 options.port = port
300 options.commands = args[1:]
301 return options
302