Esempio n. 1
0
    def wmiCollect(self, device, ip, timeout):
        """
        Start the Windows Management Instrumentation (WMI) collector

        @param device: device to collect against
        @type device: string
        @param ip: IP address of device to collect against
        @type ip: string
        @param timeout: timeout before failing the connection
        @type timeout: integer
        """
        if self.options.nowmi:
            return

        client = None
        try:
            plugins = self.selectPlugins(device, 'wmi')
            if not plugins:
                self.log.info("No WMI plugins found for %s" % device.id)
                return
            if self.checkCollection(device):
                self.log.info('WMI collector method for device %s' % device.id)
                self.log.info("plugins: %s",
                              ", ".join(map(lambda p: p.name(), plugins)))
                client = WMIClient(device, self, plugins)
            if not client or not plugins:
                self.log.warn("WMI collector creation failed")
                return
        except (SystemExit, KeyboardInterrupt):
            raise
        except Exception:
            self.log.exception("Error opening WMI collector")
        self.addClient(client, timeout, 'WMI', device.id)
Esempio n. 2
0
    def _connect(self):
        log.debug("Connecting to %s [%s]", self._devId, self._manageIp)
        self.state = ZenWinTask.STATE_WMIC_CONNECT
        self._wmic = WMIClient(self._taskConfig)
        yield self._wmic.connect()

        self.state = ZenWinTask.STATE_WMIC_QUERY
        wql = "SELECT Name, State, StartMode FROM Win32_Service"
        result = yield self._wmic.query({'query': wql})

        self.state = ZenWinTask.STATE_WMIC_PROCESS
        for service in result['query']:
            self._cacheServiceState(service)
        self._wmic.close()
        self._wmic = None

        self.state = ZenWinTask.STATE_WATCHER_CONNECT
        wql = "SELECT * FROM __InstanceModificationEvent WITHIN 5 "\
              "WHERE TargetInstance ISA 'Win32_Service'"
        self._watcher = Watcher(self._taskConfig, wql)
        yield self._watcher.connect()

        log.debug("Connected to %s [%s]", self._devId, self._manageIp)
    def _connect(self):
        log.debug("Connecting to %s [%s]", self._devId, self._manageIp)
        self.state = ZenWinTask.STATE_WMIC_CONNECT
        self._wmic = WMIClient(self._taskConfig)
        yield self._wmic.connect()
        
        self.state = ZenWinTask.STATE_WMIC_QUERY
        wql = "SELECT Name, State, StartMode FROM Win32_Service"
        result = yield self._wmic.query({'query': wql})
        
        self.state = ZenWinTask.STATE_WMIC_PROCESS
        for service in result['query']:
            self._cacheServiceState(service)
        self._wmic.close()
        self._wmic = None
        
        self.state = ZenWinTask.STATE_WATCHER_CONNECT
        wql = "SELECT * FROM __InstanceModificationEvent WITHIN 5 "\
              "WHERE TargetInstance ISA 'Win32_Service'"
        self._watcher = Watcher(self._taskConfig, wql)
        yield self._watcher.connect()

        log.debug("Connected to %s [%s]", self._devId, self._manageIp)
Esempio n. 4
0
class ZenWinTask(ObservableMixin):
    zope.interface.implements(IScheduledTask)

    STATE_WMIC_CONNECT = 'WMIC_CONNECT'
    STATE_WMIC_QUERY = 'WMIC_QUERY'
    STATE_WMIC_PROCESS = 'WMIC_PROCESS'
    STATE_WATCHER_CONNECT = 'WATCHER_CONNECT'
    STATE_WATCHER_QUERY = 'WATCHER_QUERY'
    STATE_WATCHER_PROCESS = 'WATCHER_PROCESS'

    # windows service states from wmi queries (lowercased)
    RUNNING = "running"
    STOPPED = "stopped"

    def __init__(self, deviceId, taskName, scheduleIntervalSeconds,
                 taskConfig):
        """
        Construct a new task instance to watch for Windows Event Log changes
        for the specified device.
        
        @param deviceId: the Zenoss deviceId to watch
        @type deviceId: string
        @param taskName: the unique identifier for this task
        @type taskName: string
        @param scheduleIntervalSeconds: the interval at which this task will be
               collected
        @type scheduleIntervalSeconds: int
        @param taskConfig: the configuration for this task
        """
        super(ZenWinTask, self).__init__()

        self.name = taskName
        self.configId = deviceId
        self.interval = scheduleIntervalSeconds
        self.state = TaskStates.STATE_IDLE

        self._taskConfig = taskConfig
        self._devId = deviceId
        self._manageIp = self._taskConfig.manageIp

        self._eventService = zope.component.queryUtility(IEventService)
        self._preferences = zope.component.queryUtility(
            ICollectorPreferences, "zenwin")

        # if the user hasn't specified the batchSize or queryTimeout as command
        # options then use whatever has been specified in the collector
        # preferences
        # TODO: convert these to zProperties
        self._batchSize = self._preferences.options.batchSize
        if not self._batchSize:
            self._batchSize = self._preferences.wmibatchSize
        self._queryTimeout = self._preferences.options.queryTimeout
        if not self._queryTimeout:
            self._queryTimeout = self._preferences.wmiqueryTimeout

        # Calculate the number of cycles, after which the state of every
        # service should be reinitialised, to make sure the service state
        # is up to date even if some notification messages were missed.
        self._refreshCycles = self._preferences.options.statusRefresh * 60 / self.interval
        self._currentCycles = 0

        self._wmic = None  # the WMIClient
        self._watcher = None
        self._reset()

    def _reset(self):
        """
        Reset the WMI client and notification query watcher connection to the
        device, if they are presently active.
        """
        if self._wmic:
            self._wmic.close()
        self._wmic = None
        if self._watcher:
            self._watcher.close()
        self._watcher = None

    def _sendWinServiceEvent(self, name, summary, severity):
        event = {
            'summary': summary,
            'eventClass': Status_WinService,
            'device': self._devId,
            'severity': severity,
            'agent': 'zenwin',
            'component': name,
            'eventGroup': 'StatusTest'
        }
        self._eventService.sendEvent(event)

    def _isRunning(self, state):
        return state.lower() == self.RUNNING

    def _cacheServiceState(self, service):
        if service.name in self._taskConfig.services:
            _, stoppedSeverity, _, monitoredStartModes = self._taskConfig.services[
                service.name]

            running = self._isRunning(service.state)
            log.debug("Service %s has initial state: %s mode: %s",
                      service.name, service.state, service.startMode)
            self._taskConfig.services[service.name] =\
                (running, stoppedSeverity, service.startMode, monitoredStartModes)

    def _handleResult(self, name, state, startMode):
        """
        Handle a result from the wmi query. Results from both the initial WMI
        client query and the watcher's notification query are processed by
        this method. Log running and stopped transitions. Send an event if the
        service is monitored.
        """
        if state is None:
            state = "unknown"
        state = state.lower()
        summary = "Windows service '%s' is %s" % (name, state)
        logLevel = logging.DEBUG
        if name in self._taskConfig.services:
            was_running, stoppedSeverity, oldStartMode, monitoredStartModes = \
                self._taskConfig.services[name]

            running = self._isRunning(state)
            service_was_important = (oldStartMode in monitoredStartModes)
            service_is_important = (startMode in monitoredStartModes)

            logLevel = logging.INFO
            if service_is_important:
                if running:
                    self._sendWinServiceEvent(name, summary, Clear)
                else:
                    self._sendWinServiceEvent(name, summary, stoppedSeverity)
                    logLevel = logging.CRITICAL
            else:
                self._sendWinServiceEvent(name, summary, Clear)

            self._taskConfig.services[name] = (running, stoppedSeverity,
                                               startMode, monitoredStartModes)

        logState = state
        if startMode == '' or startMode is None:
            logState = "unknown"
        summary = "Windows service '%s' is %s" % (name, logState)
        log.log(logLevel, '%s on %s', summary, self._devId)

    def cleanup(self):
        return self._reset()

    @defer.inlineCallbacks
    def _connect(self):
        log.debug("Connecting to %s [%s]", self._devId, self._manageIp)
        self.state = ZenWinTask.STATE_WMIC_CONNECT
        self._wmic = WMIClient(self._taskConfig)
        yield self._wmic.connect()

        self.state = ZenWinTask.STATE_WMIC_QUERY
        wql = "SELECT Name, State, StartMode FROM Win32_Service"
        result = yield self._wmic.query({'query': wql})

        self.state = ZenWinTask.STATE_WMIC_PROCESS
        for service in result['query']:
            self._cacheServiceState(service)
        self._wmic.close()
        self._wmic = None

        self.state = ZenWinTask.STATE_WATCHER_CONNECT
        wql = "SELECT * FROM __InstanceModificationEvent WITHIN 5 "\
              "WHERE TargetInstance ISA 'Win32_Service'"
        self._watcher = Watcher(self._taskConfig, wql)
        yield self._watcher.connect()

        log.debug("Connected to %s [%s]", self._devId, self._manageIp)

    @defer.inlineCallbacks
    def doTask(self):
        log.debug("Scanning device %s [%s]", self._devId, self._manageIp)

        try:
            # Refresh the initial state of services.
            if self._currentCycles >= self._refreshCycles:
                log.debug("Refreshing the initial states of services")
                self._reset()
                self._currentCycles = 0

            # see if we need to connect first before doing any collection
            if not self._watcher:
                yield self._connect()

            # try collecting events after a successful connect, or if we're already
            # connected
            if self._watcher:
                log.debug("Polling for events from %s [%s]", self._devId,
                          self._manageIp)

                # make a local copy of monitored services list
                services = self._taskConfig.services.copy()

                # read until we get an empty results list returned from our query
                self.state = ZenWinTask.STATE_WATCHER_QUERY
                results = []
                while True:
                    newresults = yield self._watcher.getEvents(
                        self._queryTimeout, self._batchSize)
                    if not newresults:
                        break
                    results.extend(newresults)
                    log.debug("Queuing another fetch for %s [%s]", self._devId,
                              self._manageIp)

                if log.isEnabledFor(logging.DEBUG):
                    showattrs = lambda ob, attrs: tuple(
                        getattr(ob, attr, '') for attr in attrs)
                    log.debug("Successful collection from %s [%s], results=%s",
                              self._devId, self._manageIp, [
                                  showattrs(r.targetInstance,
                                            ('name', 'state', 'startmode'))
                                  for r in results
                              ])

                self.state = ZenWinTask.STATE_WATCHER_PROCESS

                # collapse repeated results for same service - this maintains our
                # state model from collection to collection, without weird
                # intermediate states caused by multiple service state and
                # configuration changes between collections messing things up
                results_summary = {}
                for r in results:
                    result = r.targetInstance
                    if result.state:
                        results_summary[result.name] = r

                # now process all results to update service state
                # and emit CRITICAL/CLEAR events as needed
                for r in results_summary.itervalues():
                    result = r.targetInstance
                    # remove service from local copy
                    services.pop(result.name, None)
                    self._handleResult(result.name, result.state,
                                       result.startmode)

                # send events for the services that did not show up in results
                for name, data in services.iteritems():
                    running, failSeverity, startMode, monitoredStartModes = data
                    if running:
                        state = self.RUNNING
                    else:
                        state = self.STOPPED
                    self._handleResult(name, state, startMode)

                msg = 'WMI connection to %s up.' % self._devId
                self._eventService.sendEvent(
                    dict(summary=msg,
                         eventClass=Status_Wmi,
                         device=self._devId,
                         severity=Clear,
                         component='zenwin'))

                # Increment the number of cycles passed.
                self._currentCycles += 1

                log.debug("Device %s [%s] scanned successfully", self._devId,
                          self._manageIp)
        except Exception as e:
            err = str(e)
            log.debug("Device %s [%s] scanned failed, %s", self._devId,
                      self._manageIp, err)

            log.error("Unable to scan device %s: %s", self._devId, err)

            self._reset()

            summary = """
                Could not read Windows services (%s). Check your
                username/password settings and verify network connectivity.
                """ % err

            self._eventService.sendEvent(
                dict(summary=summary,
                     component='zenwin',
                     eventClass=Status_Wmi,
                     device=self._devId,
                     severity=Error,
                     traceback=traceback.format_exc()))
class ZenWinTask(ObservableMixin):
    zope.interface.implements(IScheduledTask)
        
    STATE_WMIC_CONNECT = 'WMIC_CONNECT'
    STATE_WMIC_QUERY = 'WMIC_QUERY'
    STATE_WMIC_PROCESS = 'WMIC_PROCESS'
    STATE_WATCHER_CONNECT = 'WATCHER_CONNECT'
    STATE_WATCHER_QUERY = 'WATCHER_QUERY'
    STATE_WATCHER_PROCESS = 'WATCHER_PROCESS'
    
    # windows service states from wmi queries (lowercased)
    RUNNING = "running"
    STOPPED = "stopped"
    
    def __init__(self,
                 deviceId,
                 taskName,
                 scheduleIntervalSeconds,
                 taskConfig):
        """
        Construct a new task instance to watch for Windows Event Log changes
        for the specified device.
        
        @param deviceId: the Zenoss deviceId to watch
        @type deviceId: string
        @param taskName: the unique identifier for this task
        @type taskName: string
        @param scheduleIntervalSeconds: the interval at which this task will be
               collected
        @type scheduleIntervalSeconds: int
        @param taskConfig: the configuration for this task
        """
        super(ZenWinTask, self).__init__()
        
        self.name = taskName
        self.configId = deviceId
        self.interval = scheduleIntervalSeconds
        self.state = TaskStates.STATE_IDLE
        
        self._taskConfig = taskConfig
        self._devId = deviceId
        self._manageIp = self._taskConfig.manageIp
        
        self._eventService = zope.component.queryUtility(IEventService)
        self._preferences = zope.component.queryUtility(ICollectorPreferences,
                                                        "zenwin")
                                                        
        # if the user hasn't specified the batchSize or queryTimeout as command
        # options then use whatever has been specified in the collector
        # preferences
        # TODO: convert these to zProperties
        self._batchSize = self._preferences.options.batchSize
        if not self._batchSize:
            self._batchSize = self._preferences.wmibatchSize
        self._queryTimeout = self._preferences.options.queryTimeout
        if not self._queryTimeout:
            self._queryTimeout = self._preferences.wmiqueryTimeout

        # Calculate the number of cycles, after which the state of every
        # service should be reinitialised, to make sure the service state
        # is up to date even if some notification messages were missed.
        self._refreshCycles = self._preferences.options.statusRefresh * 60 / self.interval
        self._currentCycles = 0

        self._wmic = None # the WMIClient
        self._watcher = None
        self._reset()
        
    def _reset(self):
        """
        Reset the WMI client and notification query watcher connection to the
        device, if they are presently active.
        """
        if self._wmic:
            self._wmic.close()
        self._wmic = None
        if self._watcher:
            self._watcher.close()
        self._watcher = None
        
    def _sendWinServiceEvent(self, name, summary, severity):
        event = {'summary': summary,
                 'eventClass': Status_WinService,
                 'device': self._devId,
                 'severity': severity,
                 'agent': 'zenwin',
                 'component': name,
                 'eventGroup': 'StatusTest'}
        self._eventService.sendEvent(event)
    
    def _isRunning(self, state):
        return state.lower() == self.RUNNING

    def _cacheServiceState(self, service):
        if service.name in self._taskConfig.services:
            _, stoppedSeverity, _, monitoredStartModes = self._taskConfig.services[service.name]

            running = self._isRunning(service.state)
            log.debug("Service %s has initial state: %s mode: %s", 
                        service.name, service.state, service.startMode)
            self._taskConfig.services[service.name] =\
                (running, stoppedSeverity, service.startMode, monitoredStartModes)

    def _handleResult(self, name, state, startMode):
        """
        Handle a result from the wmi query. Results from both the initial WMI
        client query and the watcher's notification query are processed by
        this method. Log running and stopped transitions. Send an event if the
        service is monitored.
        """
        if state is None:
            state = "unknown"
        state = state.lower()
        summary = "Windows service '%s' is %s" % (name, state)
        logLevel = logging.DEBUG
        if name in self._taskConfig.services:
            was_running, stoppedSeverity, oldStartMode, monitoredStartModes = \
                self._taskConfig.services[name]

            running = self._isRunning(state)
            service_was_important = (oldStartMode in monitoredStartModes)
            service_is_important = (startMode in monitoredStartModes)

            logLevel = logging.INFO
            if service_is_important:
                if running:
                    self._sendWinServiceEvent(name, summary, Clear)
                else:
                    self._sendWinServiceEvent(name, summary, stoppedSeverity)
                    logLevel = logging.CRITICAL
            else:
                self._sendWinServiceEvent(name, summary, Clear)

            self._taskConfig.services[name] = (
                running, stoppedSeverity, startMode, monitoredStartModes)

        logState = state
        if startMode == '' or startMode is None:
            logState = "unknown"
        summary = "Windows service '%s' is %s" % (name, logState)
        log.log(logLevel, '%s on %s', summary, self._devId)
        
    def cleanup(self):
        return self._reset()

    @defer.inlineCallbacks
    def _connect(self):
        log.debug("Connecting to %s [%s]", self._devId, self._manageIp)
        self.state = ZenWinTask.STATE_WMIC_CONNECT
        self._wmic = WMIClient(self._taskConfig)
        yield self._wmic.connect()
        
        self.state = ZenWinTask.STATE_WMIC_QUERY
        wql = "SELECT Name, State, StartMode FROM Win32_Service"
        result = yield self._wmic.query({'query': wql})
        
        self.state = ZenWinTask.STATE_WMIC_PROCESS
        for service in result['query']:
            self._cacheServiceState(service)
        self._wmic.close()
        self._wmic = None
        
        self.state = ZenWinTask.STATE_WATCHER_CONNECT
        wql = "SELECT * FROM __InstanceModificationEvent WITHIN 5 "\
              "WHERE TargetInstance ISA 'Win32_Service'"
        self._watcher = Watcher(self._taskConfig, wql)
        yield self._watcher.connect()

        log.debug("Connected to %s [%s]", self._devId, self._manageIp)
    
    @defer.inlineCallbacks
    def doTask(self):
        log.debug("Scanning device %s [%s]", self._devId, self._manageIp)
        
        try:
            # Refresh the initial state of services.
            if self._currentCycles >= self._refreshCycles:
                log.debug("Refreshing the initial states of services")
                self._reset()
                self._currentCycles = 0

            # see if we need to connect first before doing any collection
            if not self._watcher:
                yield self._connect()
    
            # try collecting events after a successful connect, or if we're already
            # connected
            if self._watcher:
                log.debug("Polling for events from %s [%s]", self._devId, self._manageIp)
        
                # make a local copy of monitored services list
                services = self._taskConfig.services.copy()
                
                # read until we get an empty results list returned from our query
                self.state = ZenWinTask.STATE_WATCHER_QUERY
                results = []
                while True:
                    newresults = yield self._watcher.getEvents(self._queryTimeout, self._batchSize)
                    if not newresults:
                        break
                    results.extend(newresults)
                    log.debug("Queuing another fetch for %s [%s]", self._devId, self._manageIp)

                if log.isEnabledFor(logging.DEBUG):
                    showattrs = lambda ob,attrs: tuple(getattr(ob,attr,'') for attr in attrs)
                    log.debug("Successful collection from %s [%s], results=%s",
                              self._devId, self._manageIp, 
                              [showattrs(r.targetInstance, ('name','state','startmode')) for r in results]
                              )

                self.state = ZenWinTask.STATE_WATCHER_PROCESS

                # collapse repeated results for same service - this maintains our
                # state model from collection to collection, without weird 
                # intermediate states caused by multiple service state and 
                # configuration changes between collections messing things up
                results_summary = {}
                for r in results:
                    result = r.targetInstance
                    if result.state:
                        results_summary[result.name] = r

                # now process all results to update service state
                # and emit CRITICAL/CLEAR events as needed
                for r in results_summary.itervalues():
                    result = r.targetInstance
                    # remove service from local copy
                    services.pop(result.name, None)
                    self._handleResult(result.name, result.state, result.startmode)

                # send events for the services that did not show up in results
                for name, data in services.iteritems():
                    running, failSeverity, startMode, monitoredStartModes = data
                    if running:
                        state = self.RUNNING
                    else:
                        state = self.STOPPED
                    self._handleResult(name, state, startMode)

                msg = 'WMI connection to %s up.' % self._devId
                self._eventService.sendEvent(dict(
                    summary=msg,
                    eventClass=Status_Wmi,
                    device=self._devId,
                    severity=Clear,
                    component='zenwin'))

                # Increment the number of cycles passed.
                self._currentCycles += 1

                log.debug("Device %s [%s] scanned successfully",
                          self._devId, self._manageIp)
        except Exception as e:
            err = str(e)
            log.debug("Device %s [%s] scanned failed, %s",
                      self._devId, self._manageIp, err)

            log.error("Unable to scan device %s: %s", self._devId, err)

            self._reset()

            summary = """
                Could not read Windows services (%s). Check your
                username/password settings and verify network connectivity.
                """ % err

            self._eventService.sendEvent(dict(
                summary=summary,
                component='zenwin',
                eventClass=Status_Wmi,
                device=self._devId,
                severity=Error,
                traceback=traceback.format_exc()
                ))