Package Products :: Package ZenWidgets :: Package browser :: Module Portlets |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenWidgets.browser.Portlets

      1  ##############################################################################
      2  #
      3  # Copyright (C) Zenoss, Inc. 2007, all rights reserved.
      4  #
      5  # This content is made available according to terms specified in
      6  # License.zenoss under the directory where your Zenoss product is installed.
      7  #
      8  ##############################################################################
      9
     10
     11  import re
     12  import json
     13
     14  from Products.Five.browser import BrowserView
     15  from Products.AdvancedQuery import Eq, Or
     16
     17  from Products.ZenUtils.Utils import relative_time
     18  from Products.Zuul import getFacade
     19  from Products.ZenEvents.HeartbeatUtils import getHeartbeatObjects
     20  from zenoss.protocols.services import ServiceException
     21  from zenoss.protocols.services.zep import ZepConnectionError
     22  from Products.ZenUtils.guid.interfaces import IGUIDManager
     23  from Products.ZenUtils.jsonutils import json
     24  from Products.ZenUtils.Utils import nocache, formreq, extractPostContent
     25  from Products.ZenWidgets import messaging
     26  from Products.ZenModel.Device import Device
     27  from Products.ZenModel.ZenossSecurity import *
     28  from Products.ZenEvents.browser.EventPillsAndSummaries import \
     29                                     getDashboardObjectsEventSummary, \
     30                                     ObjectsEventSummary,    \
     31                                     getEventPillME
     32
     33  import logging
     34  log = logging.getLogger('zen.portlets')
     35
     36
     37 -def zepConnectionError(retval=None):
     38      def outer(func):
     39          def inner(self, *args, **kwargs):
     40              try:
     41                  return func(self, *args, **kwargs)
     42              except ZepConnectionError, e:
     43                  msg = 'Connection refused. Check zeneventserver status on <a href="/zport/About/zenossInfo">Daemons</a>'
     44                  messaging.IMessageSender(self.context).sendToBrowser("ZEP connection error",
     45                                                          msg,
     46                                                          priority=messaging.CRITICAL,
     47                                                          sticky=True)
     48                  log.warn("Could not connect to ZEP")
     49              return retval
     50          return inner
     51      return outer
     52
     53 -class TopLevelOrganizerPortletView(ObjectsEventSummary):
     54      """
     55      Return JSON event summaries for a root organizer.
     56      """
     57      @nocache
     58      @formreq
     59 -    def __call__(self, dataRoot):
     60          self.dataRoot = dataRoot
     61          return super(TopLevelOrganizerPortletView, self).__call__()
     62
     63 -    def _getObs(self):
     64          return self.context.dmd.getDmdRoot(self.dataRoot).children()
     65
     66
     67 -class ProductionStatePortletView(BrowserView):
     68      """
     69      Return a map of device to production state in a format suitable for a
     70      YUI data table.
     71      """
     72      @nocache
     73      @formreq
     74 -    def __call__(self, *args, **kwargs):
     75          return self.getDevProdStateJSON(*args, **kwargs)
     76
     77      @json
     78 -    def getDevProdStateJSON(self, prodStates=['Maintenance']):
     79          """
     80          Return a map of device to production state in a format suitable for a
     81          YUI data table.
     82
     83          @return: A JSON representation of a dictionary describing devices
     84          @rtype: "{
     85              'columns':['Device', 'Prod State'],
     86              'data':[
     87                  {'Device':'<a href=/>', 'Prod State':'Production'},
     88                  {'Device':'<a href=/>', 'Prod State':'Maintenance'},
     89              ]}"
     90          """
     91          devroot = self.context.dmd.Devices
     92          if isinstance(prodStates, basestring):
     93              prodStates = [prodStates]
     94          orderby, orderdir = 'id', 'asc'
     95          catalog = getattr(devroot, devroot.default_catalog)
     96          queries = []
     97          for state in prodStates:
     98              queries.append(Eq('getProdState', state))
     99          query = Or(*queries)
    100          objects = catalog.evalAdvancedQuery(query, ((orderby, orderdir),))
    101          devs = (x.getObject() for x in objects)
    102          mydict = {'columns':['Device', 'Prod State'], 'data':[]}
    103          for dev in devs:
    104              if not self.context.checkRemotePerm(ZEN_VIEW, dev): continue
    105              mydict['data'].append({
    106                  'Device' : dev.getPrettyLink(),
    107                  'Prod State' : dev.getProdState()
    108              })
    109              if len(mydict['data'])>=100:
    110                  break
    111          return mydict
    112
    113
    114 -class WatchListPortletView(BrowserView):
    115      """
    116      Accepts a list of paths to Zope objects which it then attempts to resolve.
    117      If no list of paths is given, it will try to read them from the POST data
    118      of the REQUEST object.
    119
    120      @param entities: A list of paths that should be resolved into objects
    121          and passed to L{getDashboardObjectsEventSummaryJSON}.
    122      @type entities: list
    123      @return: A JSON-formatted string representation of the columns and rows
    124          of the table
    125      @rtype: string
    126      """
    127      @nocache
    128      @formreq
    129 -    def __call__(self, *args, **kwargs):
    130          return self.getEntityListEventSummary(*args, **kwargs)
    131
    132      @json
    133 -    def getEntityListEventSummary(self, entities=None):
    134          if entities is None:
    135              entities = []
    136          elif isinstance(entities, basestring):
    137              entities = [entities]
    138          def getob(e):
    139              e = str(e)
    140              try:
    141                  if not e.startswith('/zport/dmd'):
    142                      bigdev = '/zport/dmd' + e
    143                  obj = self.context.dmd.unrestrictedTraverse(bigdev)
    144              except (AttributeError, KeyError):
    145                  obj = self.context.dmd.Devices.findDevice(e)
    146              if self.context.has_permission("View", obj): return obj
    147          entities = filter(lambda x:x is not None, map(getob, entities))
    148          return getDashboardObjectsEventSummary(
    149              self.context.dmd.ZenEventManager, entities)
    150
    151
    152 -class DeviceIssuesPortletView(BrowserView):
    153      """
    154      A list of devices with issues.
    155      """
    156      @nocache
    157 -    def __call__(self):
    158          return self.getDeviceIssuesJSON()
    159
    160      @json
    161 -    def getDeviceIssuesJSON(self):
    162          """
    163          Get devices with issues in a form suitable for a portlet on the
    164          dashboard.
    165
    166          @return: A JSON representation of a dictionary describing devices
    167          @rtype: "{
    168              'columns':['Device', "Events'],
    169              'data':[
    170                  {'Device':'<a href=/>', 'Events':'<div/>'},
    171                  {'Device':'<a href=/>', 'Events':'<div/>'},
    172              ]}"
    173          """
    174          mydict = {'columns':[], 'data':[]}
    175          mydict['columns'] = ['Device', 'Events']
    176          deviceinfo = self.getDeviceDashboard()
    177          for alink, pill in deviceinfo:
    178              mydict['data'].append({'Device':alink,
    179                                     'Events':pill})
    180          return mydict
    181
    182      @zepConnectionError([])
    183 -    def getDeviceDashboard(self):
    184          """return device info for bad device to dashboard"""
    185          zep = getFacade('zep')
    186          manager = IGUIDManager(self.context.dmd)
    187          deviceSeverities = zep.getDeviceIssuesDict()
    188          zem = self.context.dmd.ZenEventManager
    189
    190          devdata = []
    191          for uuid in deviceSeverities.keys():
    192              dev = manager.getObject(uuid)
    193              if dev and isinstance(dev, Device):
    194                  if (not zem.checkRemotePerm(ZEN_VIEW, dev)
    195                      or dev.productionState < zem.prodStateDashboardThresh
    196                      or dev.priority < zem.priorityDashboardThresh):
    197                      continue
    198                  alink = dev.getPrettyLink()
    199                  try:
    200                      severities = deviceSeverities[uuid]
    201                      severities = dict((zep.getSeverityName(sev).lower(), counts) for (sev, counts) in severities.iteritems())
    202                      pill = getEventPillME(dev, severities=severities)
    203                  except ServiceException:
    204                      continue
    205                  evts = [alink,pill]
    206                  devdata.append((evts, severities))
    207          devdata.sort(key=lambda x:(x[1]['critical'], x[1]['error'], x[1]['warning']), reverse=True)
    208          return [x[0] for x in devdata[:100]]
    209
    210
    211  heartbeat_columns = ['Host', 'Daemon Process', 'Seconds Down']
    212
    213 -class HeartbeatPortletView(BrowserView):
    214      """
    215      Heartbeat issues in YUI table form, for the dashboard portlet
    216      """
    217      @nocache
    218 -    def __call__(self):
    219          return self.getHeartbeatIssuesJSON()
    220
    221      @zepConnectionError({'columns': heartbeat_columns, 'data':[]})
    222      @json
    223 -    def getHeartbeatIssuesJSON(self):
    224          """
    225          Get heartbeat issues in a form suitable for a portlet on the dashboard.
    226
    227          @return: A JSON representation of a dictionary describing heartbeats
    228          @rtype: "{
    229              'columns':['Host', 'Daemon Process', 'Seconds Down'],
    230              'data':[
    231                  {'Device':'<a href=/>', 'Daemon':'zenhub', 'Seconds':10}
    232              ]}"
    233          """
    234          data = getHeartbeatObjects(deviceRoot=self.context.dmd.Devices,
    235                  keys=heartbeat_columns)
    236          return {'columns': heartbeat_columns, 'data': data}
    237
    238
    239 -class UserMessagesPortletView(BrowserView):
    240      """
    241      User messages in YUI table form, for the dashboard portlet.
    242      """
    243      @nocache
    244      @json
    245 -    def __call__(self):
    246          """
    247          Get heartbeat issues in a form suitable for a portlet on the dashboard.
    248
    249          @return: A JSON representation of a dictionary describing heartbeats
    250          @rtype: "{
    251              'columns':['Host', 'Daemon Process', 'Seconds Down'],
    252              'data':[
    253                  {'Device':'<a href=/>', 'Daemon':'zenhub', 'Seconds':10}
    254              ]}"
    255          """
    256          ICONS = ['/zport/dmd/img/agt_action_success-32.png',
    257                   '/zport/dmd/img/messagebox_warning-32.png',
    258                   '/zport/dmd/img/agt_stop-32.png']
    259          msgbox = messaging.IUserMessages(self.context)
    260          msgs = msgbox.get_messages()
    261          cols = ['Message']
    262          res = []
    263          for msg in msgs:
    264              res.append(dict(
    265                  title = msg.title,
    266                  imgpath = ICONS[msg.priority],
    267                  body = msg.body,
    268                  ago = relative_time(msg.timestamp),
    269                  deletelink = msg.absolute_url_path() + '/delMsg'
    270              ))
    271          res.reverse()
    272          return { 'columns': cols, 'data': res }
    273