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