Package Products :: Package ZenHub :: Package services :: Module RenderConfig |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenHub.services.RenderConfig

      1  ##############################################################################
      2  #
      3  # Copyright (C) Zenoss, Inc. 2009, 2011, 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  """RenderConfig
     12
     13  zenhub service to start looking for requests to render performance graphs.
     14  """
     15
     16  from Products.ZenUtils.Utils import ipv6_available
     17
     18  import logging
     19  log = logging.getLogger('zen.HubService.RenderConfig')
     20
     21  import Globals
     22  from Products.ZenCollector.services.config import NullConfigService
     23  from Products.ZenRRD.zenrender import RenderServer
     24
     25  from twisted.web import resource, server
     26  from twisted.internet import reactor
     27  from twisted.internet.error import CannotListenError
     28  import socket
     29  import xmlrpclib, mimetypes
     30
     31  # Global variable
     32  htmlResource = None
     33
     34
     35 -class Render(resource.Resource):
     36
     37      isLeaf = True
     38
     39 -    def __init__(self):
     40          resource.Resource.__init__(self)
     41          self.renderers = {}
     42
     43 -    def render_GET(self, request):
     44          "Deal with http requests"
     45          args = request.args.copy()
     46          for k, v in args.items():
     47              if len(v) == 1:
     48                  args[k] = v[0]
     49
     50          command = request.postpath[-1]
     51          if command in ('favicon.ico',):
     52              log.debug("Received a bad request: %s", command)
     53              return ''
     54          from Products.ZenHub import ZENHUB_ZENRENDER
     55          if len(request.postpath) > 1:
     56              listener = request.postpath[-2]
     57          else:
     58              listener = ZENHUB_ZENRENDER
     59          args.setdefault('ftype', 'PNG')
     60          ftype = args['ftype']
     61          del args['ftype']
     62          mimetype = mimetypes.guess_type('x.%s' % ftype)[0]
     63          if mimetype is None:
     64              mimetype = 'image/%s' % ftype.lower()
     65          request.setHeader('Content-type', mimetype)
     66          def write(result):
     67              if result:
     68                  request.write(result)
     69              request.finish()
     70          def error(reason):
     71              log.error("Unable to fetch graph: %s", reason)
     72              request.finish()
     73          renderer = self.renderers.get(listener, False)
     74          if renderer and listener == ZENHUB_ZENRENDER:
     75              try:
     76                  rs = RenderServer(listener)
     77                  renderFn = getattr(rs,command)
     78                  result = renderFn(**args)
     79                  reactor.callLater(0,write, result)
     80              except Exception as e:
     81                  log.exception("Exception getting graph")
     82                  reactor.callLater(0,error, e.msg)
     83          else:
     84              if not renderer or not renderer.listeners:
     85                  raise Exception("Renderer %s unavailable" % listener)
     86              d = renderer.listeners[0].callRemote(command, **args)
     87              d.addCallbacks(write, error)
     88          return server.NOT_DONE_YET
     89
     90 -    def render_POST(self, request):
     91          "Deal with XML-RPC requests"
     92          content = request.content.read()
     93          for instance, renderer in self.renderers.items():
     94              if instance != request.postpath[-1]: continue
     95              for listener in renderer.listeners:
     96                  try:
     97                      args, command = xmlrpclib.loads(content)
     98                      request.setHeader('Content-type', 'text/xml')
     99                      d = listener.callRemote(str(command), *args)
    100                      def write(result):
    101                          try:
    102                              response = xmlrpclib.dumps((result,),
    103                                                         methodresponse=True,
    104                                                         allow_none=True)
    105                              request.write(response)
    106                          except Exception, ex:
    107                              log.error("Unable to %s: %s", command, ex)
    108                          request.finish()
    109                      def error(reason):
    110                          log.error("Unable to %s: %s", command, reason)
    111                          request.finish()
    112                      d.addCallbacks(write, error)
    113                      return server.NOT_DONE_YET
    114                  except Exception, ex:
    115                      log.exception(ex)
    116                      log.warning("Skipping renderer %s" % instance)
    117          raise Exception("No renderer registered")
    118
    119 -    def getChild(self, unused, ignored):
    120          "Handle all paths"
    121          return self, ()
    122
    123 -    def addRenderer(self, renderer):
    124          self.renderers[renderer.instance] = renderer
    125
    126
    127 -class RenderConfig(NullConfigService):
    128 -    def __init__(self, dmd, instance):
    129          from Products.ZenHub import ZENHUB_ZENRENDER
    130          if instance == ZENHUB_ZENRENDER:
    131              self.dmd = dmd
    132              self.instance = instance
    133          else:
    134              NullConfigService.__init__(self, dmd, instance)
    135
    136          global htmlResource
    137          try:
    138              if not htmlResource:
    139                  htmlResource = Render()
    140                  log.info("Starting graph retrieval listener on port 8090")
    141                  interface = '::' if ipv6_available() else ''
    142                  reactor.listenTCP(8090, server.Site(htmlResource), interface=interface)
    143              htmlResource.addRenderer(self)
    144          except CannotListenError, e:
    145              # Probably in a hub worker; no big deal
    146              log.debug("Not starting render listener because the port is "
    147                        "already in use.")
    148