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
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
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