Package Products :: Package ZenEvents :: Module EventManagerBase |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenEvents.EventManagerBase

       1  ###########################################################################
       2  #
       3  # This program is part of Zenoss Core, an open source monitoring platform.
       4  # Copyright (C) 2007, Zenoss Inc.
       5  #
       6  # This program is free software; you can redistribute it and/or modify it
       7  # under the terms of the GNU General Public License version 2 as published by
       8  # the Free Software Foundation.
       9  #
      10  # For complete information please visit: http://www.zenoss.com/oss/
      11  #
      12  ###########################################################################
      13
      14  __doc__ = """EventManagerBase
      15  Data connector to backend of the event management system.
      16  """
      17
      18  import time
      19  import types
      20  import random
      21  import re
      22  random.seed()
      23  import logging
      24  log = logging.getLogger("zen.Events")
      25
      26  from AccessControl import ClassSecurityInfo
      27  from AccessControl import getSecurityManager
      28  from Globals import DTMLFile
      29  from Acquisition import aq_base
      30  import DateTime
      31  from Products.ZenModel.ZenossSecurity import *
      32
      33  from Products.ZenUtils.ObjectCache import ObjectCache
      34  from Products.ZenUtils.jsonutils import unjson
      35
      36  from ZEvent import ZEvent
      37  from EventDetail import EventDetail
      38  from BetterEventDetail import BetterEventDetail
      39  from EventCommand import EventCommand
      40  from Products.ZenEvents.Exceptions import *
      41  from Products.AdvancedQuery import MatchRegexp, In, And
      42
      43  from Products.ZenModel.ZenModelRM import ZenModelRM
      44  from Products.ZenModel.ZenossSecurity import *
      45  from Products.ZenRelations.RelSchema import *
      46  from Products.ZenUtils import Time
      47  from Products.ZenUtils.FakeRequest import FakeRequest
      48  from Products.ZenEvents.ZenEventClasses import Status_Ping, Status_Wmi_Conn
      49  from Products.ZenWidgets import messaging
      50  from Products.ZenUI3.browser.eventconsole.columns import COLUMN_CONFIG
      51
      52  from ZenEventClasses import Unknown
      53
      54  from DbAccessBase import DbAccessBase
      55
      56  from Products.ZenUtils.Utils import unused
      57
      58  __pychecker__="maxargs=16"
      59
      60 -def evtprep(evts):
      61      """
      62      Prepares data from L{Products.ZenEvents.EventManagerBase.getEventSummary}
      63      for rendering in the eventrainbow template macro.
      64
      65      Each cell of the old-style event rainbow needs a CSS class specified in
      66      order to render its color, fill and border style.  evtprep determines the
      67      proper class and returns it, along with a string representation of the
      68      number of live and acknowledged events.
      69
      70          >>> from Products.ZenEvents.EventManagerBase import evtprep
      71          >>> evtprep(['zenevents_5_noack noack', 2, 2])
      72          {'cssclass': 'zenevents_5_noack noack empty thin', 'data': '2/2'}
      73          >>> evtprep(['zenevents_5_noack noack', 1, 2])
      74          {'cssclass': 'zenevents_5_noack noack', 'data': '1/2'}
      75
      76      @param evts: A tuple of the form (Severity string, Number Acknowledged int,
      77          Number Live int)
      78      @type evts: tuple
      79      @return: A dictionary of the form {'cssclass': Class string, 'data': Event
      80          count representation string}
      81
      82      """
      83      evtsdata = "%d/%d" % (evts[1],evts[2])
      84      if evts[1]==evts[2] or evts[2]==0:
      85          return {'cssclass':evts[0] + " empty thin",
      86                  'data':evtsdata}
      87      else:
      88          return {'cssclass':evts[0], 'data':evtsdata}
      89
      90
      91 -class EventManagerBase(ZenModelRM, ObjectCache, DbAccessBase):
      92      """
      93      Data connector to backend of the event management system.
      94      """
      95      #implements(IEventList, IEventStatus, ISendEvents)
      96
      97      #FQDNID = hash(socket.getfqdn())
      98
      99      eventStateConversions = (
     100                  ('New',         0),
     101                  ('Acknowledged',1),
     102                  ('Suppressed',  2),
     103                  #('Bogus',       3),
     104                  )
     105
     106      eventActions = ('status', 'history', 'drop')
     107
     108      severityConversions = (
     109          ('Critical', 5),
     110          ('Error', 4),
     111          ('Warning', 3),
     112          ('Info', 2),
     113          ('Debug', 1),
     114          ('Clear', 0),
     115      )
     116      severities = dict([(b, a) for a, b in severityConversions])
     117
     118      priorityConversions = (
     119          ('None', -1),
     120          ('Emergency', 0),
     121          ('Alert', 1),
     122          ('Critical', 2),
     123          ('Error', 3),
     124          ('Warning', 4),
     125          ('Notice', 6),
     126          ('Info', 8),
     127          ('Debug', 10),
     128      )
     129      priorities = dict([(b, a) for a, b in priorityConversions])
     130
     131      statusTable = "status"
     132      detailTable = "detail"
     133      logTable = "log"
     134      lastTimeField = "lastTime"
     135      firstTimeField = "firstTime"
     136      deviceField = "device"
     137      componentField = "component"
     138      eventClassField = "eventClass"
     139      severityField = "severity"
     140      stateField = "eventState"
     141      countField = "count"
     142      prodStateField = "prodState"
     143      DeviceGroupField = "DeviceGroups"
     144      SystemField = "Systems"
     145
     146      DeviceWhere = "\"device = '%s'\" % me.getDmdKey()"
     147      DeviceResultFields = ("eventState", "severity", "component", "eventClass",
     148                            "summary", "firstTime", "lastTime", "count" )
     149      ComponentWhere = ("\"(device = '%s' and component = '%s')\""
     150                        " % (me.device().getDmdKey(), me.name())")
     151      ComponentResultFields = ("eventState", "severity", "eventClass", "summary",
     152                               "firstTime", "lastTime", "count" )
     153      IpAddressWhere = "\"ipAddress='%s'\" % (me.getId())"
     154      EventClassWhere = "\"eventClass like '%s%%'\" % me.getDmdKey()"
     155      EventClassInstWhere = """\"eventClass = '%s' and eventClassKey = '%s'\" % (\
     156                                  me.getEventClass(), me.eventClassKey)"""
     157      DeviceClassWhere = "\"(DeviceClass = '%s' or DeviceClass like '%s/%%') \" % \
     158                           ( me.getDmdKey(), me.getDmdKey() )"
     159
     160      LocationWhere = "\"Location like '%s%%'\" % me.getDmdKey()"
     161      SystemWhere = "\"Systems like '%%|%s%%'\" % me.getDmdKey()"
     162      DeviceGroupWhere = "\"DeviceGroups like '%%|%s%%'\" % me.getDmdKey()"
     163
     164      defaultResultFields = ("eventState", "severity", "device", "component",
     165                             "eventClass", "summary", "firstTime", "lastTime",
     166                             "count" )
     167
     168      defaultFields = ('eventState', 'severity', 'evid')
     169
     170      defaultEventId = ('device', 'component', 'eventClass',
     171                           'eventKey', 'severity')
     172
     173      requiredEventFields = ('device', 'summary', 'severity')
     174
     175      refreshConversionsForm = DTMLFile('dtml/refreshNcoProduct', globals())
     176
     177      defaultAvailabilityDays = 7
     178      defaultPriority = 3
     179      eventAgingHours = 4
     180      eventAgingSeverity = 4
     181      historyMaxAgeDays = 0
     182
     183      _properties = (
     184          {'id':'backend', 'type':'string','mode':'r', },
     185          {'id':'username', 'type':'string', 'mode':'w'},
     186          {'id':'password', 'type':'string', 'mode':'w'},
     187          {'id':'host', 'type':'string', 'mode':'w'},
     188          {'id':'database', 'type':'string', 'mode':'w'},
     189          {'id':'port', 'type':'int', 'mode':'w'},
     190          {'id':'defaultWhere', 'type':'text', 'mode':'w'},
     191          {'id':'defaultOrderby', 'type':'text', 'mode':'w'},
     192          {'id':'defaultResultFields', 'type':'lines', 'mode':'w'},
     193          {'id':'statusTable', 'type':'string', 'mode':'w'},
     194          {'id':'detailTable', 'type':'string', 'mode':'w'},
     195          {'id':'logTable', 'type':'string', 'mode':'w'},
     196          {'id':'lastTimeField', 'type':'string', 'mode':'w'},
     197          {'id':'firstTimeField', 'type':'string', 'mode':'w'},
     198          {'id':'deviceField', 'type':'string', 'mode':'w'},
     199          {'id':'componentField', 'type':'string', 'mode':'w'},
     200          {'id':'severityField', 'type':'string', 'mode':'w'},
     201          {'id':'countField', 'type':'string', 'mode':'w'},
     202          {'id':'DeviceGroupField', 'type':'string', 'mode':'w'},
     203          {'id':'SystemField', 'type':'string', 'mode':'w'},
     204          {'id':'DeviceWhere', 'type':'string', 'mode':'w'},
     205          {'id':'DeviceResultFields', 'type':'lines', 'mode':'w'},
     206          {'id':'ComponentResultFields', 'type':'lines', 'mode':'w'},
     207          {'id':'EventClassWhere', 'type':'string', 'mode':'w'},
     208          {'id':'EventClassInstWhere', 'type':'string', 'mode':'w'},
     209          {'id':'DeviceClassWhere', 'type':'string', 'mode':'w'},
     210          {'id':'LocationWhere', 'type':'string', 'mode':'w'},
     211          {'id':'SystemWhere', 'type':'string', 'mode':'w'},
     212          {'id':'DeviceGroupWhere', 'type':'string', 'mode':'w'},
     213          {'id':'requiredEventFields', 'type':'lines', 'mode':'w'},
     214          {'id':'defaultEventId', 'type':'lines', 'mode':'w'},
     215          {'id':'defaultFields', 'type':'lines', 'mode':'w'},
     216          {'id':'timeout', 'type':'int', 'mode':'w'},
     217          {'id':'clearthresh', 'type':'int', 'mode':'w'},
     218          {'id':'defaultAvailabilityDays', 'type':'int', 'mode':'w'},
     219          {'id':'defaultPriority', 'type':'int', 'mode':'w'},
     220          {'id':'eventAgingHours', 'type':'int', 'mode':'w'},
     221          {'id':'eventAgingSeverity', 'type':'int', 'mode':'w'},
     222          {'id':'historyMaxAgeDays', 'type':'int', 'mode':'w'},
     223          )
     224
     225      _relations =  (
     226          ("commands", ToManyCont(ToOne, "Products.ZenEvents.EventCommand", "eventManager")),
     227      )
     228
     229      factory_type_information = (
     230          {
     231              'immediate_view' : 'editEventManager',
     232              'actions'        :
     233              (
     234                  { 'id'            : 'edit'
     235                  , 'name'          : 'Edit'
     236                  , 'action'        : 'editEventManager'
     237                  , 'permissions'   : ( "Manage DMD", )
     238                  },
     239                  { 'id'            : 'edit'
     240                  , 'name'          : 'Fields'
     241                  , 'action'        : 'editEventManagerFields'
     242                  , 'permissions'   : ( "Manage DMD", )
     243                  },
     244                  { 'id'            : 'history_edit'
     245                  , 'name'          : 'History Fields'
     246                  , 'action'        : 'editEventManagerHistoryFields'
     247                  , 'permissions'   : ( "Manage DMD", )
     248                  },
     249                  { 'id'            : 'commands'
     250                  , 'name'          : 'Commands'
     251                  , 'action'        : 'listEventCommands'
     252                  , 'permissions'   : ( "Manage DMD", )
     253                  },
     254                  { 'id'            : 'changes'
     255                  , 'name'          : 'Modifications'
     256                  , 'action'        : 'viewNewHistory'
     257                  , 'permissions'   : (ZEN_VIEW_MODIFICATIONS,)
     258                  },
     259              )
     260            },
     261          )
     262
     263      security = ClassSecurityInfo()
     264
     265
     266 -    def __init__(self, id, title='', hostname='localhost', username='root',
     267                   password='', database='events', port=3306,
     268                   defaultWhere='',defaultOrderby='',defaultResultFields=[]):
     269          """
     270          Sets up event database access and initializes the cache.
     271
     272          @param id: A unique id
     273          @type id: string
     274          @param title: A title
     275          @type title: string
     276          @param hostname: The hostname of the events database server
     277          @type hostname: string
     278          @param username: The name of a user with permissions to access the
     279              events database
     280          @type username: string
     281          @param password: The password of the user
     282          @type password: string
     283          @param database: The name of the events database
     284          @type database: string
     285          @param port: The port on which the database server is listening
     286          @type port: int
     287          @param defaultWhere: The default where clause to use when building
     288              queries
     289          @type defaultWhere: string
     290          @param defaultOrderby: The default order by clause to use when building
     291              queries
     292          @type defaultOrderby: string
     293          @param defaultResultFields: DEPRECATED. Currently unused.
     294          @type defaultResultFields: list
     295
     296          """
     297          unused(defaultOrderby, defaultResultFields)
     298          self.id = id
     299          self.title = title
     300          self.username=username
     301          self.password=password
     302          self.database=database
     303          self.host=hostname
     304          self.port=port
     305          DbAccessBase.__init__(self)
     306
     307          self.defaultWhere = defaultWhere
     308          self.defaultOrderby="%s desc, %s desc" % (
     309                              self.severityField, self.lastTimeField)
     310
     311          self._schema = {}
     312          self._fieldlist = []
     313          self._colors = ()
     314          self._ackedcolors = ()
     315          ObjectCache.__init__(self)
     316          self.initCache()
     317
     318      #==========================================================================
     319      # Event query functions from IEventQuery
     320      #==========================================================================
     321
     322
     323 -    def getEventResultFields(self, context):
     324          """
     325          A wrapper for L{lookupManagedEntityResultFields} accepting an object
     326          with an C{event_key} attribute.
     327
     328          >>> class dummy(object):
     329          ...     event_key = 'Device'
     330          ...
     331          >>> d = dummy()
     332          >>> f = dmd.ZenEventManager.getEventResultFields(d)
     333          >>> f==dmd.ZenEventManager.DeviceResultFields
     334          True
     335          >>> d.event_key = 'Robot'
     336          >>> f = dmd.ZenEventManager.getEventResultFields(d)
     337          >>> f==dmd.ZenEventManager.defaultResultFields
     338          True
     339
     340          @param context: An object with an C{event_key} attribute.
     341          @type context: L{ManagedEntity}
     342          @return: A sequence of strings representing columns in the database.
     343          @rtype: tuple
     344          """
     345          return self.lookupManagedEntityResultFields(getattr(context,
     346                                                      'event_key', 'Default'))
     347
     348 -    def getEventListME(self, me, **kwargs):
     349          """
     350          Queries the database for events on a managed entity.
     351
     352          @param me: The object for which to fetch events
     353          @type me: L{ManagedEntity}
     354          @return: L{ZEvent} objects
     355          @rtype: list
     356          """
     357          where = ""
     358          if hasattr(me, 'getWhere'):
     359              where = me.getWhere()
     360          else:
     361              where = self.lookupManagedEntityWhere(me)
     362          try:
     363              resultFields = kwargs['resultFields']; del kwargs['resultFields']
     364          except KeyError:
     365              resultFields = self.lookupManagedEntityResultFields(me.event_key)
     366          return self.getEventList(resultFields=resultFields, where=where,
     367                                   **kwargs)
     368
     369
     370 -    def filteredWhere(self, where, filters, values):
     371          """
     372          Create SQL representing conditions that match passed filters and append
     373          it to a given where clause.
     374
     375          Expressions are built using various criteria, including the type of
     376          filter widget representing the column and factors specific to the
     377          column itself.
     378
     379          All C{textfield} columns except C{count} will be matched as regular
     380          expressions.
     381
     382          C{count} may be passed as a comparison expression such as ">=2", "=8",
     383          "<10", etc., or an integer, in which case it will be evaluated as
     384          ">=n".
     385
     386          C{firstTime} and C{lastTime} are turned into seconds since the epoch,
     387          then evaluated as '>=n' and '<=n', respectively.
     388
     389          C{multiselectmenu} columns (prodState, severity, eventState, priority)
     390          arrive as a list of values to match, and become 'and (field=v1 or
     391          field=v2...)' where field is the column and vn is the value.
     392
     393          @param where: The where clause to which to append further conditions
     394          @type where: str
     395          @param filters: Values for which to create filters (e.g.,
     396                          {'device':'^loc.*$', 'severity':[4, 5]})
     397          @type filters: dict or JSON str representing dict
     398          @param values: Clause will be parameterized and the values list will be
     399                  populated with the values for the query
     400          @type values: list
     401          """
     402          queryValues = []
     403          newwhere = ''
     404          if filters is None: filters = {}
     405          elif isinstance(filters, basestring):
     406              filters = unjson(filters)
     407          for k,v in filters.items():
     408              ftype = COLUMN_CONFIG[k].get('filter', 'textfield')
     409              if isinstance(ftype, dict):
     410                  ftype = ftype['xtype']
     411              if k=='device':
     412                  # get all list of devices where title match the search term
     413                  deviceids = self._getDeviceIdsMatching(v)
     414                  if deviceids:
     415                      newwhere += " and (device REGEXP %%s OR device IN ('%s')) " % "','".join(deviceids)
     416                  else:
     417                      newwhere += " and (%s REGEXP %%s) " % (k,)
     418                  queryValues.append(v)
     419              elif k=='component':
     420                  componentWhere = ""
     421                  componentids = self._getComponentIdsMatching(v)
     422                  if componentids:
     423                      componentWhere = " OR component IN ('%s') " % "','".join(componentids)
     424                  # because components don't have to exist in the ZODB always search the
     425                  # database for them
     426                  newwhere += ' and ((%s REGEXP %%s) %s) ' % (k,componentWhere)
     427                  queryValues.append(v)
     428              elif k=='count':
     429                  m = re.match(r'^(?P<condition>\>=|\<=|\>|\<|=)?\s*(?P<value>[0-9]+)$', v.strip())
     430                  if m:
     431                      cond = m.group('condition') if m.group('condition') else '='
     432                      queryValues.append(m.group('value'))
     433
     434                      newwhere += ' and count %s %%s' % cond
     435                  else:
     436                      raise ValueError('%s is not a valid count' % v)
     437
     438              elif ftype=='textfield':
     439                  newwhere += ' and (%s REGEXP %%s) ' % (k,)
     440                  queryValues.append(v)
     441              elif k=='firstTime':
     442                  v2 = Time.isoToTimestamp(v)
     443                  newwhere += ' and %s >= %%s ' % (k,)
     444                  queryValues.append(v2)
     445              elif k=='lastTime':
     446                  v2 = Time.isoToTimestamp(v)
     447                  newwhere += ' and %s >= %%s ' % (k, )
     448                  queryValues.append(v2)
     449              elif ftype=='multiselectmenu':
     450                  if isinstance(v, basestring): v = (v,)
     451                  if len(v)>0:
     452                      sevstr = ' or '.join(['%s=%%s' % (k,) for s in v])
     453                      queryValues.extend(v)
     454                      newwhere += ' and (%s) ' % sevstr
     455          values.extend(queryValues)
     456          return where + newwhere
     457
     458
     459 -    def _filterCatalogResultsForIds(self, catalog, querySet):
     460          """
     461          Used by both the id matching sub queries
     462          this gets brain results and returns a list of
     463          ids
     464          @param catalog: catalog we are searching
     465          @param querySet: Advanced Query Search Terms
     466          @return [string]: all the ids of the search results that match
     467                            the queryset
     468          """
     469          try:
     470              brains = catalog.evalAdvancedQuery(querySet)
     471          except:
     472              # they had an error in their regex, just return nothing they may still be working on it
     473              return None
     474          # return list of device ids for mysql to filter by
     475          ids = []
     476          for brain in brains:
     477              ids.append(brain.id)
     478          return ids
     479
     480 -    def _getComponentIdsMatching(self, searchTerm):
     481          """
     482          This returns a list of component ids where the titleOrId
     483          matches the searchTerm
     484          @param searchTerm: query for which we want to search for (can be regex)
     485          """
     486          catalog = self.dmd.global_catalog
     487          querySet = [MatchRegexp('name', '.*%s.*' % searchTerm),
     488                      In('objectImplements',
     489                         'Products.ZenModel.DeviceComponent.DeviceComponent')]
     490          return self._filterCatalogResultsForIds(catalog, And(*querySet))
     491
     492 -    def _getDeviceIdsMatching(self, searchTerm, globSearch=True):
     493          """
     494          This returns a list of device ids where the titleOrId
     495          matches the searchTerm
     496          @param searchTerm: query for which we want to search for (can be regex)
     497          """
     498          catalog = self.dmd.Devices.deviceSearch
     499          if globSearch:
     500              searchTerm = '.*%s.*' % searchTerm
     501          querySet = MatchRegexp('titleOrId', searchTerm)
     502          return self._filterCatalogResultsForIds(catalog, querySet)
     503
     504 -    def getEventBatchME(self, me, selectstatus=None, resultFields=[],
     505                          where="", orderby="", severity=None, state=2,
     506                          startdate=None, enddate=None, offset=0, rows=0,
     507                          getTotalCount=False, filter="", goodevids=[],
     508                          badevids=[], **kwargs):
     509          """
     510          Returns a batch of events based on criteria from checked rows on the
     511          event console.
     512
     513          The event console can show thousands of events, and we want to support a
     514          "Select All" feature; enter this method. It builds a query based on the
     515          select status from the console ("All", "None", "Acknowledged",
     516          "Unacknowledged") and any checkboxes that have been modified manually.
     517
     518          @param me: The managed entity for which to query events.
     519          @type me: L{ManagedEntity}
     520          @param resultFields: The columns to return from the database.
     521          @type resultFields: list
     522          @param where: The base where clause to modify.
     523          @type where: string
     524          @param orderby: The "ORDER BY" string governing sort order.
     525          @type orderby: string
     526          @param severity: The minimum severity for which to query.
     527          @type severity: int
     528          @param state: The minimum state for which to query.
     529          @type state: int
     530          @param startdate: The early date limit
     531          @type startdate: string, DateTime
     532          @param enddate: The late date limit
     533          @type enddate: string, DateTime
     534          @param offset: The row at which to begin returning
     535          @type offset: int
     536          @param rows: DEPRECATED The number of rows to return (ignored).
     537          @type rows: int
     538          @param getTotalCount: Whether or not to return a count of the total
     539              number of rows
     540          @type getTotalCount: bool
     541          @param filter: A glob by which to filter events
     542          @type filter: string
     543          @param goodevids: Ids of events that specifically should be included
     544          @type goodevids: list
     545          @param badevids: Ids of events that specifically should not be included
     546          @type badevids: list
     547          @return: Ids of matching events
     548          @rtype: list
     549          @todo: Remove unused parameters from the method definition
     550          """
     551          unused(getTotalCount, rows)
     552          newwhere = self.lookupManagedEntityWhere(me)
     553          if where: newwhere = self._wand(newwhere, '%s%s', where, '')
     554          where = newwhere
     555          badevidsstr, goodevidsstr = '',''
     556          if not isinstance(goodevids, (list, tuple)): goodevids = [goodevids]
     557          if not isinstance(badevids, (list, tuple)): badevids = [badevids]
     558          if badevids: badevidsstr = " and evid not in ('%s')" %(
     559                                              "','".join(badevids))
     560          if goodevids: goodevidsstr = " and evid in ('%s')" %(
     561                                              "','".join(goodevids))
     562          if selectstatus=='all':
     563              where += badevidsstr
     564          elif selectstatus=='none':
     565              where += goodevidsstr or ' and 0'
     566          elif selectstatus=='acked':
     567              oper = bool(goodevidsstr) and ' or' or ' and'
     568              where += goodevidsstr + oper + " (eventstate=1 %s) " % badevidsstr
     569          elif selectstatus=='unacked':
     570              oper = bool(goodevidsstr) and ' or' or 'and'
     571              where += goodevidsstr + oper + " (eventstate=0 %s) " % badevidsstr
     572          try:
     573              resultFields = kwargs['resultFields']; del kwargs['resultFields']
     574          except KeyError:
     575              resultFields = self.lookupManagedEntityResultFields(me.event_key)
     576          events = self.getEventList(
     577                                      filter=filter,
     578                                      offset=offset,
     579                                      getTotalCount=False,
     580                                      startdate=startdate,
     581                                      enddate=enddate, severity=severity,
     582                                      state=state, orderby=orderby,
     583                                      resultFields=resultFields,
     584                                      where=where,**kwargs)
     585          return [ev.evid for ev in events]
     586
     587 -    def getEventIds(self, me, selectstatus=None,
     588                          orderby="", filters=None, evids=[],
     589                          excludeIds=[], asof=None):
     590          """
     591          Returns a batch of events based on criteria from checked rows on the
     592          event console.
     593
     594          The event console can show thousands of events, and we want to support a
     595          "Select All" feature; enter this method. It builds a query based on the
     596          select status from the console ("All", "New", "Acknowledged",
     597          "Suppressed") and any checkboxes that have been modified manually.
     598
     599          @param me: The managed entity for which to query events.
     600          @type me: L{ManagedEntity}
     601          @param orderby: The "ORDER BY" string governing sort order.
     602          @type orderby: string
     603          @param filters: Values for which to create filters (e.g.,
     604                          {'device':'^loc.*$', 'severity':[4, 5]})
     605          @type filters: dict or JSON str representing dict
     606          @param evids: Ids of events that specifically should be included
     607          @type evids: list
     608          @param excludeIds: Ids of events that specifically should not be included
     609          @type excludeIds: list
     610          @return: Ids of matching events
     611          @rtype: set
     612          """
     613          where = self.lookupManagedEntityWhere(me)
     614          eventids = set()
     615          if evids:
     616              eventids.update(evids)
     617          if selectstatus:
     618              if selectstatus != 'All':
     619                  eventStates= dict(self.eventStateConversions)
     620                  assert selectstatus in (eventStates.keys())
     621                  where = self._wand(where, '%s = %s', self.stateField,
     622                             eventStates[selectstatus])
     623              if asof:
     624                  if where: where += ' and '
     625                  where += (" not (stateChange>FROM_UNIXTIME(%s) "
     626                            "and eventState=0)" % self.dateDB(asof))
     627              events = self.getEventList( resultFields=['evid'],
     628                                          filters=filters,
     629                                          getTotalCount=False,
     630                                          orderby=orderby,
     631                                          where=where)
     632              for ev in events:
     633                  eventids.add(ev.evid)
     634
     635          if eventids and excludeIds:
     636              eventids.difference_update(excludeIds)
     637          return eventids
     638
     639 -    def restrictedUserFilter(self, where):
     640          """This is a hook do not delete me!"""
     641          return where
     642
     643 -    def getEventList(self, resultFields=None, where="", orderby="",
     644              severity=None, state=2, startdate=None, enddate=None, offset=0,
     645              rows=0, getTotalCount=False, filter="", filters=None,
     646              parameterizedWhere=None, **kwargs):
     647          """
     648          Fetch a list of events from the database matching certain criteria.
     649
     650          @param resultFields: The columns to return from the database.
     651          @type resultFields: list
     652          @param where: The base where clause to modify.
     653          @type where: string
     654          @param orderby: The "ORDER BY" string governing sort order.
     655          @type orderby: string
     656          @param severity: The minimum severity for which to query.
     657          @type severity: int
     658          @param state: The minimum state for which to query.
     659          @type state: int
     660          @param startdate: The early date limit
     661          @type startdate: string, DateTime
     662          @param enddate: The late date limit
     663          @type enddate: string, DateTime
     664          @param offset: The row at which to begin returning
     665          @type offset: int
     666          @param rows: The number of rows to return.
     667          @type rows: int
     668          @param getTotalCount: Whether or not to return a count of the total
     669              number of rows
     670          @type getTotalCount: bool
     671          @param filter: A glob by which to filter events
     672          @type filter: string
     673          @return: Matching events as L{ZEvent}s.
     674          @rtype: list
     675          @todo: Remove unused parameters from the method definition
     676          """
     677          unused(kwargs)
     678          paramValues = []
     679          try:
     680              where = self.restrictedUserFilter(where)
     681              if not resultFields:
     682                  resultFields = self.defaultResultFields
     683              resultFields = list(resultFields)
     684              resultFields.extend(self.defaultFields)
     685
     686              #validate all fields
     687              fieldList = [x.lower() for x in self.getFieldList()]
     688              for field in resultFields:
     689                  if field.lower() not in fieldList:
     690                      raise ('requested column %s is not valid' % field)
     691
     692              calcfoundrows = ''
     693              if getTotalCount:
     694                  calcfoundrows = 'SQL_CALC_FOUND_ROWS'
     695              select = ["select ", calcfoundrows, ','.join(resultFields),
     696                          "from %s where" % self.statusTable ]
     697              if not where:
     698                  where = self.defaultWhere
     699
     700              #escape any % in the where clause because of format eval later
     701              where = where.replace('%', '%%')
     702
     703              if parameterizedWhere is not None:
     704                  pwhere, pvals = parameterizedWhere
     705                  if where: where += " and "
     706                  where += pwhere
     707                  paramValues.extend(pvals)
     708
     709              def paramWhereAnd(where, fmt, field, value):
     710                  if value != None and where.find(field) == -1:
     711                      if where: where += " and "
     712                      where += fmt % (field,)
     713                      paramValues.append(value)
     714                  return where
     715
     716              where = paramWhereAnd(where, "%s >= %%s", self.severityField, severity)
     717              where = paramWhereAnd(where, "%s <= %%s", self.stateField, state)
     718
     719              log.debug("filter is %s" % filter )
     720              if filter:
     721                  where += ' and (%s) ' % (' or '.join(['%s LIKE "%%%s%%"' % (
     722                              x, filter) for x in resultFields]))
     723              if startdate:
     724                  startdate, enddate = self._setupDateRange(startdate, enddate)
     725                  where = paramWhereAnd(where,"%s >= %%s",self.lastTimeField, startdate )
     726                  where = paramWhereAnd(where,"%s <= %%s",self.firstTimeField, enddate )
     727
     728              if filters is not None:
     729                  where = self.filteredWhere(where, filters, paramValues)
     730              select.append(where)
     731              if not orderby:
     732                  orderby = self.defaultOrderby
     733              if orderby:
     734                  #validate orderby is a valid field
     735                  orderby = self._scrubOrderby(orderby)
     736                  select.append("order by")
     737                  select.append(orderby)
     738
     739              if rows:
     740                  #validate offset and rows are ints
     741                  int(offset)
     742                  int(rows)
     743                  select.append("limit %s, %s" % (offset, rows))
     744              select.append(';')
     745              select = " ".join(select)
     746              if getTotalCount:
     747                  try: retdata, totalCount = self.checkCache(select)
     748                  except TypeError:
     749                      retdata, totalCount = self.checkCache(select), 100
     750              else: retdata = self.checkCache(select)
     751              if not False:
     752                  conn = self.connect()
     753                  try:
     754                      curs = conn.cursor()
     755                      log.debug(select % tuple(paramValues))
     756                      curs.execute(select, paramValues)
     757                      retdata = []
     758                      # iterate through the data results and convert to python
     759                      # objects
     760                      if self.checkRemotePerm(ZEN_VIEW, self.dmd.Events):
     761                          eventPermission = True
     762                      else:
     763                          eventPermission = False
     764                      for row in curs.fetchall():
     765                          row = map(self.convert, resultFields, row)
     766                          evt = ZEvent(self, resultFields, row, eventPermission)
     767                          retdata.append(evt)
     768                      if getTotalCount:
     769                          curs.execute("SELECT FOUND_ROWS()")
     770                          totalCount = curs.fetchone()[0]
     771                  finally: self.close(conn)
     772                  if getTotalCount: self.addToCache(select, (retdata, totalCount))
     773                  else: self.addToCache(select, retdata)
     774                  self.cleanCache()
     775              if getTotalCount:
     776                  return retdata, totalCount
     777              else: return retdata
     778          except:
     779              log.exception("Failure querying events")
     780              raise
     781
     782
     783 -    def getEventSummaryME(self, me, severity=1, state=1, prodState=None):
     784          """
     785          Return the CSS class, number of acknowledged events, and number of
     786          unacknowledged events, per severity, for a C{ManagedEntity}.
     787
     788          @param me: The object of the inquiry.
     789          @type me: L{ManagedEntity}
     790          @param severity: The minimum severity for which to retrieve events
     791          @type severity: int
     792          @param state: The minimum state for which to retrieve events
     793          @type state: int
     794          @param prodState: The minimum production state for which to retrieve
     795              events
     796          @type prodState: int
     797          @return: List of lists of the form [class, acked count, unacked count].
     798          @rtype: list
     799          """
     800          try:
     801              where = self.lookupManagedEntityWhere(me)
     802              return self.getEventSummary(where, severity, state, prodState)
     803          except:
     804              log.exception("event summary for %s failed" % me.getDmdKey())
     805              raise
     806
     807
     808 -    def getEventSummary(self, where="", severity=1, state=1, prodState=None):
     809          """
     810          Return a list of tuples with number of events and the color of the
     811          severity that the number represents.
     812
     813          This method should not be called directly, but overridden by subclasses.
     814
     815          @param where: The base where clause to modify.
     816          @type where: string
     817          @param severity: The minimum severity for which to retrieve events
     818          @type severity: int
     819          @param state: The minimum state for which to retrieve events
     820          @type state: int
     821          @param prodState: The minimum production state for which to retrieve
     822              events
     823          @type prodState: int
     824          @return: List of lists of the form [class, acked count, unacked count].
     825          @rtype: list
     826          """
     827          raise NotImplementedError
     828
     829
     830 -    def getEventDetailFromStatusOrHistory(self, evid=None, dedupid=None,
     831                                                              better=False):
     832          try:
     833              event = self.dmd.ZenEventManager.getEventDetail(
     834                                                      evid, dedupid, better)
     835          except ZenEventNotFound:
     836              event = self.dmd.ZenEventHistory.getEventDetail(evid, dedupid,
     837                                                                          better)
     838          return event
     839
     840
     841 -    def getEventDetail(self, evid=None, dedupid=None, better=False):
     842          """
     843          Return an EventDetail object for a particular event.
     844
     845          @param evid: Event ID
     846          @type evid: string
     847          @param dedupid: string used to determine duplicates
     848          @type dedupid: string
     849          @param better: provide even more detail than normal?
     850          @type better: boolean
     851          @return: fields from the event
     852          @rtype: EventDetail object
     853          """
     854          idfield = evid and "evid" or "dedupid"
     855          if not evid: evid = dedupid
     856          cachekey = '%s%s' % (idfield, evid)
     857          event = self.checkCache(cachekey)
     858          if event: return event
     859          fields = self.getFieldList()
     860          evid = self.escape(evid)
     861          selectevent = "select "
     862          selectevent += ", ".join(fields)
     863          selectevent += " from %s where" % self.statusTable
     864          selectevent += " %s = '%s'" % (idfield, evid)
     865          conn = self.connect()
     866          try:
     867              curs = conn.cursor()
     868              curs.execute(selectevent)
     869              evrow = curs.fetchone()
     870              if not evrow:
     871                  raise ZenEventNotFound( "Event id '%s' not found" % evid)
     872              evdata = map(self.convert, fields, evrow)
     873              if better:
     874                  event = BetterEventDetail(self, fields, evdata)
     875              else:
     876                  event = EventDetail(self, fields, evdata)
     877
     878              selectdetail = "select name, value from %s where" % self.detailTable
     879              selectdetail += " evid = '%s'" % event.evid
     880              #print selectdetail
     881              curs.execute(selectdetail)
     882              event._details = curs.fetchall()
     883
     884              selectlogs = "select userName, ctime, text"
     885              selectlogs += " from %s where" % self.logTable
     886              selectlogs += " evid = '%s' order by ctime desc" % event.evid
     887              #print selectlogs
     888              curs.execute(selectlogs)
     889              jrows = curs.fetchall()
     890              logs = []
     891              for row in jrows:
     892                  user = self.cleanstring(row[0])
     893                  date = self.dateString(row[1])
     894                  text = row[2]
     895                  logs.append((user, date, text))
     896              event._logs = logs
     897          finally: self.close(conn)
     898
     899          self.addToCache(cachekey, event)
     900          self.cleanCache()
     901          return event
     902
     903
     904 -    def getStatusME(self, me, statusclass=None, **kwargs):
     905          """
     906          """
     907          from Products.ZenModel.Organizer import Organizer
     908          if me.event_key == "Device":
     909              return self.getDeviceStatus(me.getId(), statusclass, **kwargs)
     910          elif me.event_key == "Component":
     911              return self.getComponentStatus(me.getParentDeviceName(),
     912                                        me.getId(), statusclass, **kwargs)
     913          elif isinstance(me, Organizer):
     914              return self.getOrganizerStatus(me, statusclass=statusclass,
     915                                              **kwargs)
     916          else:
     917              return self.getGenericStatus(me)
     918
     919
     920 -    def getGenericStatus(self, me):
     921          """Return status based on a where clause defined for the me event_type.
     922          No fancy caching done this might be a little slow if there are a lot
     923          of events.  Where clause is evaled
     924          """
     925          where = self.lookupManagedEntityWhere(me)
     926          select = "select count(*) from %s where %s" % (self.statusTable, where)
     927          statusCount = self.checkCache(select)
     928          if not statusCount:
     929              conn = self.connect()
     930              try:
     931                  curs = conn.cursor()
     932                  #print select
     933                  curs.execute(select)
     934                  statusCount = curs.fetchone()[0]
     935              finally: self.close(conn)
     936
     937              self.addToCache(select,statusCount)
     938          return statusCount
     939
     940
     941 -    def getOrganizerStatus(self, org, statusclass=None, severity=None,
     942                             state=0, where=""):
     943          """see IEventStatus
     944          """
     945          orgfield = self.lookupManagedEntityField(org.event_key)
     946          select = "select %s from %s where " % (orgfield, self.statusTable)
     947          where = self._wand(where, "%s = '%s'", self.eventClassField,statusclass)
     948          where = self._wand(where, "%s >= %s", self.severityField, severity)
     949          where = self._wand(where, "%s <= %s", self.stateField, state)
     950          select += where
     951          #print select
     952          statusCache = self.checkCache(select)
     953          if not statusCache:
     954              conn = self.connect()
     955              try:
     956                  curs = conn.cursor()
     957                  curs.execute(select)
     958                  statusCache=[]
     959                  orgdict={}
     960                  for row in curs.fetchall():
     961                      orgfield = self.cleanstring(row[0])
     962                      if not orgfield: continue
     963                      if orgfield.startswith("|"): orgfield = orgfield[1:]
     964                      for orgname in orgfield.split("|"):
     965                          orgdict.setdefault(orgname, 0)
     966                          orgdict[orgname] += 1
     967                  statusCache = orgdict.items()
     968                  self.addToCache(select,statusCache)
     969              finally: self.close(conn)
     970          countevts = 0
     971          for key, value  in statusCache:
     972              if key.startswith(org.getOrganizerName()):
     973                  countevts += value
     974          return countevts
     975
     976
     977 -    def getOrganizerStatusIssues(self, event_key,severity=4,state=0,
     978                                  where="", limit=0):
     979          """Return list of tuples (org, count) for all organizers with events.
     980          """
     981          orgfield = self.lookupManagedEntityField(event_key)
     982          select = "select %s, count from %s where " % (orgfield,self.statusTable)
     983          where = self._wand(where, "%s >= %s", self.severityField, severity)
     984          where = self._wand(where, "%s <= %s", self.stateField, state)
     985          where = self._wand(where,"%s like '%s'",self.eventClassField,"/Status%")
     986          select += where
     987          statusCache = self.checkCache(select)
     988          if not statusCache:
     989              conn = self.connect()
     990              try:
     991                  curs = conn.cursor()
     992                  curs.execute(select)
     993                  statusCache=[]
     994                  orgdict={}
     995                  for row in curs.fetchall():
     996                      orgfield = self.cleanstring(row[0])
     997                      if not orgfield: continue
     998                      if orgfield.startswith("|"): orgfield = orgfield[1:]
     999                      for orgname in orgfield.split("|"):
    1000                          if not orgname: continue
    1001                          count, total = orgdict.setdefault(orgname, (0,0))
    1002                          count+=1
    1003                          total+=row[1]
    1004                          orgdict[orgname] = (count,total)
    1005                  statusCache = [ [n, c[0], int(c[1])] for n, c in orgdict.items() ]
    1006                  statusCache.sort(lambda x,y: cmp(x[1],y[1]))
    1007                  statusCache.reverse()
    1008                  if limit:
    1009                      statusCache = statusCache[:limit]
    1010                  self.addToCache(select,statusCache)
    1011              finally: self.close(conn)
    1012          return statusCache
    1013
    1014
    1015 -    def getDevicePingIssues(self, state=2, limit=0):
    1016          """Return devices with ping problems.
    1017          """
    1018          return self.getDeviceIssues(where="eventClass = '%s'" % Status_Ping,
    1019                                      severity=3,
    1020                                      state=state,
    1021                                      limit=limit)
    1022
    1023
    1024 -    def getDeviceStatusIssues(self, severity=4, state=1, limit=0):
    1025          """Return only status issues.
    1026          """
    1027          return self.getDeviceIssues(where="eventClass like '/Status%'",
    1028                              severity=severity, state=state, limit=limit)
    1029
    1030
    1031 -    def getDeviceIssues(self,severity=1,state=0,where="",mincount=0,limit=0):
    1032          """Return list of tuples (device, count, total) of events for
    1033          all devices with events.
    1034          """
    1035          where = self._wand(where, "%s >= %s", self.severityField, severity)
    1036          where = self._wand(where, "%s <= %s", self.stateField, state)
    1037          select = """select distinct device, count(device) as evcount,
    1038                      sum(count) from status where %s group by device
    1039                      having evcount > %s""" % (where, mincount)
    1040          statusCache = self.checkCache(select)
    1041          if not statusCache:
    1042              try:
    1043                  conn = self.connect()
    1044                  try:
    1045                      curs = conn.cursor()
    1046                      curs.execute(select)
    1047                      statusCache = [ [d,int(c),int(s)] for d,c,s in curs.fetchall() ]
    1048                      #statusCache = list(curs.fetchall())
    1049                      statusCache.sort(lambda x,y: cmp(x[1],y[1]))
    1050                      statusCache.reverse()
    1051                      if limit:
    1052                          statusCache = statusCache[:limit]
    1053                  finally: self.close(conn)
    1054              except:
    1055                  log.exception(select)
    1056                  raise
    1057          return statusCache
    1058
    1059
    1060 -    def getDeviceStatus(self, device, statclass=None, countField=None,
    1061                          severity=3, state=None, where=""):
    1062          """see IEventStatus
    1063          """
    1064          if countField == None: countField = self.countField
    1065          select = "select %s, %s from %s where " % (
    1066                    self.deviceField, self.countField, self.statusTable)
    1067          where = self._wand(where, "%s = '%s'", self.eventClassField, statclass)
    1068          where = self._wand(where, "%s >= %s", self.severityField, severity)
    1069          where = self._wand(where, "%s <= %s", self.stateField, state)
    1070          select += where
    1071          #print select
    1072          statusCache = self.checkCache(select)
    1073          if not statusCache:
    1074              try:
    1075                  conn = self.connect()
    1076                  try:
    1077                      curs = conn.cursor()
    1078                      curs.execute(select)
    1079                      statusCache = {}
    1080                      for dev, count in curs.fetchall():
    1081                          dev = self.cleanstring(dev)
    1082                          statusCache[dev] = count
    1083                      self.addToCache(select,statusCache)
    1084                  finally: self.close(conn)
    1085              except:
    1086                  log.exception("status failed for device %s", device)
    1087                  return -1
    1088          return statusCache.get(device, 0)
    1089
    1090
    1091 -    def defaultAvailabilityStart(self):
    1092          return Time.USDate(time.time() - 60*60*24*self.defaultAvailabilityDays)
    1093
    1094
    1095 -    def defaultAvailabilityEnd(self):
    1096          return Time.USDate(time.time())
    1097
    1098
    1099 -    def getAvailability(self, state, **kw):
    1100          import Availability
    1101          allowedFilters = (
    1102              "device", "component", "eventClass", "systems", "severity",
    1103              "prodState", "manager", "agent", "DeviceClass", "Location",
    1104              "System", "DeviceGroup", "DevicePriority", "monitor")
    1105
    1106          for name in allowedFilters:
    1107              if hasattr(state, name):
    1108                  kw.setdefault(name, getattr(state, name))
    1109          if getattr(state, 'startDate', None) is not None:
    1110              kw.setdefault('startDate', Time.ParseUSDate(state.startDate))
    1111          if getattr(state, 'endDate', None) is not None:
    1112              # End date needs to be inclusive of events that occurred on that
    1113              # date. So we advance to the last second of the day.
    1114              kw.setdefault('endDate', Time.getEndOfDay(Time.ParseUSDate(
    1115                  state.endDate)))
    1116          kw.setdefault('startDate',
    1117                        time.time() - 60*60*24*self.defaultAvailabilityDays)
    1118          return Availability.query(self.dmd, **kw)
    1119
    1120
    1121 -    def getHeartbeat(self, failures=True, simple=False, limit=0, db=None):
    1122          """Return all heartbeat issues list of tuples (device, component, secs)
    1123          """
    1124          sel = "select device, component, lastTime from heartbeat"
    1125          if failures:
    1126              sel += " where DATE_ADD(lastTime, INTERVAL timeout SECOND) <= NOW()"
    1127
    1128          statuses = []
    1129          conn = self.connect()
    1130          try:
    1131              curs = conn.cursor()
    1132              curs.execute(sel)
    1133              res = list(curs.fetchall())
    1134              res.sort(lambda x,y: cmp(x[2],y[2]))
    1135              devclass = self.getDmdRoot("Devices")
    1136              for devname, comp, lastTime in res:
    1137                  dtime = int(time.time() - lastTime.timeTime())
    1138
    1139                  alink = devname
    1140                  if not simple:
    1141                      dev = devclass.findDevice(devname)
    1142                      if dev:
    1143                          alink = "<a href='%s'>%s</a>" % (
    1144                                  dev.getPrimaryUrlPath(), dev.titleOrId())
    1145
    1146                  statuses.append([alink, comp, str(dtime), devname])
    1147              if limit:
    1148                  statuses = statuses[:limit]
    1149          finally:
    1150              self.close(conn)
    1151          return statuses
    1152
    1153 -    def getHeartbeatObjects(self, failures=True, simple=False, limit=0, db=None):
    1154          beats = self.getHeartbeat(failures, simple, limit, db)
    1155          return [{'alink':b[0], 'comp':b[1], 'dtime':b[2], 'devId':b[3]}
    1156                  for b in beats]
    1157
    1158
    1159 -    def getAllComponentStatus(self,
    1160                                statclass,
    1161                                countField=None,
    1162                                severity=3,
    1163                                state=1,
    1164                                where=""):
    1165          "Fetch the counts on all components matching statClass"
    1166          if countField == None: countField = self.countField
    1167          select = "select %s, %s, %s from %s where "\
    1168                    % (self.deviceField, self.componentField, countField,
    1169                       self.statusTable)
    1170          where = self._wand(where, "%s = '%s'", self.eventClassField, statclass)
    1171          where = self._wand(where, "%s >= %s", self.severityField, severity)
    1172          where = self._wand(where, "%s <= %s", self.stateField, state)
    1173          select += where
    1174          conn = self.connect()
    1175          try:
    1176              curs = conn.cursor()
    1177              curs.execute(select)
    1178              result = {}
    1179              for dev, comp, count in curs.fetchall():
    1180                  dev = self.cleanstring(dev)
    1181                  comp = self.cleanstring(comp)
    1182                  result[dev,comp] = count
    1183              return result
    1184          finally:
    1185              self.close(conn)
    1186
    1187
    1188 -    def getMaxSeverity(self, me):
    1189          """ Returns the severity of the most severe event. """
    1190          where = self.lookupManagedEntityWhere(me.device())
    1191          if me.event_key == 'Component':
    1192              where = self._wand(where, "%s = '%s'",
    1193                  self.componentField, me.id)
    1194          select = "select max(%s) from %s where " % (self.severityField,
    1195              self.statusTable)
    1196          query = select + where
    1197          conn = self.connect()
    1198          try:
    1199              curs = conn.cursor()
    1200              curs.execute(query)
    1201              severity = curs.fetchall()[0][0]
    1202          finally: self.close(conn)
    1203          return max(severity, 0)
    1204
    1205
    1206 -    def getComponentStatus(self, device, component, statclass=None,
    1207                      countField=None, severity=3, state=1, where=""):
    1208          """see IEventStatus
    1209          """
    1210          if countField == None: countField = self.countField
    1211          select = "select %s, %s, %s from %s where "\
    1212                    % (self.deviceField, self.componentField, countField,
    1213                    self.statusTable)
    1214          where = self._wand(where, "%s = '%s'", self.eventClassField, statclass)
    1215          where = self._wand(where, "%s >= %s", self.severityField, severity)
    1216          where = self._wand(where, "%s <= %s", self.stateField, state)
    1217          select += where
    1218          statusCache = self.checkCache(select)
    1219          if not statusCache:
    1220              conn = self.connect()
    1221              try:
    1222                  curs = conn.cursor()
    1223                  curs.execute(select)
    1224                  statusCache ={}
    1225                  for dev, comp, count in curs.fetchall():
    1226                      dev = self.cleanstring(dev)
    1227                      comp = self.cleanstring(comp)
    1228                      statusCache[dev+comp] = count
    1229                  self.addToCache(select,statusCache)
    1230              finally: self.close(conn)
    1231          return statusCache.get(device+component, 0)
    1232
    1233 -    def getBatchComponentInfo(self, components):
    1234          """
    1235          Given a list of dicts with keys 'device', 'component', make a query to
    1236          get an overall severity and device status for the group.
    1237          """
    1238          severity, state = 3, 1
    1239          components = list(components) # Sometimes a generator. We use it twice.
    1240
    1241          def doQuery(query):
    1242              conn = self.connect()
    1243              data = None
    1244              try:
    1245                  curs = conn.cursor()
    1246                  curs.execute(query)
    1247                  data = curs.fetchall()
    1248              finally: self.close(conn)
    1249              return data
    1250
    1251          select = "select MAX(%s) from %s where " % (self.severityField,
    1252                                                      self.statusTable)
    1253          where = self._wand("", "%s >= %s", self.severityField, severity)
    1254          where = self._wand(where, "%s <= %s", self.stateField, state)
    1255          def componentWhere(device, component):
    1256              return "device = '%s' and component= '%s'" % (device, component)
    1257          cwheres = ' and ' + ' or '.join(['(%s)'% componentWhere(**comp)
    1258                                          for comp in components])
    1259          sevquery = select + where + cwheres
    1260
    1261          select = "select MAX(%s) from %s where " % (self.countField,
    1262                                                      self.statusTable)
    1263          where = self._wand("", "%s >= %s", self.severityField, severity)
    1264          where = self._wand(where, "%s <= %s", self.stateField, state)
    1265          where = self._wand(where, "%s = '%s'", self.eventClassField,
    1266                             '/Status/Ping')
    1267          devwhere = lambda d:"device = '%s'" % d
    1268          dwheres = ' and ' + '(%s)' % (' or '.join(
    1269              map(devwhere, [x['device'] for x in components])))
    1270          statquery = select + where + dwheres
    1271
    1272          maxseverity = doQuery(sevquery)[0][0]
    1273          maxstatus = doQuery(statquery)[0][0]
    1274          return maxseverity, maxstatus
    1275
    1276 -    def getEventOwnerListME(self, me, severity=0, state=1):
    1277          """Return list of event owners based on passed in managed entity.
    1278          """
    1279          try:
    1280              where = self.lookupManagedEntityWhere(me)
    1281              return self.getEventOwnerList(where, severity, state)
    1282          except:
    1283              log.exception("event summary for %s failed" % me.getDmdKey())
    1284              raise
    1285
    1286
    1287 -    def getEventOwnerList(self, where="", severity=0, state=1):
    1288          """Return a list of userids that correspond to the events in where.
    1289          select distinct ownerid from status where
    1290          device="win2k.confmon.loc" and eventState > 2
    1291          """
    1292          select ="select distinct ownerid from status where "
    1293          where = self._wand(where, "%s >= %s", self.severityField, severity)
    1294          where = self._wand(where, "%s <= %s", self.stateField, state)
    1295          select += where
    1296          #print select
    1297          statusCache = self.checkCache(select)
    1298          if statusCache: return statusCache
    1299          conn = self.connect()
    1300          try:
    1301              curs = conn.cursor()
    1302              curs.execute(select)
    1303              statusCache = [ uid[0] for uid in curs.fetchall() if uid[0] ]
    1304              self.addToCache(select,statusCache)
    1305          finally: self.close(conn)
    1306          return statusCache
    1307
    1308
    1309 -    def lookupManagedEntityWhere(self, me):
    1310          """
    1311          Lookup and build where clause for managed entity.
    1312
    1313          @param me: managed entity
    1314          @type me: object
    1315          @return: where clause
    1316          @rtype: string
    1317          """
    1318          key = me.event_key + "Where"
    1319          wheretmpl = getattr(aq_base(self), key, False)
    1320          if not wheretmpl:
    1321              raise ValueError("No 'where' clause found for event_key %s" % me.event_key)
    1322
    1323          # This code snippet is meant to fake out the where requirement
    1324          # We want no filter on the device so in effect "where 1" achieves
    1325          # this in sql syntax
    1326          if me.id == 'Devices':
    1327              return '(DeviceCLass like \'/%\')'
    1328          return eval(wheretmpl,{'me':me})
    1329
    1330
    1331 -    def lookupManagedEntityField(self, event_key):
    1332          """
    1333          Lookup database field for managed entity default
    1334          using event_key.
    1335
    1336          @param event_key: event
    1337          @type event_key: string
    1338          @return: field for the managed entity
    1339          @rtype: object
    1340          """
    1341          key = event_key + "Field"
    1342          return getattr(aq_base(self), key, event_key)
    1343
    1344
    1345 -    def lookupManagedEntityResultFields(self, event_key):
    1346          """
    1347          Gets the column names that should be requested in an event query for
    1348          this entity type.
    1349
    1350          Returns a set of result fields predefined for this entity type.  If
    1351          none have been defined, returns the default result fields.
    1352
    1353          >>> f = dmd.ZenEventManager.lookupManagedEntityResultFields('Device')
    1354          >>> f==dmd.ZenEventManager.DeviceResultFields
    1355          True
    1356          >>> f = dmd.ZenEventManager.lookupManagedEntityResultFields('Robot')
    1357          >>> f==dmd.ZenEventManager.defaultResultFields
    1358          True
    1359
    1360          @param event_key: The event key of a managed entity.
    1361          @type event_key: string
    1362          @return: A tuple of strings representing columns in the database.
    1363          """
    1364          key = event_key + "ResultFields"
    1365          fields = getattr(aq_base(self), key, self.defaultResultFields)
    1366          return fields
    1367
    1368
    1369 -    def _wand(self, where, fmt, field, value):
    1370          """
    1371          >>> dmd.ZenEventManager._wand('where 1=1', '%s=%s', 'a', 'b')
    1372          'where 1=1 and a=b'
    1373          >>> dmd.ZenEventManager._wand('where a=5', '%s=%s', 'a', 'b')
    1374          'where a=5'
    1375          >>> dmd.ZenEventManager._wand('where b=a', '%s=%s', 'a', 'b')
    1376          'where b=a'
    1377          """
    1378          if value != None and where.find(field) == -1:
    1379              if where: where += " and "
    1380              where += fmt % (field, value)
    1381          return where
    1382
    1383 -    def _setupDateRange(self, startdate=None,
    1384                                enddate=None):
    1385          """
    1386          Make a start and end date range that is at least one day long.
    1387          returns a start and end date as a proper database element.
    1388          """
    1389          if enddate is None:
    1390              enddate = DateTime.DateTime()-1
    1391          if startdate is None:
    1392              startdate = DateTime.DateTime()
    1393          if type(enddate) == types.StringType:
    1394              enddate = DateTime.DateTime(enddate, datefmt='us')
    1395          enddate = enddate.latestTime()
    1396          if type(startdate) == types.StringType:
    1397              startdate = DateTime.DateTime(startdate, datefmt='us')
    1398          startdate = startdate.earliestTime()
    1399          startdate = self.dateDB(startdate)
    1400          enddate = self.dateDB(enddate)
    1401          return startdate, enddate
    1402
    1403 -    def _scrubOrderby(self, orderby):
    1404          """
    1405          validates the syntax and columns for an orderby used on the status and
    1406          history tables. Also removes adjacent sorts of the same columns as an
    1407          optimization
    1408          @return: orderby by clause
    1409          @raise exception: if order by clause is invalid
    1410          """
    1411          sortValues = []
    1412          prevSortCol = None
    1413          fieldList = [x.lower() for x in self.getFieldList()]
    1414          log.debug("orderby is %s" % orderby)
    1415          for x in orderby.split(','):
    1416              col, dir = x.split()
    1417              col = col.lower()
    1418              dir = dir.upper()
    1419              if dir not in ['DESC','ASC'] or col not in fieldList:
    1420                  raise ("order by  value %s %s not valid" % (col, dir))
    1421              #remove adjacent sorts of same column;
    1422              if not prevSortCol or prevSortCol != col:
    1423                  sortValues.append((col, dir))
    1424              prevSortCol = col
    1425
    1426          orderby = ', '.join([' '.join(x) for x in sortValues])
    1427
    1428          log.debug("final orderby is %s" % orderby)
    1429          return orderby
    1430
    1431 -    def getAvgFieldLength(self, fieldname):
    1432          conn = self.connect()
    1433          try:
    1434              curs = conn.cursor()
    1435              selstatement = ("SELECT AVG(CHAR_LENGTH(mycol))+20 FROM (SELECT %s AS "
    1436                              "mycol FROM %s WHERE %s IS NOT NULL LIMIT 500) AS "
    1437                              "a;") % (fieldname, self.statusTable, fieldname)
    1438              curs.execute(selstatement)
    1439              avglen = curs.fetchone()
    1440          finally: self.close(conn)
    1441          try: return float(avglen[0])
    1442          except TypeError: return 10.
    1443
    1444
    1445      #==========================================================================
    1446      # Event sending functions
    1447      #==========================================================================
    1448
    1449      security.declareProtected(ZEN_SEND_EVENTS, 'sendEvents')
    1450 -    def sendEvents(self, events):
    1451          """Send a group of events to the backend.
    1452          """
    1453          count = 0
    1454          for event in events:
    1455              try:
    1456                  self.sendEvent(event)
    1457                  count += 1
    1458              except Exception, ex:
    1459                  log.exception(ex)
    1460          return count
    1461
    1462
    1463      security.declareProtected(ZEN_SEND_EVENTS, 'sendEvent')
    1464 -    def sendEvent(self, event):
    1465          """
    1466          Send an event to the backend.
    1467
    1468          @param event: event
    1469          @type event: event object
    1470          @todo: implement
    1471          """
    1472          raise NotImplementedError
    1473
    1474
    1475      #==========================================================================
    1476      # Schema management functions
    1477      #==========================================================================
    1478
    1479 -    def convert(self, field, value):
    1480          """Perform convertion of value coming from database value if nessesary.
    1481          """
    1482          value = self.cleanstring(value)
    1483          #FIXME this is commented out because we often need severity as a
    1484          # number (like in ZEvent.getCssClass) and sorting.  Need to have
    1485          # both fields at some point
    1486          #if field == self.severityField:
    1487          #    idx = len(self.severityConversions) - value
    1488          #    value = self.severityConversions[idx][0]
    1489          #elif field == 'prodState':
    1490          #    value = self.dmd.convertProdState(value)
    1491          if self.isDate(field):
    1492              value = self.dateString(value)
    1493          return value
    1494
    1495
    1496      security.declareProtected(ZEN_VIEW, "getFieldList")
    1497 -    def getFieldList(self):
    1498          """Return a list of all fields in the status table of the  backend.
    1499          """
    1500          if not getattr(self, '_fieldlist', None):
    1501              self.loadSchema()
    1502          return self._fieldlist
    1503
    1504 -    def getEventStates(self):
    1505          """Return a list of possible event states.
    1506          """
    1507          return self.eventStateConversions
    1508
    1509 -    def getEventActions(self):
    1510          """Return a list of possible event actions.
    1511          """
    1512          return self.eventActions
    1513
    1514      security.declareProtected(ZEN_COMMON,'getSeverities')
    1515 -    def getSeverities(self):
    1516          """Return a list of tuples of severities [('Warning', 3), ...]
    1517          """
    1518          return self.severityConversions
    1519
    1520 -    def getSeverityString(self, severity):
    1521          """Return a string representation of the severity.
    1522          """
    1523          try:
    1524              return self.severities[severity]
    1525          except KeyError:
    1526              return "Unknown"
    1527
    1528 -    def getPriorities(self):
    1529          """Return a list of tuples of priorities [('Warning', 3), ...]
    1530          """
    1531          return self.priorityConversions
    1532
    1533 -    def getPriorityString(self, priority):
    1534          """Return the priority name
    1535          """
    1536          try:
    1537              return self.priorities[priority]
    1538          except IndexError:
    1539              return "Unknown"
    1540
    1541 -    def convertEventField(self, field, value, default=""):
    1542          """
    1543          Convert numeric values commonly found in events to their textual
    1544          representation.
    1545          """
    1546          if value is None: return default
    1547          try:
    1548              value = int(value)
    1549          except ValueError:
    1550              return "unknown (%r)" % (value,)
    1551
    1552          if field == 'severity' and self.severities.has_key(value):
    1553              return "%s (%d)" % (self.severities[value], value)
    1554          elif field == "priority" and self.priorities.has_key(value):
    1555              return "%s (%d)" % (self.priorities[value], value)
    1556          elif field == 'eventState':
    1557              if value < len(self.eventStateConversions):
    1558                  return "%s (%d)" % (self.eventStateConversions[value][0], value)
    1559          elif field == "prodState":
    1560              prodState = self.dmd.convertProdState(value)
    1561              if isinstance(prodState, types.StringType):
    1562                  return "%s (%d)" % (prodState, value)
    1563          elif field == "DevicePriority":
    1564              priority = self.dmd.convertPriority(value)
    1565              if isinstance(priority, types.StringType):
    1566                  return "%s (%d)" % (priority, value)
    1567
    1568          return "unknown (%r)" % (value,)
    1569
    1570
    1571 -    def getStatusCssClass(self, status):
    1572          if status < 0: status = "unknown"
    1573          elif status > 3: status = 3
    1574          return "zenstatus_%s" % status
    1575
    1576
    1577 -    def getStatusImgSrc(self, status):
    1578          ''' Return the img source for a status number
    1579          '''
    1580          if status < 0:
    1581              src = 'grey'
    1582          elif status == 0:
    1583              src = 'green'
    1584          else:
    1585              src = 'red'
    1586          return '/zport/dmd/img/%s_dot.png' % src
    1587
    1588
    1589 -    def getEventCssClass(self, severity, acked=False):
    1590          """return the css class name to be used for this event.
    1591          """
    1592          __pychecker__='no-constCond'
    1593          value = severity < 0 and "unknown" or severity
    1594          acked = acked and "acked" or "noack"
    1595          return "zenevents_%s_%s %s" % (value, acked, acked)
    1596
    1597
    1598 -    def isDate(self, colName):
    1599          """Check to see if a column is of type date.
    1600          """
    1601          if not self._schema:
    1602              self.getFieldList()
    1603          return self._schema.get(colName, False)
    1604
    1605
    1606 -    def dateString(self, value):
    1607          """Convert a date from database format to string.
    1608          """
    1609          if isinstance(value, DateTime.DateTime):
    1610              value = value.timeTime()
    1611          return Time.LocalDateTime(value)
    1612
    1613
    1614
    1615 -    def dateDB(self, value):
    1616          """Convert a date to its database format.
    1617          """
    1618          if isinstance(value, DateTime.DateTime):
    1619              return "%.3f" % value.timeTime()
    1620          elif isinstance(value, basestring):
    1621              return "%.3f" % DateTime.DateTime(value).timeTime()
    1622          return value
    1623
    1624
    1625 -    def escape(self, value):
    1626          """
    1627          Prepare string values for db by escaping special characters.
    1628
    1629          @param value: string
    1630          @type value: string
    1631          @todo: implement
    1632          """
    1633          raise NotImplementedError
    1634
    1635
    1636 -    def loadSchema(self):
    1637          """Load schema from database. If field is a date set value to true."""
    1638          schema = {}
    1639          fieldlist = []
    1640          sql = "describe %s;" % self.statusTable
    1641          conn = self.connect()
    1642          try:
    1643              curs = conn.cursor()
    1644              curs.execute(sql)
    1645              for row in curs.fetchall():
    1646                  fieldlist.append(row[0])
    1647                  col = self.cleanstring(row[0])
    1648                  if self.backend == "mysql":
    1649                      type = row[1] in ("datetime", "timestamp", "double")
    1650                  schema[col] = type
    1651              if schema: self._schema = schema
    1652              self._fieldlist = fieldlist
    1653          finally: self.close(conn)
    1654
    1655
    1656 -    def eventControls(self):
    1657          """Are there event controls on this event list.
    1658          """
    1659          if self.isManager() and self.statusTable in ["status","history"]:
    1660              return 1
    1661          return 0
    1662
    1663 -    def updateEvents(self, stmt, whereClause, reason,
    1664                       table="status", toLog=True):
    1665          userId = getSecurityManager().getUser().getId()
    1666          insert = 'INSERT INTO log (evid, userName, text) ' + \
    1667                   'SELECT evid, "%s", "%s" ' % (userId, reason) + \
    1668                   'FROM %s ' % table + whereClause
    1669          query = stmt + ' ' + whereClause
    1670          conn = self.connect()
    1671          try:
    1672              curs = conn.cursor()
    1673              if toLog: curs.execute(insert)
    1674              curs.execute(query)
    1675          finally: self.close(conn)
    1676          self.clearCache()
    1677          self.manage_clearCache()
    1678
    1679      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_addEvent')
    1680 -    def manage_addEvent(self, REQUEST=None):
    1681          ''' Create an event from user supplied data
    1682          '''
    1683          if REQUEST is None:
    1684              return
    1685
    1686          defaultFields = set(self.dmd.ZenEventManager.getFieldList())
    1687          ignoreFields = set(['eventClass', 'count', 'clearid',
    1688               'clearid', 'eventClassMapping', 'stateChange', 'evid',
    1689               'eventState', 'lastTime', 'dedupid', 'firstTime', 'prodState', ])
    1690          eventDict = dict([(field, REQUEST.get(field, '')) \
    1691                             for field in defaultFields - ignoreFields ])
    1692
    1693          # We don't want to put empty eventClass into the dict because that
    1694          # can keep the event from being mapped to /Unknown correctly.
    1695          if REQUEST.get('eventClass', None):
    1696              eventDict['eventClass'] = REQUEST['eventClass']
    1697
    1698          try:
    1699              evid = self.sendEvent(eventDict)
    1700          except ZenEventError, ex:
    1701              log.exception("Invalid event not processed = %s" % eventDict)
    1702              messaging.IMessageSender(self).sendToBrowser(
    1703                 'Invalid Event', str(ex),
    1704                 priority=messaging.WARNING
    1705              )
    1706              return self.callZenScreen(REQUEST)
    1707          except ZenBackendFailure, ex:
    1708              log.exception("Event not processed = %s" % eventDict)
    1709              messaging.IMessageSender(self).sendToBrowser(
    1710                 'Unable to process Event', str(ex),
    1711                 priority=messaging.WARNING
    1712              )
    1713              return self.callZenScreen(REQUEST)
    1714
    1715          if 'RESPONSE' in REQUEST:
    1716              REQUEST['RESPONSE'].redirect('/zport/dmd/Events/viewEvents')
    1717          else:
    1718              return evid
    1719
    1720
    1721 -    def deleteEvents(self, whereClause, reason):
    1722          self.updateEvents('DELETE FROM status', whereClause, reason)
    1723
    1724
    1725      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteEvents')
    1726 -    def manage_deleteEvents(self, evids=(), REQUEST=None):
    1727          "Delete the given event ids"
    1728          if type(evids) == type(''):
    1729              evids = [evids]
    1730          num = len(evids)
    1731          if evids:
    1732              evids = ",".join([ "'%s'" % evid for evid in evids])
    1733              userid = getSecurityManager().getUser()
    1734              update = "update status set ownerid='%s' " % userid
    1735              whereClause = ' where evid in (%s)' % evids
    1736              self.updateEvents(update, whereClause, '', toLog=False)
    1737              self.deleteEvents(whereClause, 'Deleted by user')
    1738          if REQUEST:
    1739              messaging.IMessageSender(self).sendToBrowser(
    1740                  'Moved To History',
    1741                  '%s event%s have been moved to history.' % (
    1742                                  num, (num != 1 and 's') or '')
    1743              )
    1744              return self.callZenScreen(REQUEST)
    1745
    1746 -    def undeleteEvents(self, whereClause, reason):
    1747          fields = self.getFieldList()
    1748          if 'deletedTime' in fields:
    1749              fields.remove('deletedTime')
    1750          fields = ','.join(fields)
    1751          # Blank out clearid
    1752          fields = fields.replace('clearid','NULL')
    1753          evmgr = self.dmd.ZenEventManager
    1754          evmgr.updateEvents('INSERT status ' + \
    1755                             'SELECT %s FROM history' % fields,
    1756                             whereClause + ' ON DUPLICATE KEY UPDATE '+
    1757                             'status.count=status.count+history.count',
    1758                             reason, 'history', toLog=False)
    1759          evmgr.updateEvents('DELETE FROM history', whereClause, \
    1760                             reason, 'history')
    1761
    1762      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_undeleteEvents')
    1763 -    def manage_undeleteEvents(self, evids=(), REQUEST=None):
    1764          "Move the given event ids into status and delete from history"
    1765          if type(evids) == type(''):
    1766              evids = [evids]
    1767          num = len(evids)
    1768          if evids:
    1769              evids = ",".join([ "'%s'" % evid for evid in evids])
    1770              whereClause = ' where evid in (%s)' % evids
    1771              self.undeleteEvents(whereClause, 'Undeleted by user')
    1772          if REQUEST:
    1773              messaging.IMessageSender(self).sendToBrowser(
    1774                  'Undeleted',
    1775                  '%s events have been moved out of history.' % num
    1776              )
    1777              return self.callZenScreen(REQUEST)
    1778
    1779
    1780      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteAllEvents')
    1781 -    def manage_deleteAllEvents(self, devname, REQUEST=None):
    1782          "Delete the events for a given Device (used for deleting the device"
    1783          whereClause = 'where device = "%s"' % devname
    1784          self.deleteEvents(whereClause, 'Device deleted')
    1785          if REQUEST:
    1786              messaging.IMessageSender(self).sendToBrowser(
    1787                  'Events Deleted',
    1788                  'Deleted all events for %s' % devname
    1789              )
    1790              return self.callZenScreen(REQUEST)
    1791
    1792
    1793      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteHistoricalEvents')
    1794 -    def manage_deleteHistoricalEvents(self, devname=None, agedDays=None,
    1795                                          REQUEST=None):
    1796          """
    1797          Delete historical events.  If devices is given then only delete
    1798          events for that device.  If agedDays is given then only delete
    1799          events that are older than that many days.
    1800          devname and agedDays are mutually exclusive.  No real reason for this
    1801          other than there is no current need to use both in same call and I
    1802          don't want to test the combination.
    1803          This is an option during device deletion.  It is also used
    1804          by zenactions to keep history table clean.
    1805
    1806          NB: Device.deleteDevice() is not currently calling this when devices
    1807          are deleted.  See ticket #2996.
    1808          """
    1809          import subprocess
    1810          import os
    1811          import Products.ZenUtils.Utils as Utils
    1812
    1813          cmd = Utils.zenPath('Products', 'ZenUtils', 'ZenDeleteHistory.py')
    1814          if devname:
    1815              args = ['--device=%s' % devname]
    1816          elif agedDays:
    1817              args = ['--numDays=%s' % agedDays]
    1818          else:
    1819              return
    1820          proc = subprocess.Popen(
    1821                  [cmd]+args, stdout=subprocess.PIPE,
    1822                  stderr=subprocess.STDOUT, env=os.environ)
    1823          # We are abandoning this proc to do it's thing. or not.  We don't
    1824          # want to block because we would delay user feedback on a device
    1825          # delete when this might take a while to perform.
    1826          if REQUEST:
    1827              messaging.IMessageSender(self).sendToBrowser(
    1828                  'Events Deleted',
    1829                  'Historical events have been deleted.'
    1830              )
    1831              return self.callZenScreen(REQUEST)
    1832          else:
    1833              # Maybe, just maybe, we might want to wait on the subprocess...
    1834              return proc
    1835
    1836
    1837      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_deleteHeartbeat')
    1838 -    def manage_deleteHeartbeat(self, devname, REQUEST=None):
    1839          if devname:
    1840              delete = "delete from heartbeat where device = '%s'" % devname
    1841              conn = self.connect()
    1842              try:
    1843                  curs = conn.cursor()
    1844                  curs.execute(delete);
    1845              finally: self.close(conn)
    1846          if REQUEST:
    1847              messaging.IMessageSender(self).sendToBrowser(
    1848                  'Heartbeats Cleared',
    1849                  'Heartbeat events have been moved to the history.'
    1850              )
    1851              return self.callZenScreen(REQUEST)
    1852
    1853
    1854      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_ackEvents')
    1855 -    def manage_ackEvents(self, evids=(), REQUEST=None):
    1856          "Ack the given event ids"
    1857          if type(evids) == type(''):
    1858              evids = [evids]
    1859          request = FakeRequest()
    1860          self.manage_setEventStates(1 , evids, REQUEST=request)
    1861          if REQUEST:
    1862              dest = '/zport/dmd/Events/evconsole'
    1863              if request.get('message', ''):
    1864                  dest += '?message=%s' % request['message']
    1865              if not getattr(REQUEST, 'dontRedirect', False):
    1866                  REQUEST['RESPONSE'].redirect(dest)
    1867
    1868
    1869      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_ackEvents')
    1870 -    def manage_unackEvents(self, evids=(), REQUEST=None):
    1871          "Unacknowledge the given event ids"
    1872          if type(evids) == type(''):
    1873              evids = [evids]
    1874          request = FakeRequest()
    1875          self.manage_setEventStates(0 , evids, REQUEST=request)
    1876          if REQUEST:
    1877              dest = '/zport/dmd/Events/evconsole'
    1878              if request.get('message', ''):
    1879                  dest += '?message=%s' % request['message']
    1880              if not getattr(REQUEST, 'dontRedirect', False):
    1881                  REQUEST['RESPONSE'].redirect(dest)
    1882
    1883
    1884      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_setEventStates')
    1885 -    def manage_setEventStates(self, eventState=None, evids=(),
    1886                                userid="", REQUEST=None):
    1887          reason = None
    1888          if eventState is not None and evids:
    1889              eventState = int(eventState)
    1890              if eventState > 0 and not userid:
    1891                  userid = getSecurityManager().getUser().getId()
    1892              update = "update status set eventState=%s, ownerid='%s' " % (
    1893                          eventState, userid)
    1894              whereClause = "where evid in ("
    1895              whereClause += ",".join([ "'%s'" % evid for evid in evids]) + ")"
    1896              reason = 'Event state changed to '
    1897              try:
    1898                  reason += self.eventStateConversions[eventState][0]
    1899              except KeyError:
    1900                  reason += 'unknown (%d)' % eventState
    1901              self.updateEvents(update, whereClause, reason)
    1902          if REQUEST:
    1903              return self.callZenScreen(REQUEST)
    1904
    1905
    1906      security.declareProtected(ZEN_MANAGE_EVENTS,'manage_setEventStates')
    1907 -    def manage_createEventMap(self, eventClass=None, evids=(),
    1908                                REQUEST=None):
    1909          """Create an event map from an event or list of events.
    1910          """
    1911          evclass = None
    1912          evmap = None
    1913          numCreated = 0
    1914          numNotUnknown = 0
    1915          numNoKey = 0
    1916          if eventClass and evids:
    1917              evclass = self.getDmdRoot("Events").getOrganizer(eventClass)
    1918              sel = """select eventClassKey, eventClass, message
    1919                      from %s where evid in ('%s')"""
    1920              sel = sel % (self.statusTable, "','".join(evids))
    1921              conn = self.connect()
    1922              try:
    1923                  curs = conn.cursor()
    1924                  curs.execute(sel);
    1925                  for row in curs.fetchall():
    1926                      evclasskey, curevclass, msg = row
    1927                      if curevclass != Unknown:
    1928                          numNotUnknown += 1
    1929                          continue
    1930                      if not evclasskey:
    1931                          numNoKey += 1
    1932                          continue
    1933                      evmap = evclass.createInstance(evclasskey)
    1934                      evmap.eventClassKey = evclasskey
    1935                      evmap.example = msg
    1936                      numCreated += 1
    1937                      evmap.index_object()
    1938              finally: self.close(conn)
    1939          elif REQUEST:
    1940              if not evids:
    1941                  messaging.IMessageSender(self).sendToBrowser(
    1942                      'Error',
    1943                      'No events selected',
    1944                      priority=messaging.WARNING
    1945                  )
    1946              elif not eventClass:
    1947                  messaging.IMessageSender(self).sendToBrowser(
    1948                      'Error',
    1949                      'No event class selected',
    1950                      priority=messaging.WARNING
    1951                  )
    1952
    1953          msg = ''
    1954          if numNotUnknown:
    1955              msg += ((msg and ' ') +
    1956                      '%s event%s %s not class /Unknown.' % (
    1957                          numNotUnknown,
    1958                          (numNotUnknown != 1 and 's') or '',
    1959                          (numNotUnknown != 1 and 'are') or 'is'))
    1960          if numNoKey:
    1961              msg += ((msg and ' ') +
    1962                      '%s event%s %s not have an event class key.' % (
    1963                          numNoKey,
    1964                          (numNoKey != 1 and 's') or '',
    1965                          (numNoKey != 1 and 'do') or 'does'))
    1966          msg += (msg and ' ') + 'Created %s event mapping%s.' % (
    1967                          numCreated,
    1968                          (numCreated != 1 and 's') or '')
    1969
    1970          url = None
    1971          if len(evids) == 1 and evmap:
    1972              url = evmap.absolute_url()
    1973          elif evclass and evmap:
    1974              url = evclass.absolute_url()
    1975
    1976          if REQUEST:
    1977              msg = REQUEST.get('message', '') + msg
    1978
    1979              messaging.IMessageSender(self).sendToBrowser('Event Map', msg)
    1980              # EventView might pass a fake Request during an ajax call from
    1981              # event console.  Don't bother rendering anything in this case.
    1982              if getattr(REQUEST, 'dontRender', False):
    1983                  return ''
    1984              if url:
    1985                  REQUEST['RESPONSE'].redirect(url)
    1986          else:
    1987              return msg, url
    1988
    1989
    1990      security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_refreshConversions')
    1991 -    def manage_refreshConversions(self, REQUEST=None):
    1992          """get the conversion information from the database server"""
    1993          assert(self == self.dmd.ZenEventManager)
    1994          self.loadSchema()
    1995          self.dmd.ZenEventHistory.loadSchema()
    1996          if REQUEST:
    1997              messaging.IMessageSender(self).sendToBrowser(
    1998                  'Event Schema', 'Event schema has been refreshed.')
    1999              return self.callZenScreen(REQUEST)
    2000
    2001
    2002      security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_editCache')
    2003 -    def manage_editCache(self, timeout=5, clearthresh=20, REQUEST=None):
    2004          """Reset cache values"""
    2005          self.timeout = int(timeout)
    2006          self.clearthresh = int(clearthresh)
    2007          if REQUEST:
    2008              message = "Cache parameters set"
    2009              return self.editCache(self, REQUEST, manage_tabs_message=message)
    2010
    2011
    2012      security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_clearCache')
    2013 -    def manage_clearCache(self, REQUEST=None):
    2014          """Reset cache values"""
    2015          assert(self == self.dmd.ZenEventManager)
    2016          self.cleanCache(force=1)
    2017          self.dmd.ZenEventHistory.cleanCache(force=1)
    2018          if REQUEST:
    2019              messaging.IMessageSender(self).sendToBrowser(
    2020                  'Event Cache', 'Event cache has been cleared.')
    2021              return self.callZenScreen(REQUEST)
    2022
    2023
    2024      security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_editEventManager')
    2025 -    def manage_editEventManager(self, REQUEST=None):
    2026          ''' Call zmanage_editProperties then take care of saving a few
    2027          values to ZenEventHistory
    2028          '''
    2029          assert(self == self.dmd.ZenEventManager)
    2030          self.zmanage_editProperties(REQUEST)
    2031          self.dmd.ZenEventHistory.timeout = REQUEST['history_timeout']
    2032          self.dmd.ZenEventHistory.clearthresh = REQUEST['history_clearthresh']
    2033          self.dmd.ZenEventHistory.username = self.dmd.ZenEventManager.username
    2034          self.dmd.ZenEventHistory.password = self.dmd.ZenEventManager.password
    2035          self.dmd.ZenEventHistory.database = self.dmd.ZenEventManager.database
    2036          self.dmd.ZenEventHistory.host = self.dmd.ZenEventManager.host
    2037          self.dmd.ZenEventHistory.port = self.dmd.ZenEventManager.port
    2038          if REQUEST: return self.callZenScreen(REQUEST)
    2039
    2040
    2041      security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'manage_clearHeartbeats')
    2042 -    def manage_clearHeartbeats(self, REQUEST=None):
    2043          """truncate heartbeat table"""
    2044          conn = self.connect()
    2045          try:
    2046              curs = conn.cursor()
    2047              sql = 'truncate table heartbeat'
    2048              curs.execute(sql)
    2049          finally: self.close(conn)
    2050          if REQUEST:
    2051              messaging.IMessageSender(self).sendToBrowser(
    2052                  'Heartbeats Cleared', 'Heartbeats have been cleared.')
    2053              return self.callZenScreen(REQUEST)
    2054
    2055      security.declareProtected(ZEN_MANAGE_EVENTMANAGER,'zmanage_editProperties')
    2056 -    def zmanage_editProperties(self, REQUEST=None):
    2057          ''' Need to handle editing of history event fields differently
    2058          '''
    2059          assert(self == self.dmd.ZenEventManager)
    2060          screenName = REQUEST.get('zenScreenName', '')
    2061          if screenName.find('editEventManagerHistoryFields') != -1 :
    2062              obj = self.dmd.ZenEventHistory
    2063          else:
    2064              obj = self
    2065          if screenName == 'editEventManager.pt':
    2066              # We renamed the password field to try to keep browsers from
    2067              # asking user if they wanted to save the password.
    2068              if REQUEST.has_key('mysql_pass'):
    2069                  REQUEST.form['password'] = REQUEST['mysql_pass']
    2070          editProperties = ZenModelRM.zmanage_editProperties
    2071          # suppress 'self is not first method argument' from pychecker
    2072          editProperties(obj, REQUEST)
    2073          if REQUEST: return self.callZenScreen(REQUEST)
    2074
    2075      security.declareProtected(ZEN_MANAGE_EVENTS, 'manage_addLogMessage')
    2076 -    def manage_addLogMessage(self, evid=None, message='', REQUEST=None):
    2077          """
    2078          Add a log message to an event
    2079          """
    2080          if not evid:
    2081              return
    2082          userId = getSecurityManager().getUser().getId()
    2083          conn = self.connect()
    2084          try:
    2085              curs = conn.cursor()
    2086              insert = 'INSERT INTO log (evid, userName, text) '
    2087              insert += 'VALUES ("%s", "%s", "%s")' % (evid,
    2088                                                       userId,
    2089                                                       conn.escape_string(message))
    2090              curs.execute(insert)
    2091          finally: self.close(conn)
    2092          self.clearCache('evid' + evid)
    2093          self.dmd.ZenEventHistory.clearCache('evid' + evid)
    2094          if REQUEST: return self.callZenScreen(REQUEST)
    2095
    2096
    2097      security.declareProtected(ZEN_MANAGE_EVENTMANAGER, 'manage_addCommand')
    2098 -    def manage_addCommand(self, id, REQUEST=None):
    2099          """
    2100          Add a new EventCommand
    2101
    2102          @param id: new command name
    2103          @type id: string
    2104          @param REQUEST: Zope REQUEST object
    2105          @type REQUEST: Zope REQUEST object
    2106          """
    2107          if id is None:
    2108              if REQUEST:
    2109                  return self.callZenScreen(REQUEST)
    2110              return
    2111
    2112          if not isinstance(id, unicode):
    2113              id = self.prepId(id)
    2114
    2115          id = id.strip()
    2116          if id == '':
    2117              if REQUEST:
    2118                  return self.callZenScreen(REQUEST)
    2119              return
    2120
    2121          ec = EventCommand(id)
    2122          self.commands._setObject(id, ec)
    2123          if REQUEST:
    2124              return self.callZenScreen(REQUEST)
    2125
    2126
    2127      security.declareProtected(ZEN_MANAGE_EVENTMANAGER, 'manage_deleteCommands')
    2128 -    def manage_deleteCommands(self, ids=[], REQUEST=None):
    2129          """
    2130          Delete an EventCommand
    2131
    2132          @param ids: commands to delete
    2133          @type ids: list of strings
    2134          @param REQUEST: Zope REQUEST object
    2135          @type REQUEST: Zope REQUEST object
    2136          """
    2137          for id in ids:
    2138              self.commands._delObject(id)
    2139          if REQUEST: return self.callZenScreen(REQUEST)
    2140
    2141
    2142      #==========================================================================
    2143      # Utility functions
    2144      #==========================================================================
    2145
    2146 -    def installIntoPortal(self):
    2147          """Install skins into portal.
    2148          """
    2149          from Products.CMFCore.utils import getToolByName
    2150          from Products.CMFCore.DirectoryView import addDirectoryViews
    2151          from cStringIO import StringIO
    2152          import string
    2153
    2154          out = StringIO()
    2155          skinstool = getToolByName(self, 'portal_skins')
    2156          if 'zenevents' not in skinstool.objectIds():
    2157              addDirectoryViews(skinstool, 'skins', globals())
    2158              out.write("Added 'zenevents' directory view to portal_skins\n")
    2159          skins = skinstool.getSkinSelections()
    2160          for skin in skins:
    2161              path = skinstool.getSkinPath(skin)
    2162              path = map(string.strip, string.split(path,','))
    2163              if 'zenevents' not in path:
    2164                  try: path.insert(path.index('zenmodel'), 'zenevents')
    2165                  except ValueError:
    2166                      path.append('zenevents')
    2167                  path = string.join(path, ', ')
    2168                  skinstool.addSkinSelection(skin, path)
    2169                  out.write("Added 'zenevents' to %s skin\n" % skin)
    2170              else:
    2171                  out.write(
    2172                      "Skipping %s skin, 'zenevents' is already set up\n" % skin)
    2173          return out.getvalue()
    2174