def __init__(self, context): super(ZepFacade, self).__init__(context) config = getGlobalConfiguration() zep_url = config.get('zep-uri', 'http://localhost:8084') schema = getUtility(IQueueSchema) self.client = ZepServiceClient(zep_url, schema) self.configClient = ZepConfigClient(zep_url, schema) self.heartbeatClient = ZepHeartbeatClient(zep_url, schema) self._guidManager = IGUIDManager(context.dmd)
class ZepFacade(ZuulFacade): implements(IZepFacade) AND = AND OR = OR DEFAULT_SORT_MAP = { 'eventstate': { 'field': EventSort.STATUS }, 'eventstatetext':{ 'field': EventSort.STATUS }, 'severity': { 'field': EventSort.SEVERITY }, 'firsttime': { 'field': EventSort.FIRST_SEEN }, 'lasttime': { 'field': EventSort.LAST_SEEN }, 'eventclass': { 'field': EventSort.EVENT_CLASS }, 'device': { 'field': EventSort.ELEMENT_TITLE }, 'component': { 'field': EventSort.ELEMENT_SUB_TITLE }, 'count': { 'field': EventSort.COUNT }, 'summary': { 'field': EventSort.EVENT_SUMMARY }, 'ownerid': { 'field': EventSort.CURRENT_USER_NAME }, 'agent': { 'field': EventSort.AGENT }, 'monitor': { 'field': EventSort.MONITOR }, 'eventkey': { 'field': EventSort.EVENT_KEY }, 'evid': { 'field': EventSort.UUID }, 'statechange': { 'field': EventSort.STATUS_CHANGE }, 'dedupid': { 'field': EventSort.FINGERPRINT }, 'eventclasskey': { 'field': EventSort.EVENT_CLASS_KEY }, 'eventgroup': { 'field': EventSort.EVENT_GROUP }, } SORT_DIRECTIONAL_MAP = { 'asc' : EventSort.ASCENDING, 'desc' : EventSort.DESCENDING, } ZENOSS_DETAIL_OLD_TO_NEW_MAPPING = { 'prodState': EventProxy.PRODUCTION_STATE_DETAIL_KEY, 'DevicePriority': EventProxy.DEVICE_PRIORITY_DETAIL_KEY, 'ipAddress': EventProxy.DEVICE_IP_ADDRESS_DETAIL_KEY, 'Location': EventProxy.DEVICE_LOCATION_DETAIL_KEY, 'DeviceGroups': EventProxy.DEVICE_GROUPS_DETAIL_KEY, 'Systems': EventProxy.DEVICE_SYSTEMS_DETAIL_KEY, 'DeviceClass': EventProxy.DEVICE_CLASS_DETAIL_KEY, } ZENOSS_DETAIL_NEW_TO_OLD_MAPPING = dict((new, old) for old, new in ZENOSS_DETAIL_OLD_TO_NEW_MAPPING.iteritems()) JAVA_MIN_INTEGER = -2147483648 # Values that zep uses to index details with no value ZENOSS_NULL_NUMERIC_DETAIL_INDEX_VALUE = JAVA_MIN_INTEGER ZENOSS_NULL_TEXT_DETAIL_INDEX_VALUE = '\x07' SEVERITIES_BATCH_SIZE = 400 COUNT_REGEX = re.compile(r'^(?P<from>\d+)?:?(?P<to>\d+)?$') def __init__(self, context): super(ZepFacade, self).__init__(context) config = getGlobalConfiguration() zep_url = config.get('zep-uri', 'http://localhost:8084') schema = getUtility(IQueueSchema) self.client = ZepServiceClient(zep_url, schema) self.configClient = ZepConfigClient(zep_url, schema) self.heartbeatClient = ZepHeartbeatClient(zep_url, schema) self._guidManager = IGUIDManager(context.dmd) self.statsClient = ZepStatsClient(zep_url, schema) def _create_identifier_filter(self, value): if not isinstance(value, (tuple, list, set)): value = (value,) return map(lambda s:str(s).strip(), value) def _createFullTextSearch(self, parameter): if not hasattr(parameter, '__iter__'): parameter = (parameter,) return map(lambda s:str(s).strip(), parameter) def createEventFilter(self, severity=(), status=(), event_class=(), first_seen=None, last_seen=None, status_change=None, update_time=None, count_range=None, element_identifier=(), element_title=(), element_sub_identifier=(), element_sub_title=(), uuid=(), event_summary=None, tags=(), fingerprint=(), agent=(), monitor=(), event_key=(), current_user_name=(), subfilter=(), operator=None, details=None, event_class_key=(), event_group=(), message=()): """ Creates a filter based on passed arguments. Caller is responsible for handling the include-zero-items case. For example, passing an empty uuid tuple won't filter by uuid so includes everything. """ filter = {} if uuid: filter['uuid'] = uuid if event_summary: filter['event_summary'] = self._createFullTextSearch(event_summary) if event_class: filter['event_class'] = event_class if status: filter['status'] = status if severity: filter['severity'] = severity if first_seen: filter['first_seen'] = self._timeRange(first_seen) if last_seen: filter['last_seen'] = self._timeRange(last_seen) if status_change: filter['status_change'] = self._timeRange(status_change) if update_time: filter['update_time'] = self._timeRange(update_time) # These tags come from params, which means for some reason someone is filtering manually on a tag. if tags: filter['tag_filter'] = {'tag_uuids': tags} if count_range: if not isinstance(count_range, (tuple, list)): try: count = int(count_range) count_range = (count, count) except ValueError: match = ZepFacade.COUNT_REGEX.match(count_range) if not match: raise ValueError('Invalid range: %s' % (count_range)) count_range = (match.group('from'), match.group('to')) filter['count_range'] = {} count_from, count_to = count_range if count_from is not None: filter['count_range']['from'] = int(count_from) if count_to is not None: filter['count_range']['to'] = int(count_to) if element_identifier: filter['element_identifier'] = self._create_identifier_filter(element_identifier) if element_title: filter['element_title'] = self._create_identifier_filter(element_title) if element_sub_identifier: filter['element_sub_identifier'] = self._create_identifier_filter(element_sub_identifier) if element_sub_title: filter['element_sub_title'] = self._create_identifier_filter(element_sub_title) if fingerprint: filter['fingerprint'] = fingerprint if agent: filter['agent'] = agent if monitor: filter['monitor'] = monitor if event_key: filter['event_key'] = event_key if current_user_name: filter['current_user_name'] = current_user_name if subfilter: filter['subfilter'] = subfilter if details: filter['details'] = self._createEventDetailFilter(details) if event_class_key: filter['event_class_key'] = event_class_key if event_group: filter['event_group'] = event_group if message: filter['message'] = self._createFullTextSearch(message) # Everything's repeated on the protobuf, so listify result = dict((k, listify(v)) for k,v in filter.iteritems()) if operator: result['operator'] = operator return result def _createEventDetailFilter(self, details): """ @param details: All details present in this filter request. Example: { 'zenoss.device.production_state' = 4, 'zenoss.device.priority' : 2 } @type details: dict """ detailFilterItems = [] for key, val in details.iteritems(): detailFilterItems.append({ 'key': key, 'value': val, }) log.debug('Final detail filter: %r' % detailFilterItems) return detailFilterItems def _timeRange(self, timeRange): d = { 'start_time' : timeRange[0], } if len(timeRange) == 2: d['end_time'] = timeRange[1] return d def _getEventSort(self, sortParam): eventSort = {} if isinstance(sortParam, (list, tuple)): field, direction = sortParam eventSort['direction'] = self.SORT_DIRECTIONAL_MAP[direction.lower()] else: field = sortParam eventSort.update(getDetailsInfo().getSortMap()[field.lower()]) return from_dict(EventSort, eventSort) def _getUserUuid(self, userName): # We have to call _getOb instead of getUserSettings here because the # latter will create a new user settings object even if the user is # not known. try: user = self._dmd.ZenUsers._getOb(userName) return IGlobalIdentifier(user).getGUID() except AttributeError: raise Exception('Could not find user "%s"' % userName) def _findUserInfo(self): userName = getSecurityManager().getUser().getId() return self._getUserUuid(userName), userName def addNote(self, uuid, message, userName, userUuid=None): if userName and not userUuid: userUuid = self._getUserUuid(userName) self.client.addNote(uuid, message, userUuid, userName) def addNoteBulkAsync(self, uuids, message, userName, userUuid=None): if userName and not userUuid: userUuid = self._getUserUuid(userName) self.client.addNoteBulkAsync(uuids, message, userUuid, userName) def postNote(self, uuid, note): self.client.postNote(uuid, from_dict(EventNote, note)) def _getEventSummaries(self, source, offset, limit=1000): response, content = source(offset=offset, limit=limit) return { 'total' : content.total, 'limit' : content.limit, 'next_offset' : content.next_offset if content.HasField('next_offset') else None, 'events' : (to_dict(event) for event in content.events), } def getEventSummariesFromArchive(self, offset, limit=1000, sort=None, filter=None, exclusion_filter=None): return self.getEventSummaries(offset, limit, sort, filter, client_fn=self.client.getEventSummariesFromArchive, exclusion_filter=exclusion_filter) def getEventSummaries(self, offset, limit=1000, sort=None, filter=None, exclusion_filter=None, client_fn=None, use_permissions=False): if client_fn is None: client_fn = self.client.getEventSummaries if filter is not None and isinstance(filter,dict): filter = from_dict(EventFilter, filter) if exclusion_filter is not None and isinstance(exclusion_filter, dict): exclusion_filter['operator'] = 1 # Set operator to OR exclusion_filter = from_dict(EventFilter, exclusion_filter) if sort is not None: sort = tuple(self._getEventSort(s) for s in safeTuple(sort)) result = None if use_permissions: user = getSecurityManager().getUser() userSettings = self._dmd.ZenUsers._getOb(user.getId()) hasGlobalRoles = not userSettings.hasNoGlobalRoles() if not hasGlobalRoles: # get guids for the objects user has permission to access # and add to filter guids = userSettings.getAllAdminGuids(returnChildrenForRootObj=True) if guids: if filter is None: filter = EventFilter() tf = filter.tag_filter.add() tf.tag_uuids.extend(guids) else: # no permission to see events, return 0 result = { 'total' : 0, 'events' : [], } if not result: result = self._getEventSummaries(source=partial(client_fn, filter=filter, exclusion_filter=exclusion_filter, sort=sort ), offset=offset, limit=limit ) return result def getEventSummariesGenerator(self, filter=None, exclude=None, sort=None, archive=False, timeout=None): if isinstance(exclude, dict): exclude = from_dict(EventFilter, exclude) if isinstance(filter, dict): filter = from_dict(EventFilter, filter) if sort is not None: sort = tuple(self._getEventSort(s) for s in safeTuple(sort)) searchid = self.client.createSavedSearch(event_filter=filter, exclusion_filter=exclude, sort=sort, archive=archive, timeout=timeout) log.debug("created saved search %s", searchid) eventSearchFn = partial(self.client.savedSearch, searchid, archive=archive) offset = 0 limit = 1000 try: while offset is not None: result = self._getEventSummaries(eventSearchFn, offset, limit) for evt in result['events']: yield evt offset = result['next_offset'] finally: try: log.debug("closing saved search %s", searchid) self.client.deleteSavedSearch(searchid, archive=archive) except Exception as e: log.debug("error closing saved search %s (%s) - %s", searchid, type(e), e) def getEventSummary(self, uuid): response, content = self.client.getEventSummary(uuid) return to_dict(content) def nextEventSummaryUpdate(self, next_request): status, response = self.client.nextEventSummaryUpdate(from_dict(EventSummaryUpdateRequest, next_request)) return status, to_dict(response) def _processArgs(self, eventFilter, exclusionFilter, userName): if eventFilter: eventFilter = from_dict(EventFilter, eventFilter) if exclusionFilter: exclusionFilter = from_dict(EventFilter, exclusionFilter) if not userName: userUuid, userName = self._findUserInfo() else: userUuid = self._getUserUuid(userName) if eventFilter is None and exclusionFilter is None: raise NoFiltersException("Cannot modify event summaries without at least one filter specified.") return {'eventFilter': eventFilter, 'exclusionFilter': exclusionFilter, 'userName': userName, 'userUuid': userUuid} def closeEventSummaries(self, eventFilter=None, exclusionFilter=None, limit=None, userName=None, timeout=None): arguments = self._processArgs(eventFilter, exclusionFilter, userName) eventFilter = arguments.get('eventFilter') exclusionFilter = arguments.get('exclusionFilter') userName = arguments.get('userName') userUuid = arguments.get('userUuid') status, response = self.client.closeEventSummaries( userUuid, userName, eventFilter, exclusionFilter, limit, timeout=timeout) return status, to_dict(response) def acknowledgeEventSummaries(self, eventFilter=None, exclusionFilter=None, limit=None, userName=None, timeout=None): arguments = self._processArgs(eventFilter, exclusionFilter, userName) eventFilter = arguments.get('eventFilter') exclusionFilter = arguments.get('exclusionFilter') userName = arguments.get('userName') userUuid = arguments.get('userUuid') status, response = self.client.acknowledgeEventSummaries(userUuid, userName, eventFilter, exclusionFilter, limit, timeout=timeout) return status, to_dict(response) def reopenEventSummaries(self, eventFilter=None, exclusionFilter=None, limit=None, userName=None, timeout=None): arguments = self._processArgs(eventFilter, exclusionFilter, userName) eventFilter = arguments.get('eventFilter') exclusionFilter = arguments.get('exclusionFilter') userName = arguments.get('userName') userUuid = arguments.get('userUuid') status, response = self.client.reopenEventSummaries( userUuid, userName, eventFilter, exclusionFilter, limit, timeout=timeout) return status, to_dict(response) def updateEventSummaries(self, update, eventFilter=None, exclusionFilter=None, limit=None, timeout=None): update_pb = from_dict(EventSummaryUpdate, update) event_filter_pb = None if (eventFilter is None) else from_dict(EventFilter, eventFilter) exclusion_filter_pb = None if (exclusionFilter is None) else from_dict(EventFilter, exclusionFilter) status, response = self.client.updateEventSummaries(update_pb, event_filter_pb, exclusion_filter_pb, limit=limit, timeout=timeout) return status, to_dict(response) def getConfig(self): # the config client doesn't return a ZepConfig. It merges the ZepConfig # with some other properties to create a config structure. config = self.configClient.getConfig() return config def setConfigValues(self, values): """ @type values: Dictionary @param values: Key Value pairs of config values """ zepConfigProtobuf = from_dict(ZepConfig, values) self.configClient.setConfigValues(zepConfigProtobuf) def setConfigValue(self, name, value): self.configClient.setConfigValue(name, value) def removeConfigValue(self, name): self.configClient.removeConfigValue(name) def _getTopLevelOrganizerUuids(self, tagUuid): """ Returns a list of child UUIDs if the specified tagUuid is a top-level organizer. Otherwise returns None. This is needed because several operations in ZEP are performed on UUIDs tagged in the events, however the top-level organizers are not tagged on events as an optimization. @type tagUuid: string @param tagUuid: UUID of potential top-level organizer """ obj = self._guidManager.getObject(tagUuid) uuids = None if obj and obj.getDmdKey() == '/': uuids = [IGlobalIdentifier(n).getGUID() for n in obj.children()] return uuids def getEventSeveritiesByUuid(self, tagUuid, severities=(), status=()): """ returns a dict of severities for the element tagUuid """ uuids = [ tagUuid ] return self.getEventSeveritiesByUuids(uuids , severities=severities, status=status)[tagUuid] def getEventSeveritiesByUuids(self, tagUuids, severities=(), status=()): """ returns a dict whose keys are each uuid in tagUuids and values the dict of severities per uuid """ uuids = [] requested_uuids = {} for uuid in tagUuids: children_uuids = self._getTopLevelOrganizerUuids(uuid) if children_uuids: requested_uuids[uuid] = children_uuids uuids.extend(children_uuids) else: requested_uuids[uuid] = [ uuid ] uuids.append(uuid) uuids = list(set(uuids)) severities = self.getEventSeverities(uuids, severities=severities, status=status) severities_to_return = {} for requested_uuid in requested_uuids.keys(): children_uuids = requested_uuids[requested_uuid] sevmap = {} for uuid in children_uuids: sevs = severities[uuid] for sev, counts in sevs.iteritems(): counts_dict = sevmap.get(sev) if counts_dict: # Condense counts of child organizers into a flattened out count counts_dict['count'] += counts['count'] counts_dict['acknowledged_count'] += counts['acknowledged_count'] else: sevmap[sev] = counts severities_to_return[requested_uuid] = sevmap return severities_to_return def _createSeveritiesDict(self, eventTagSeverities): severities = {} for tag in eventTagSeverities: severities[tag.tag_uuid] = {} for sev in tag.severities: severities[tag.tag_uuid][sev.severity] = dict(count=sev.count, acknowledged_count=sev.acknowledged_count) for sev in EventSeverity.numbers: if not sev in severities[tag.tag_uuid]: severities[tag.tag_uuid][sev] = dict(count=0, acknowledged_count=0) return severities def getEventSeverities(self, tagUuids, severities=(), status=(), eventClass=()): """ Get a dictionary of the event severity counts for each UUID. @param tagUuids: A sequence of element UUIDs @param severities: A sequence of severities to include. Default is CRITICAL/ERROR/WARNING. @type severities: Sequence of severities. @param status: A sequence of event statuses to include. Default is NEW/ACKNOWLEDGED. @type status: Sequence of event severities. @rtype: dict @return: A dictionary of UUID -> { C{EventSeverity} -> { count, acknowledged_count } } """ objects_severities = {} tagUuids = list(tagUuids) tagUuids.sort() number_of_uuids = len(tagUuids) batch_size = ZepFacade.SEVERITIES_BATCH_SIZE number_of_batches = number_of_uuids / batch_size if (number_of_uuids % batch_size) > 0: number_of_batches = number_of_batches + 1 if number_of_batches > 1: log.info("Retrieving severities for {0} uuids.".format(number_of_uuids)) for batch in range(0, number_of_batches): start = batch*batch_size end = (start + batch_size) if end > number_of_uuids: end = number_of_uuids uuids = tagUuids[start:end] eventTagSeverities = self._getEventTagSeverities(severity=severities, status=status, tags=uuids, eventClass=eventClass) objects_severities.update(self._createSeveritiesDict(eventTagSeverities)) return objects_severities def getWorstSeverityByUuid(self, tagUuid, default=SEVERITY_CLEAR, ignore=()): return self.getWorstSeverity([tagUuid], default=default, ignore=ignore)[tagUuid] def getWorstSeverity(self, tagUuids, default=SEVERITY_CLEAR, ignore=()): """ Get a dictionary of the worst event severity for each UUID. @param tagUuids: A sequence of element UUIDs @param default: The default severity to use if there are no results or if a severity is ignored @type default: An C{EventSeverity} enum value @param ignore: Severities to not include as worst, use the default instead. @type ignore: A list of C{EventSeverity} enum values @rtype: dict @return: A dictionary of UUID -> C{EventSeverity} """ if not tagUuids: return {} # Prepopulate the list with defaults severities = dict.fromkeys(tagUuids, default) eventTagSeverities = self._getEventTagSeverities(tags=tagUuids) for tag in eventTagSeverities: for sev in tag.severities: if sev.severity not in ignore: severities[tag.tag_uuid] = max(sev.severity, severities.get(tag.tag_uuid, 0)) return severities def getSeverityName(self, severity): return EventSeverity.getPrettyName(severity) def createEventMapping(self, evdata, eventClassId): """ Associates event(s) with an event class. """ evmap = None evclass = self._dmd.Events.getOrganizer(eventClassId) numCreated = 0 numNotUnknown = 0 numNoKey = 0 for data in evdata: evclasskey = data.get('eventClassKey') if data.get('eventClass'): curevclass = data.get('eventClass')['text'] else: curevclass = Unknown example = data.get('message') if curevclass != Unknown: numNotUnknown += 1 continue if not evclasskey: numNoKey += 1 continue evmap = evclass.createInstance(evclasskey) evmap.eventClassKey = evclasskey evmap.example = example evmap.index_object() numCreated += 1 # message msg = '' if numNotUnknown: msg += ((msg and ' ') + '%s event%s %s not of the class Unknown.' % ( numNotUnknown, (numNotUnknown != 1 and 's') or '', (numNotUnknown != 1 and 'are') or 'is')) if numNoKey: msg += ((msg and ' ') + '%s event%s %s not have an event class key.' % ( numNoKey, (numNoKey != 1 and 's') or '', (numNoKey != 1 and 'do') or 'does')) msg += (msg and ' ') + 'Created %s event mapping%s.' % ( numCreated, (numCreated != 1 and 's') or '') # redirect url = None if len(evdata) == 1 and evmap: url = evmap.getPrimaryId() elif evclass and evmap: url = evclass.getPrimaryId() return msg, url def _getEventTagSeverities(self, eventClass=(), severity=(), status=(), tags=(), deviceOnly=False): if not severity: severity = (SEVERITY_CRITICAL, SEVERITY_ERROR, SEVERITY_WARNING) if not status: status = (STATUS_NEW, STATUS_ACKNOWLEDGED) if deviceOnly: eventFilter = self.createEventFilter( severity=severity, status=status, event_class=eventClass, tags=tags, element_sub_identifier=[""], ) else: eventFilter = self.createEventFilter( severity=severity, status=status, event_class=eventClass, tags=tags, ) response, content = self.client.getEventTagSeverities(from_dict(EventFilter, eventFilter)) return content.severities def getDevicePingIssues(self): return self.getDeviceIssues(eventClass=[Status_Ping], severity=[SEVERITY_WARNING,SEVERITY_ERROR,SEVERITY_CRITICAL], status=[STATUS_NEW,STATUS_ACKNOWLEDGED,STATUS_SUPPRESSED]) def getDeviceStatusIssues(self): return self.getDeviceIssues(eventClass=["/Status/"], severity=[SEVERITY_ERROR,SEVERITY_CRITICAL], status=[STATUS_NEW,STATUS_ACKNOWLEDGED]) def getDeviceIssues(self, eventClass=(), severity=(SEVERITY_DEBUG, SEVERITY_INFO, SEVERITY_WARNING, SEVERITY_ERROR, SEVERITY_CRITICAL), status=(STATUS_NEW,)): tagSeverities = self._getEventTagSeverities( eventClass=eventClass, severity=severity, status=status, deviceOnly=True) issues = [] for eventTagSeverity in tagSeverities: device = self._guidManager.getObject(eventTagSeverity.tag_uuid) if device and isinstance(device, Device): count = 0 for severity in eventTagSeverity.severities: count += severity.count total = eventTagSeverity.total issues.append((device.id, count, total)) return issues def getDeviceIssuesDict(self, eventClass=(), severity=(), status=()): severities = self._getEventTagSeverities(eventClass, severity, status) return self._createSeveritiesDict(severities) def getDetails(self): """ Retrieve all of the indexed detail items. @rtype list of EventDetailItem dicts """ return getDetailsInfo().getDetails() def getUnmappedDetails(self): """ Return only non-zenoss details. This is used to get details that will not be mapped to another key. (zenoss.device.production_state maps back to prodState, so will be excluded here) """ return getDetailsInfo().getUnmappedDetails() def getDetailsMap(self): """ Return a mapping of detail keys to dicts of detail items """ return getDetailsInfo().getDetailsMap() def parseParameterDetails(self, parameters): """ Given grid parameters, split into keys that are details and keys that are other parameters. """ params = {} details = {} detail_keys = self.getDetailsMap().keys() for k, v in parameters.iteritems(): if k in self.ZENOSS_DETAIL_OLD_TO_NEW_MAPPING: k = self.ZENOSS_DETAIL_OLD_TO_NEW_MAPPING[k] if k in detail_keys: details[k] = v else: params[k] = v # verify parameters against known valid ones # If there's an extra, it either needs to be added or # is an invalid detail that can't be searched. leftovers = set(s.lower() for s in params) - set(self.DEFAULT_SORT_MAP) - set(('tags', 'deviceclass', 'systems', 'location', 'devicegroups', 'message', 'excludenonactionables' )) if leftovers: raise InvalidQueryParameterException("Invalid query parameters specified: %s" % ', '.join(leftovers)) return params, details def addIndexedDetails(self, detailItemSet): """ @type detailItemSet: zenoss.protocols.protobufs.zep_pb2.EventDetailItemSet """ _ZEP_DETAILS_INFO = [] return self.configClient.addIndexedDetails(detailItemSet) def updateIndexedDetail(self, item): """ @type item: zenoss.protocols.protobufs.zep_pb2.EventDetailItem """ _ZEP_DETAILS_INFO = [] return self.configClient.updateIndexedDetail(item) def removeIndexedDetail(self, key): """ @type key: string """ # Gather the new details information _ZEP_DETAILS_INFO = [] return self.configClient.removeIndexedDetail(key) def countEventsSince(self, since): """ Returns the total number of events in summary and archive that have been seen since the specified time (in seconds). @type since: int @param since: Time (in seconds) from the epoch. @rtype: int @return: The number of events in summary and archive that have been seen since the specified time. """ sinceInMillis = int(since * 1000) eventFilter = self.createEventFilter(last_seen=[sinceInMillis]) total = self.getEventSummaries(0, filter=eventFilter, limit=0)['total'] total += self.getEventSummariesFromArchive(0, filter=eventFilter, limit=0)['total'] return total def getHeartbeats(self, monitor=None): response, heartbeats = self.heartbeatClient.getHeartbeats(monitor=monitor) heartbeats_dict = to_dict(heartbeats) return heartbeats_dict.get('heartbeats', []) def deleteHeartbeats(self, monitor=None): self.heartbeatClient.deleteHeartbeats(monitor=monitor) def deleteHeartbeat(self, monitor, daemon): """ Removes the heartbeat record for the specified monitor and daemon. @param monitor: The heartbeat monitor (i.e. 'localhost'). @type monitor: basestring @param daemon: The heartbeat daemon (i.e. 'zenhub'). @type daemon: basestring """ self.heartbeatClient.deleteHeartbeat(monitor, daemon) def create(self, summary, severity, device, component=None, mandatory=True, **kwargs): """ Create an event. @param summary: Summary message of the event. This variable gets mapped to an C{Event} protobuf field of the same name. @type summary: string @param severity: Severity name of the event. This variable gets mapped to the C{Event} protobuf using an C{EventProtobufSeverityMapper} (C{Products.ZenMessaging.queuemessaging.adapters.EventProtobufSeverityMapper}). This value can be an integer-like string value 0-5 or the string of the severity (clear, debug, info, warning, error, critical). The casing of the string does not matter. An empty severity value will be mapped to CLEAR. @type severity: string @param device: Device string. This variable gets set as the element on the C{Event} protobuf using an C{EventProtobufDeviceMapper} (C{Products.ZenMessaging.queuemessaging.adapters.EventProtobufDeviceMapper}). The value for this variable will always be set as a DEVICE element type. This value is later interpreted by zeneventd during the C{IdentifierPipe} (C{Products.ZenEvents.events2.processing.IdentifierPipe}) segment of the event processing pipeline. If an ipAddress is also provided in kwargs, the ipAddress is also used to help identify the device. If the ipAddress is provided, it is used first. If the ipAddress is not provided, the IP for a device is attempted to be discerned from the value of this variable. If the IP cannot be inferred, identification falls back to the value of this variable as either the ID of the device, or the title of the device as stored in the device catalog (as the NAME field). @type device: string @param component: ID of the component. This variable is used to lookup components by their ID or the title of the component (also stored as the NAME field in the catalog). See more info on how these objects are cataloged here: C{Products.Zuul.catalog.global_catalog.IndexableWrapper}. @type component: string @param mandatory: If True, message will be returned unless it can be routed to a queue. @type mandatory: boolean @param eventClass: Name of the event class to fall under. @type eventClass: string For other parameters see class Event. """ occurrence_uuid = str(uuid4()) rcvtime = time() args = dict(evid=occurrence_uuid, summary=summary, severity=severity, device=device) if component: args['component'] = component args.update(kwargs) event = ZenEvent(rcvtime=rcvtime, **args) publisher = getUtility(IEventPublisher) publisher.publish(event, mandatory=mandatory) def updateDetails(self, evid, **detailInfo): """ Given an evid, update the detail key/value pairs in ZEP. """ if len(detailInfo) == 1 and isinstance(detailInfo.values()[0], EventDetailSet): return self.client.updateDetails(evid, detailInfo.values()[0]) detailSet = EventDetailSet() for key, value in detailInfo.items(): detailSet.details.add(name=key, value=(value,)) return self.client.updateDetails(evid, detailSet) def getStats(self): response, stats = self.statsClient.get() statsList = [] for stat in stats.stats: myst = {} myst['name'] = stat.name myst['description'] = stat.description myst['value'] = stat.value statsList.append(myst) return statsList