1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 This module provides a collector daemon that polls Windows devices for changes
18 to Windows services. Retrieved status is then converted into Zenoss events
19 and sent back to ZenHub for further processing.
20 """
21
22 import logging
23
24
25
26
27
28 import pysamba.twisted.reactor
29
30 import Globals
31 import zope.component
32 import zope.interface
33
34 from twisted.internet import defer, reactor
35 from twisted.python.failure import Failure
36
37 from Products.ZenCollector.daemon import CollectorDaemon
38 from Products.ZenCollector.interfaces import ICollectorPreferences,\
39 IEventService,\
40 IScheduledTask
41 from Products.ZenCollector.tasks import SimpleTaskFactory,\
42 SimpleTaskSplitter,\
43 TaskStates
44 from Products.ZenEvents.ZenEventClasses import Error, Clear, Status_WinService, Status_Wmi
45 from Products.ZenModel.WinServiceClass import STARTMODE_AUTO
46 from Products.ZenUtils.observable import ObservableMixin
47 from Products.ZenWin.WMIClient import WMIClient
48 from Products.ZenWin.Watcher import Watcher
49 from Products.ZenWin.utils import addNTLMv2Option, setNTLMv2Auth
50
51
52
53
54 from Products.ZenUtils.Utils import unused
55 from Products.ZenCollector.services.config import DeviceProxy
56 unused(DeviceProxy)
57
58
59
60
61 log = logging.getLogger("zen.zenwin")
62
63
64
66 zope.interface.implements(ICollectorPreferences)
67
69 """
70 Construct a new ZenWinPreferences instance and provide default
71 values for needed attributes.
72 """
73 self.collectorName = "zenwin"
74 self.defaultRRDCreateCommand = None
75 self.cycleInterval = 5 * 60
76 self.configCycleInterval = 20
77 self.options = None
78
79
80
81 self.configurationService = 'Products.ZenWin.services.WinServiceConfig'
82
83 self.wmibatchSize = 10
84 self.wmiqueryTimeout = 1000
85
87 parser.add_option('--debug', dest='debug', default=False,
88 action='store_true',
89 help='Increase logging verbosity.')
90 parser.add_option('--proxywmi', dest='proxywmi',
91 default=False, action='store_true',
92 help='Use a process proxy to avoid long-term blocking'
93 )
94 parser.add_option('--queryTimeout', dest='queryTimeout',
95 default=None, type='int',
96 help='The number of milliseconds to wait for ' + \
97 'WMI query to respond. Overrides the ' + \
98 'server settings.')
99 parser.add_option('--batchSize', dest='batchSize',
100 default=None, type='int',
101 help='Number of data objects to retrieve in a ' +
102 'single WMI query.')
103 addNTLMv2Option(parser)
104
105 - def postStartup(self):
106
107 logseverity = self.options.logseverity
108 if logseverity <= 5:
109 pysamba.library.DEBUGLEVEL.value = 99
110
111
112 setNTLMv2Auth(self.options)
113
114
116 zope.interface.implements(IScheduledTask)
117
118 STATE_WMIC_CONNECT = 'WMIC_CONNECT'
119 STATE_WMIC_QUERY = 'WMIC_QUERY'
120 STATE_WMIC_PROCESS = 'WMIC_PROCESS'
121 STATE_WATCHER_CONNECT = 'WATCHER_CONNECT'
122 STATE_WATCHER_QUERY = 'WATCHER_QUERY'
123 STATE_WATCHER_PROCESS = 'WATCHER_PROCESS'
124
125
126 RUNNING = "running"
127 STOPPED = "stopped"
128
129 - def __init__(self,
130 deviceId,
131 taskName,
132 scheduleIntervalSeconds,
133 taskConfig):
134 """
135 Construct a new task instance to watch for Windows Event Log changes
136 for the specified device.
137
138 @param deviceId: the Zenoss deviceId to watch
139 @type deviceId: string
140 @param taskName: the unique identifier for this task
141 @type taskName: string
142 @param scheduleIntervalSeconds: the interval at which this task will be
143 collected
144 @type scheduleIntervalSeconds: int
145 @param taskConfig: the configuration for this task
146 """
147 super(ZenWinTask, self).__init__()
148
149 self.name = taskName
150 self.configId = deviceId
151 self.interval = scheduleIntervalSeconds
152 self.state = TaskStates.STATE_IDLE
153
154 self._taskConfig = taskConfig
155 self._devId = deviceId
156 self._manageIp = self._taskConfig.manageIp
157
158 self._eventService = zope.component.queryUtility(IEventService)
159 self._preferences = zope.component.queryUtility(ICollectorPreferences,
160 "zenwin")
161
162
163
164
165
166 self._batchSize = self._preferences.options.batchSize
167 if not self._batchSize:
168 self._batchSize = self._preferences.wmibatchSize
169 self._queryTimeout = self._preferences.options.queryTimeout
170 if not self._queryTimeout:
171 self._queryTimeout = self._preferences.wmiqueryTimeout
172
173 self._wmic = None
174 self._watcher = None
175 self._reset()
176
178 """
179 Reset the WMI client and notification query watcher connection to the
180 device, if they are presently active.
181 """
182 if self._wmic:
183 self._wmic.close()
184 self._wmic = None
185 if self._watcher:
186 self._watcher.close()
187 self._watcher = None
188
190 """
191 Callback activated when the task is complete so that final statistics
192 on the collection can be displayed.
193 """
194 if not isinstance(result, Failure):
195 log.debug("Device %s [%s] scanned successfully",
196 self._devId, self._manageIp)
197 else:
198 log.debug("Device %s [%s] scanned failed, %s",
199 self._devId, self._manageIp, result.getErrorMessage())
200
201
202
203 return result
204
230
240
242 """
243 Handle a result from the wmi query. Results from both the initial WMI
244 client query and the watcher's notification query are processed by
245 this method. Log running and stopped transitions. Send an event if the
246 service is monitored.
247 """
248 state = state.lower()
249 summary = "Windows service '%s' is %s" % (name, state)
250 logLevel = logging.DEBUG
251 if name in self._taskConfig.services:
252 was_running, stoppedSeverity, oldStartMode, monitoredStartModes = \
253 self._taskConfig.services[name]
254
255 running = (state == self.RUNNING)
256 service_was_important = (oldStartMode in monitoredStartModes)
257 service_is_important = (startMode in monitoredStartModes)
258
259 logLevel = logging.INFO
260 if service_is_important:
261 if running:
262 self._sendWinServiceEvent(name, summary, Clear)
263 else:
264 self._sendWinServiceEvent(name, summary, stoppedSeverity)
265 logLevel = logging.CRITICAL
266 else:
267
268
269 if service_was_important and not running:
270 self._sendWinServiceEvent(name, summary, Clear)
271
272 self._taskConfig.services[name] = (
273 running, stoppedSeverity, startMode, monitoredStartModes)
274
275 log.log(logLevel, '%s on %s', summary, self._devId)
276
278 """
279 Callback for a successful fetch of services from the remote device.
280 """
281 self.state = ZenWinTask.STATE_WATCHER_PROCESS
282
283 log.debug("Successful collection from %s [%s], results=%s",
284 self._devId, self._manageIp, results)
285
286
287 services = self._taskConfig.services.copy()
288 if results:
289 for result in [r.targetInstance for r in results]:
290 if result.state:
291 if result.name in services:
292
293 del services[result.name]
294 self._handleResult(
295 result.name, result.state, result.startmode)
296
297 for name, data in services.items():
298 running, failSeverity, startMode, monitoredStartModes = data
299 if running:
300 state = self.RUNNING
301 else:
302 state = self.STOPPED
303 self._handleResult(name, state, startMode)
304 if results:
305
306
307
308
309 log.debug("Queuing another fetch for %s [%s]",
310 self._devId, self._manageIp)
311 d = defer.Deferred()
312 reactor.callLater(0, d.callback, None)
313 d.addCallback(self._collectCallback)
314 return d
315
325
327 """
328 Callback called after a connect or previous collection so that another
329 collection can take place.
330 """
331 log.debug("Polling for events from %s [%s]",
332 self._devId, self._manageIp)
333
334 self.state = ZenWinTask.STATE_WATCHER_QUERY
335 d = self._watcher.getEvents(self._queryTimeout, self._batchSize)
336 d.addCallbacks(self._collectSuccessful, self._failure)
337 d.addCallbacks(self._deviceUp)
338 return d
339
341 """
342 Callback called after a successful connect to the remote Windows device.
343 """
344 log.debug("Connected to %s [%s]", self._devId, self._manageIp)
345
357
364
366 """
367 Called when a connection needs to be created to the remote Windows
368 device.
369 """
370 log.debug("Connecting to %s [%s]", self._devId, self._manageIp)
371 self.state = ZenWinTask.STATE_WMIC_CONNECT
372 self._wmic = WMIClient(self._taskConfig)
373 d = self._wmic.connect()
374 d.addCallback(self._initialQuery)
375 return d
376
379
381 log.debug("Scanning device %s [%s]", self._devId, self._manageIp)
382
383
384 if not self._watcher:
385 d = self._connect()
386 d.addCallbacks(self._connectCallback, self._failure)
387 else:
388
389
390
391 d = defer.Deferred()
392 reactor.callLater(0, d.callback, None)
393
394
395
396 d.addCallback(self._collectCallback)
397
398
399
400
401 d.addBoth(self._finished)
402
403
404
405 return d
406
407
408
409
410
411 if __name__ == '__main__':
412 myPreferences = ZenWinPreferences()
413 myTaskFactory = SimpleTaskFactory(ZenWinTask)
414 myTaskSplitter = SimpleTaskSplitter(myTaskFactory)
415 daemon = CollectorDaemon(myPreferences, myTaskSplitter)
416 daemon.run()
417