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

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

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