def onSuccess(self, results, config):
        data = self.new_data()

        datasource_by_pid = {}
        metrics_by_component = collections.defaultdict(
            lambda: collections.defaultdict(list))

        # Used for process restart checking.
        if not hasattr(self, 'previous_pids_by_component'):
            self.previous_pids_by_component = collections.defaultdict(set)

        pids_by_component = collections.defaultdict(set)

        # Win32_Process: Counts and correlation to performance table.
        process_key = [x for x in results if 'Win32_Process' in x.wql][0]
        for item in results[process_key]:
            processText = get_processText(item)

            for datasource in config.datasources:
                regex = re.compile(datasource.params['regex'])

                # Zenoss 4.2 2013-10-15 RPS style.
                if 'replacement' in datasource.params:
                    matcher = OSProcessDataMatcher(
                        includeRegex=datasource.params['includeRegex'],
                        excludeRegex=datasource.params['excludeRegex'],
                        replaceRegex=datasource.params['replaceRegex'],
                        replacement=datasource.params['replacement'],
                        primaryUrlPath=datasource.params['primaryUrlPath'],
                        generatedId=datasource.params['generatedId'])

                    if not matcher.matches(processText):
                        continue

                # Zenoss 4.2 intermediate style
                elif hasattr(OSProcess, 'matchRegex'):
                    excludeRegex = re.compile(
                        datasource.params['excludeRegex'])

                    basic_match = OSProcess.matchRegex(
                        regex, excludeRegex, processText)

                    if not basic_match:
                        continue

                    capture_match = OSProcess.matchNameCaptureGroups(
                        regex, processText, datasource.component)

                    if not capture_match:
                        continue

                # Zenoss 4.1-4.2 style.
                else:
                    if datasource.params['ignoreParameters']:
                        processText = item.ExecutablePath or item.Name

                    name, args = get_processNameAndArgs(item)
                    if datasource.params['ignoreParameters']:
                        proc_id = getProcessIdentifier(name, None)
                    else:
                        proc_id = getProcessIdentifier(name, args)

                    if datasource.component != prepId(proc_id):
                        continue

                datasource_by_pid[item.ProcessId] = datasource
                pids_by_component[datasource.component].add(item.ProcessId)

                # Track process count. Append 1 each time we find a
                # match because the generic aggregator below will sum
                # them up to the total count.
                metrics_by_component[datasource.component][COUNT_DATAPOINT].append(1)

        # Send process status events.
        for datasource in config.datasources:
            component = datasource.component

            if COUNT_DATAPOINT in metrics_by_component[component]:
                severity = 0
                summary = 'matching processes running'

                # Process restart checking.
                previous_pids = self.previous_pids_by_component.get(component)
                current_pids = pids_by_component.get(component)

                # No restart if there are no current or previous PIDs.
                # previous PIDs.
                if previous_pids and current_pids:

                    # Only consider PID changes a restart if all PIDs
                    # matching the process changed.
                    if current_pids.isdisjoint(previous_pids):
                        summary = 'matching processes restarted'

                        # If the process is configured to alert on
                        # restart, the first "up" won't be a clear.
                        if datasource.params['alertOnRestart']:
                            severity = datasource.params['severity']

            else:
                severity = datasource.params['severity']
                summary = 'no matching processes running'

                # Add a 0 count for process that aren't running.
                metrics_by_component[component][COUNT_DATAPOINT].append(0)

            data['events'].append({
                'device': datasource.device,
                'component': component,
                'eventClass': datasource.eventClass,
                'eventGroup': 'Process',
                'summary': summary,
                'severity': severity,
                })

        # Prepare for next cycle's restart check by merging current
        # process PIDs with previous. This is to catch restarts that
        # stretch across more than subsequent cycles.
        self.previous_pids_by_component.update(
            (c, p) for c, p in pids_by_component.iteritems() if p)

        # Win32_PerfFormattedData_PerfProc_Process: Datapoints.
        perf_key = [x for x in results if 'Win32_Perf' in x.wql][0]
        for item in results[perf_key]:
            if item.IDProcess not in datasource_by_pid:
                continue

            datasource = datasource_by_pid[item.IDProcess]
            for point in datasource.points:
                if point.id == COUNT_DATAPOINT:
                    continue

                try:
                    value = int(getattr(item, point.id))
                except (TypeError, ValueError):
                    LOG.warn(
                        "%s %s %s: Couldn't convert %r to integer",
                        datasource.device, datasource.component, point.id,
                        value)
                except AttributeError:
                    LOG.warn(
                        "%s %s: %s not in result",
                        datasource.device, datasource.component, point.id)
                else:
                    metrics_by_component[datasource.component][point.id].append(value)

        # Aggregate and store datapoint values.
        for component, points in metrics_by_component.iteritems():
            for point, values in points.iteritems():
                if point in NON_AGGREGATED_DATAPOINTS:
                    value = values[0]
                else:
                    value = sum(values)

                data['values'][component][point] = (value, 'N')

        # Send overall clear.
        data['events'].append({
            'device': config.id,
            'severity': Event.Clear,
            'eventClass': Status_OSProcess,
            'summary': 'process scan successful',
            })

        return data
示例#2
0
    def onSuccess(self, results, config):
        data = self.new_data()

        datasource_by_pid = {}
        metrics_by_component = collections.defaultdict(
            lambda: collections.defaultdict(list))

        # Used for process restart checking.
        if not hasattr(self, 'previous_pids_by_component'):
            self.previous_pids_by_component = collections.defaultdict(set)

        pids_by_component = collections.defaultdict(set)

        sorted_datasource = sorted(config.datasources,
                                   key=lambda x: x.params.get('sequence', 0))

        # Win32_Process: Counts and correlation to performance table.
        process_key = [x for x in results if 'Win32_Process' in x.wql][0]
        for item in results[process_key]:
            processText = get_processText(item)

            for datasource in sorted_datasource:
                regex = re.compile(datasource.params['regex'])

                # Zenoss 4.2 2013-10-15 RPS style.
                if 'replacement' in datasource.params:
                    matcher = OSProcessDataMatcher(
                        includeRegex=datasource.params['includeRegex'],
                        excludeRegex=datasource.params['excludeRegex'],
                        replaceRegex=datasource.params['replaceRegex'],
                        replacement=datasource.params['replacement'],
                        primaryUrlPath=datasource.params['primaryUrlPath'],
                        generatedId=datasource.params['generatedId'])

                    if not matcher.matches(processText):
                        continue

                # Zenoss 4.2 intermediate style
                elif hasattr(OSProcess, 'matchRegex'):
                    excludeRegex = re.compile(
                        datasource.params['excludeRegex'])

                    basic_match = OSProcess.matchRegex(regex, excludeRegex,
                                                       processText)

                    if not basic_match:
                        continue

                    capture_match = OSProcess.matchNameCaptureGroups(
                        regex, processText, datasource.component)

                    if not capture_match:
                        continue

                # Zenoss 4.1-4.2 style.
                else:
                    if datasource.params['ignoreParameters']:
                        processText = item.ExecutablePath or item.Name

                    name, args = get_processNameAndArgs(item)
                    if datasource.params['ignoreParameters']:
                        proc_id = getProcessIdentifier(name, None)
                    else:
                        proc_id = getProcessIdentifier(name, args)

                    if datasource.component != prepId(proc_id):
                        continue

                datasource_by_pid[item.ProcessId] = datasource
                pids_by_component[datasource.component].add(item.ProcessId)

                # Track process count. Append 1 each time we find a
                # match because the generic aggregator below will sum
                # them up to the total count.
                metrics_by_component[
                    datasource.component][COUNT_DATAPOINT].append(1)

                # Don't continue matching once a match is found.
                break

        # Send process status events.
        for datasource in config.datasources:
            component = datasource.component

            if COUNT_DATAPOINT in metrics_by_component[component]:
                severity = 0
                summary = 'matching processes running'

                # Process restart checking.
                previous_pids = self.previous_pids_by_component.get(component)
                current_pids = pids_by_component.get(component)

                # No restart if there are no current or previous PIDs.
                # previous PIDs.
                if previous_pids and current_pids:

                    # Only consider PID changes a restart if all PIDs
                    # matching the process changed.
                    if current_pids.isdisjoint(previous_pids):
                        summary = 'matching processes restarted'

                        # If the process is configured to alert on
                        # restart, the first "up" won't be a clear.
                        if datasource.params['alertOnRestart']:
                            severity = datasource.params['severity']

            else:
                severity = datasource.params['severity']
                summary = 'no matching processes running'

                # Add a 0 count for process that aren't running.
                metrics_by_component[component][COUNT_DATAPOINT].append(0)

            data['events'].append({
                'device': datasource.device,
                'component': component,
                'eventClass': datasource.eventClass,
                'eventGroup': 'Process',
                'summary': summary,
                'severity': severity,
            })

        # Prepare for next cycle's restart check by merging current
        # process PIDs with previous. This is to catch restarts that
        # stretch across more than subsequent cycles.
        self.previous_pids_by_component.update(
            (c, p) for c, p in pids_by_component.iteritems() if p)

        # Win32_PerfFormattedData_PerfProc_Process: Datapoints.
        perf_keys = [x for x in results if 'Win32_Perf' in x.wql]
        if perf_keys:
            for item in results[perf_keys[0]]:
                if item.IDProcess not in datasource_by_pid:
                    continue
                datasource = datasource_by_pid[item.IDProcess]
                for point in datasource.points:
                    if point.id == COUNT_DATAPOINT:
                        continue

                    try:
                        value = int(getattr(item, point.id))
                    except (TypeError, ValueError):
                        LOG.warn("%s %s %s: Couldn't convert %r to integer",
                                 datasource.device, datasource.component,
                                 point.id, value)
                    except AttributeError:
                        LOG.warn("%s %s: %s not in result", datasource.device,
                                 datasource.component, point.id)
                    else:
                        metrics_by_component[datasource.component][
                            point.id].append(value)

        # Aggregate and store datapoint values.
        for component, points in metrics_by_component.iteritems():
            for point, values in points.iteritems():
                if point in NON_AGGREGATED_DATAPOINTS:
                    value = values[0]
                else:
                    value = sum(values)

                data['values'][component][point] = (value, 'N')

        # Send overall clear.
        data['events'].append({
            'device': config.id,
            'severity': Event.Clear,
            'eventClass': Status_OSProcess,
            'summary': 'process scan successful',
        })

        generateClearAuthEvents(config, data['events'])

        return data
示例#3
0
    def processResults(self, cmd, results):
        matcher = OSProcessDataMatcher(includeRegex=cmd.includeRegex,
                                       excludeRegex=cmd.excludeRegex,
                                       replaceRegex=cmd.replaceRegex,
                                       replacement=cmd.replacement,
                                       primaryUrlPath=cmd.primaryUrlPath,
                                       generatedId=cmd.generatedId)

        def matches(processMetrics):
            pid, rss, cpu, cmdAndArgs = processMetrics
            return matcher.matches(cmdAndArgs)

        lines = cmd.result.output.splitlines()[1:]
        metrics = map(self._extractProcessMetrics, lines)
        matchingMetrics = filter(matches, metrics)

        # We can not take into account processes that have already been
        # matched by other process class
        if hasattr(cmd, 'already_matched_cmdAndArgs'):
            if cmd.already_matched_cmdAndArgs:
                matchingMetrics = [
                    m for m in matchingMetrics
                    if m[3] not in cmd.already_matched_cmdAndArgs
                ]
                cmd.already_matched_cmdAndArgs.extend(
                    [m[3] for m in matchingMetrics])
            else:
                cmd.already_matched_cmdAndArgs = [
                    m[3] for m in matchingMetrics
                ]

        pids, rss, cpu = self._combineProcessMetrics(matchingMetrics)

        processSet = cmd.displayName

        # report any processes that are missing, and post perf data
        missingeventSent = False
        for dp in cmd.points:
            # cmd.points = list of tuples ... each tuple contains one of the following:
            #    dictionary, count
            #    dictionary, cpu
            #    dictionary, mem
            if pids:
                if 'cpu' in dp.id:
                    results.values.append((dp, cpu))
                if 'mem' in dp.id:
                    results.values.append((dp, rss))
                if 'count' in dp.id:
                    results.values.append((dp, len(pids)))
            else:
                if 'count' in dp.id:
                    results.values.append((dp, 0))
                failSeverity = dp.data['failSeverity']
                # alert on missing (the process set contains 0 processes...)
                summary = 'Process set contains 0 running processes: %s' % processSet
                message = "%s\n   Using regex \'%s\' \n   All Processes have stopped since the last model occurred. Last Modification time (%s)" \
                            % (summary, cmd.includeRegex, cmd.deviceConfig.lastmodeltime)
                if missingeventSent != summary:
                    self.sendEvent(results,
                                   device=cmd.deviceConfig.device,
                                   summary=summary,
                                   message=message,
                                   component=processSet,
                                   eventKey=cmd.generatedId,
                                   severity=failSeverity)
                    log.warning("(%s) %s" % (cmd.deviceConfig.device, message))
                    missingeventSent = summary
        # When not instantiated for each call fixes missing messages
        missingeventSent = False

        # Report process changes
        # Note that we can't tell the difference between a
        # reconfiguration from zenhub and process that goes away.
        device = cmd.deviceConfig.device

        # Retrieve the current processes and corresponding pids
        afterPidsProcesses = {}
        if pids:
            afterPidsProcesses = pids
        afterPids = afterPidsProcesses.keys()
        afterProcessSetPIDs = {}
        afterProcessSetPIDs[processSet] = afterPids

        # Globals.MostRecentMonitoredTimePids is a global that simply keeps the most recent data ... used to retrieve the "before" at monitoring time
        if Globals.MostRecentMonitoredTimePids.get(device, None):
            beforePidsProcesses = Globals.MostRecentMonitoredTimePids[
                device].get(processSet, None)
        else:
            beforePidsProcesses = Globals.MostRecentMonitoredTimePids[
                device] = {}

        # the first time this runs ... there is no "before"
        # this occurs when beforePidsProcesses is an empty dict
        # we need to save off the current processes and continue til the next monitoring time when "before" and "after" will be present
        if beforePidsProcesses is None:
            log.debug(
                "No existing 'before' process information for process set: %s ... skipping"
                % processSet)
            Globals.MostRecentMonitoredTimePids[device][
                processSet] = afterPidsProcesses
            return

        beforePids = beforePidsProcesses.keys()
        beforeProcessSetPIDs = {}
        beforeProcessSetPIDs[processSet] = beforePids

        processState = determineProcessState(beforeProcessSetPIDs,
                                             afterProcessSetPIDs)
        (deadPids, restartedPids, newPids) = processState

        # only if configured to alert on restarts...
        alertOnRestart = dp.data['alertOnRestart']
        if alertOnRestart and restartedPids:
            droppedPids = []
            for pid in beforeProcessSetPIDs[processSet]:
                if pid not in afterProcessSetPIDs[processSet]:
                    droppedPids.append(pid)
            summary = 'Process(es) restarted in process set: %s' % processSet
            message = '%s\n Using regex \'%s\' Discarded dead pid(s) %s Using new pid(s) %s'\
                % (summary, cmd.includeRegex, droppedPids, afterProcessSetPIDs[processSet])
            self.sendEvent(results,
                           device=cmd.deviceConfig.device,
                           summary=summary,
                           message=message,
                           component=processSet,
                           eventKey=cmd.generatedId,
                           severity=cmd.severity)
            log.info("(%s) %s" % (cmd.deviceConfig.device, message))

        # report alive processes
        for alivePid in afterProcessSetPIDs[processSet]:
            if alivePid in restartedPids:
                continue
            summary = "Process up: %s" % processSet
            message = '%s\n Using regex \'%s\' with pid\'s %s ' % (
                summary, cmd.includeRegex, alivePid)
            self.sendEvent(results,
                           device=cmd.deviceConfig.device,
                           summary=summary,
                           message=message,
                           component=processSet,
                           eventKey=cmd.generatedId,
                           severity=Event.Clear)
            log.debug("(%s) %s" % (cmd.deviceConfig.device, message))

        for newPid in newPids:
            log.debug(
                "found new process: %s (pid: %d) on %s" %
                (afterPidsProcesses[newPid], newPid, cmd.deviceConfig.device))

        Globals.MostRecentMonitoredTimePids[device][
            processSet] = afterPidsProcesses