Package Products :: Package ZenModel :: Module PerformanceConf |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenModel.PerformanceConf

      1  #! /usr/bin/env python
      2  ##############################################################################
      3  #
      4  # Copyright (C) Zenoss, Inc. 2006-2009, all rights reserved.
      5  #
      6  # This content is made available according to terms specified in
      7  # License.zenoss under the directory where your Zenoss product is installed.
      8  #
      9  ##############################################################################
     10
     11
     12  __doc__ = """PerformanceConf
     13  The configuration object for Performance servers
     14  """
     15
     16  import os
     17  import zlib
     18  import socket
     19  from urllib import urlencode
     20  from ipaddr import IPAddress
     21  import logging
     22  log = logging.getLogger('zen.PerformanceConf')
     23
     24  from Products.ZenUtils.IpUtil import ipwrap
     25
     26  try:
     27      from base64 import urlsafe_b64encode
     28      raise ImportError
     29  except ImportError:
     30
     31
     32 -    def urlsafe_b64encode(s):
     33          """
     34          Encode a string so that it's okay to be used in an URL
     35
     36          @param s: possibly unsafe string passed in by the user
     37          @type s: string
     38          @return: sanitized, url-safe version of the string
     39          @rtype: string
     40          """
     41
     42          import base64
     43          s = base64.encodestring(s)
     44          s = s.replace('+', '-')
     45          s = s.replace('/', '_')
     46          s = s.replace('\n', '')
     47          return s
     48
     49
     50  import xmlrpclib
     51
     52  from AccessControl import ClassSecurityInfo
     53  from AccessControl import Permissions as permissions
     54  from Globals import DTMLFile
     55  from Globals import InitializeClass
     56  from Monitor import Monitor
     57  from Products.Jobber.jobs import SubprocessJob
     58  from Products.ZenRelations.RelSchema import ToMany, ToOne
     59  from Products.ZenUtils.Utils import basicAuthUrl, zenPath, binPath
     60  from Products.ZenUtils.Utils import unused
     61  from Products.ZenUtils.Utils import isXmlRpc
     62  from Products.ZenUtils.Utils import executeCommand
     63  from Products.ZenModel.ZDeviceLoader import DeviceCreationJob
     64  from Products.ZenWidgets import messaging
     65  from Products.ZenMessaging.audit import audit
     66  from StatusColor import StatusColor
     67
     68  PERF_ROOT = None
     69
     70  """
     71  Prefix for renderurl if zenoss is running a reverse proxy on the master. Prefix will be stripped when appropriate and
     72  requests for data will be made to the proxy server when appropriate.  Render url should be of the form "rev_proxy:/<path>" eg:
     73  "rev_proxy:/mypath" where /mypath should be proxied to an appropriate zenrender/renderserver by the installed proxy server
     74  """
     75  REVERSE_PROXY = "rev_proxy:"
     76
     77 -def performancePath(target):
     78      """
     79      Return the base directory where RRD performance files are kept.
     80
     81      @param target: path to performance file
     82      @type target: string
     83      @return: sanitized path to performance file
     84      @rtype: string
     85      """
     86      global PERF_ROOT
     87      if PERF_ROOT is None:
     88          PERF_ROOT = zenPath('perf')
     89      if target.startswith('/'):
     90          target = target[1:]
     91      return os.path.join(PERF_ROOT, target)
     92
     93
     94 -def manage_addPerformanceConf(context, id, title=None, REQUEST=None,):
     95      """
     96      Make a device class
     97
     98      @param context: Where you are in the Zope acquisition path
     99      @type context: Zope context object
    100      @param id: unique identifier
    101      @type id: string
    102      @param title: user readable label (unused)
    103      @type title: string
    104      @param REQUEST: Zope REQUEST object
    105      @type REQUEST: Zope REQUEST object
    106      @return:
    107      @rtype:
    108      """
    109      unused(title)
    110      dc = PerformanceConf(id)
    111      context._setObject(id, dc)
    112
    113      if REQUEST is not None:
    114          REQUEST['RESPONSE'].redirect(context.absolute_url()
    115                   + '/manage_main')
    116
    117
    118  addPerformanceConf = DTMLFile('dtml/addPerformanceConf', globals())
    119
    120
    121 -class PerformanceConf(Monitor, StatusColor):
    122      """
    123      Configuration for Performance servers
    124      """
    125      portal_type = meta_type = 'PerformanceConf'
    126
    127      monitorRootName = 'Performance'
    128
    129      security = ClassSecurityInfo()
    130      security.setDefaultAccess('allow')
    131
    132      eventlogCycleInterval = 60
    133      perfsnmpCycleInterval = 300
    134      processCycleInterval = 180
    135      statusCycleInterval = 60
    136      winCycleInterval = 60
    137      wmibatchSize = 10
    138      wmiqueryTimeout = 100
    139      configCycleInterval = 6 * 60
    140
    141      zenProcessParallelJobs = 10
    142
    143      pingTimeOut = 1.5
    144      pingTries = 2
    145      pingChunk = 75
    146      pingCycleInterval = 60
    147      maxPingFailures = 1440
    148
    149      modelerCycleInterval = 720
    150
    151      renderurl = '/zport/RenderServer'
    152      renderuser = ''
    153      renderpass = ''
    154
    155      discoveryNetworks = ()
    156
    157      # make the default rrdfile size smaller
    158      # we need the space to live within the disk cache
    159      defaultRRDCreateCommand = (
    160          'RRA:AVERAGE:0.5:1:600',   # every 5 mins for 2 days
    161          'RRA:AVERAGE:0.5:6:600',   # every 30 mins for 12 days
    162          'RRA:AVERAGE:0.5:24:600',  # every 2 hours for 50 days
    163          'RRA:AVERAGE:0.5:288:600', # every day for 600 days
    164          'RRA:MAX:0.5:6:600',
    165          'RRA:MAX:0.5:24:600',
    166          'RRA:MAX:0.5:288:600',
    167          )
    168
    169      _properties = (
    170          {'id': 'eventlogCycleInterval', 'type': 'int', 'mode': 'w'},
    171          {'id': 'perfsnmpCycleInterval', 'type': 'int', 'mode': 'w'},
    172          {'id': 'processCycleInterval', 'type': 'int', 'mode': 'w'},
    173          {'id': 'statusCycleInterval', 'type': 'int', 'mode': 'w'},
    174          {'id': 'winCycleInterval', 'type': 'int', 'mode': 'w'},
    175          {'id': 'wmibatchSize', 'type': 'int', 'mode': 'w',
    176           'description':"Number of data objects to retrieve in a single WMI query",},
    177          {'id': 'wmiqueryTimeout', 'type': 'int', 'mode': 'w',
    178           'description':"Number of milliseconds to wait for WMI query to respond",},
    179          {'id': 'configCycleInterval', 'type': 'int', 'mode': 'w'},
    180          {'id': 'renderurl', 'type': 'string', 'mode': 'w'},
    181          {'id': 'renderuser', 'type': 'string', 'mode': 'w'},
    182          {'id': 'renderpass', 'type': 'string', 'mode': 'w'},
    183          {'id': 'defaultRRDCreateCommand', 'type': 'lines', 'mode': 'w'
    184           },
    185          {'id': 'zenProcessParallelJobs', 'type': 'int', 'mode': 'w'},
    186          {'id': 'pingTimeOut', 'type': 'float', 'mode': 'w'},
    187          {'id': 'pingTries', 'type': 'int', 'mode': 'w'},
    188          {'id': 'pingChunk', 'type': 'int', 'mode': 'w'},
    189          {'id': 'pingCycleInterval', 'type': 'int', 'mode': 'w'},
    190          {'id': 'maxPingFailures', 'type': 'int', 'mode': 'w'},
    191          {'id': 'modelerCycleInterval', 'type': 'int', 'mode': 'w'},
    192          {'id': 'discoveryNetworks', 'type': 'lines', 'mode': 'w'},
    193          )
    194
    195      _relations = Monitor._relations + (
    196          ("devices", ToMany(ToOne,"Products.ZenModel.Device","perfServer")),
    197          )
    198
    199      # Screen action bindings (and tab definitions)
    200      factory_type_information = (
    201          {
    202              'immediate_view' : 'viewPerformanceConfOverview',
    203              'actions'        :
    204              (
    205                  { 'id'            : 'overview'
    206                  , 'name'          : 'Overview'
    207                  , 'action'        : 'viewPerformanceConfOverview'
    208                  , 'permissions'   : (
    209                    permissions.view, )
    210                  },
    211                  { 'id'            : 'edit'
    212                  , 'name'          : 'Edit'
    213                  , 'action'        : 'editPerformanceConf'
    214                  , 'permissions'   : ("Manage DMD",)
    215                  },
    216                  { 'id'            : 'performance'
    217                  , 'name'          : 'Performance'
    218                  , 'action'        : 'viewDaemonPerformance'
    219                  , 'permissions'   : (permissions.view,)
    220                  },
    221              )
    222            },
    223          )
    224
    225
    226      security.declareProtected('View', 'getDefaultRRDCreateCommand')
    227 -    def getDefaultRRDCreateCommand(self):
    228          """
    229          Get the default RRD Create Command, as a string.
    230          For example:
    231          '''RRA:AVERAGE:0.5:1:600
    232          RRA:AVERAGE:0.5:6:600
    233          RRA:AVERAGE:0.5:24:600
    234          RRA:AVERAGE:0.5:288:600
    235          RRA:MAX:0.5:288:600'''
    236
    237          @return: RRD create command
    238          @rtype: string
    239          """
    240          return '\n'.join(self.defaultRRDCreateCommand)
    241
    242
    243 -    def findDevice(self, deviceName):
    244          """
    245          Return the object given the name
    246
    247          @param deviceName: Name of a device
    248          @type deviceName: string
    249          @return: device corresponding to the name, or None
    250          @rtype: device object
    251          """
    252          brains = self.dmd.Devices._findDevice(deviceName)
    253          if brains:
    254              return brains[0].getObject()
    255
    256
    257 -    def getNetworkRoot(self, version=None):
    258          """
    259          Get the root of the Network object in the DMD
    260
    261          @return: base DMD Network object
    262          @rtype: Network object
    263          """
    264          return self.dmd.Networks.getNetworkRoot(version)
    265
    266
    267 -    def buildGraphUrlFromCommands(self, gopts, drange):
    268          """
    269          Return an URL for the given graph options and date range
    270
    271          @param gopts: graph options
    272          @type gopts: string
    273          @param drange: time range to use
    274          @type drange: string
    275          @return: URL to a graphic
    276          @rtype: string
    277          """
    278          newOpts = []
    279          width = 0
    280          for o in gopts:
    281              if o.startswith('--width'):
    282                  width = o.split('=')[1].strip()
    283                  continue
    284              newOpts.append(o)
    285
    286          encodedOpts = urlsafe_b64encode(
    287              zlib.compress('|'.join(newOpts), 9))
    288          params = {
    289              'gopts': encodedOpts,
    290              'drange': drange,
    291              'width': width,
    292              }
    293
    294          url = self._getSanitizedRenderURL()
    295          if RenderURLUtil(self.renderurl).proxiedByZenoss():
    296              params['remoteHost'] = self.getRemoteRenderUrl()
    297              url = '/zport/RenderServer'
    298
    299          url = '%s/render?%s' % (url, urlencode(params),)
    300          return url
    301
    302 -    def _getSanitizedRenderURL(self):
    303          """
    304          remove any keywords/directives from renderurl.
    305          example is "proxy://host:8091" is changed to "http://host:8091"
    306          """
    307          return RenderURLUtil(self.renderurl).getSanitizedRenderURL()
    308
    309 -    def performanceGraphUrl(self, context, targetpath, targettype, view, drange):
    310          """
    311          Set the full path of the target and send to view
    312
    313          @param context: Where you are in the Zope acquisition path
    314          @type context: Zope context object
    315          @param targetpath: device path of performance metric
    316          @type targetpath: string
    317          @param targettype: unused
    318          @type targettype: string
    319          @param view: view object
    320          @type view: Zope object
    321          @param drange: date range
    322          @type drange: string
    323          @return: URL to graph
    324          @rtype: string
    325          """
    326          unused(targettype)
    327          targetpath = performancePath(targetpath)
    328          gopts = view.getGraphCmds(context, targetpath)
    329          return self.buildGraphUrlFromCommands(gopts, drange)
    330
    331
    332 -    def getRemoteRenderUrl(self):
    333          """
    334          return the full render url with http protocol prepended if the renderserver is remote.
    335          Return empty string otherwise
    336          """
    337          return RenderURLUtil(self.renderurl).getRemoteRenderUrl()
    338
    339 -    def _get_render_server(self, allow_none=False):
    340          if self.getRemoteRenderUrl():
    341              renderurl = self.getRemoteRenderUrl()
    342              # Going through the hub or directly to zenrender
    343              log.info("Remote renderserver at %s", renderurl)
    344              url = basicAuthUrl(str(self.renderuser),
    345                                 str(self.renderpass), renderurl)
    346              server = xmlrpclib.Server(url, allow_none=allow_none)
    347          else:
    348              if not self.renderurl:
    349                  raise KeyError("No render URL is defined")
    350              server = self.getObjByPath(self.renderurl)
    351          return server
    352
    353 -    def performanceCustomSummary(self, gopts):
    354          """
    355          Fill out full path for custom gopts and call to server
    356
    357          @param gopts: graph options
    358          @type gopts: string
    359          @return: URL
    360          @rtype: string
    361          """
    362          gopts = self._fullPerformancePath(gopts)
    363          server = self._get_render_server()
    364          return server.summary(gopts)
    365
    366 -    def fetchValues(self, paths, cf, resolution, start, end=""):
    367          """
    368          Return values
    369
    370          @param paths: paths to performance metrics
    371          @type paths: list
    372          @param cf: RRD CF
    373          @type cf: string
    374          @param resolution: resolution
    375          @type resolution: string
    376          @param start: start time
    377          @type start: string
    378          @param end: end time
    379          @type end: string
    380          @return: values
    381          @rtype: list
    382          """
    383          server = self._get_render_server(allow_none=True)
    384          return server.fetchValues(map(performancePath, paths), cf,
    385                                    resolution, start, end)
    386
    387
    388 -    def currentValues(self, paths):
    389          """
    390          Fill out full path and call to server
    391
    392          @param paths: paths to performance metrics
    393          @type paths: list
    394          @return: values
    395          @rtype: list
    396          """
    397          server = self._get_render_server()
    398          return server.currentValues(map(performancePath, paths))
    399
    400
    401 -    def _fullPerformancePath(self, gopts):
    402          """
    403          Add full path to a list of custom graph options
    404
    405          @param gopts: graph options
    406          @type gopts: string
    407          @return: full path + graph options
    408          @rtype: string
    409          """
    410          for i in range(len(gopts)):
    411              opt = gopts[i]
    412              if opt.find('DEF') == 0:
    413                  opt = opt.split(':')
    414                  (var, file) = opt[1].split('=')
    415                  file = performancePath(file)
    416                  opt[1] = '%s=%s' % (var, file)
    417                  opt = ':'.join(opt)
    418                  gopts[i] = opt
    419          return gopts
    420
    421
    422      security.declareProtected('View', 'performanceDeviceList')
    423 -    def performanceDeviceList(self, force=True):
    424          """
    425          Return a list of URLs that point to our managed devices
    426
    427          @param force: unused
    428          @type force: boolean
    429          @return: list of device objects
    430          @rtype: list
    431          """
    432          unused(force)
    433          devlist = []
    434          for dev in self.devices():
    435              dev = dev.primaryAq()
    436              if not dev.pastSnmpMaxFailures() and dev.monitorDevice():
    437                  devlist.append(dev.getPrimaryUrlPath(full=True))
    438          return devlist
    439
    440
    441      security.declareProtected('View', 'performanceDataSources')
    442 -    def performanceDataSources(self):
    443          """
    444          Return a string that has all the definitions for the performance DS's.
    445
    446          @return: list of Data Sources
    447          @rtype: string
    448          """
    449          dses = []
    450          oidtmpl = 'OID %s %s'
    451          dstmpl = """datasource %s
    452          rrd-ds-type = %s
    453          ds-source = snmp://%%snmp%%/%s%s
    454          """
    455          rrdconfig = self.getDmdRoot('Devices').rrdconfig
    456          for ds in rrdconfig.objectValues(spec='RRDDataSource'):
    457              if ds.isrow:
    458                  inst = '.%inst%'
    459              else:
    460                  inst = ''
    461              dses.append(oidtmpl % (ds.getName(), ds.oid))
    462              dses.append(dstmpl % (ds.getName(), ds.rrdtype,
    463                          ds.getName(), inst))
    464          return '\n'.join(dses)
    465
    466 -    def deleteRRDFiles(self, device, datasource=None, datapoint=None):
    467          """
    468          Remove RRD performance data files
    469
    470          @param device: Name of a device or entry in DMD
    471          @type device: string
    472          @param datasource: datasource name
    473          @type datasource: string
    474          @param datapoint: datapoint name
    475          @type datapoint: string
    476          """
    477          remoteUrl = None
    478          renderurl = self.getRemoteRenderUrl() or self._getSanitizedRenderURL()
    479          if renderurl.startswith('http'):
    480              if datapoint:
    481                  remoteUrl = '%s/deleteRRDFiles?device=%s&datapoint=%s' % (
    482                       renderurl, device, datapoint)
    483              elif datasource:
    484                  remoteUrl = '%s/deleteRRDFiles?device=%s&datasource=%s' % (
    485                       renderurl, device, datasource)
    486              else:
    487                  remoteUrl = '%s/deleteRRDFiles?device=%s' % (
    488                       renderurl, device)
    489          rs = self.getDmd().getParentNode().RenderServer
    490          rs.deleteRRDFiles(device, datasource, datapoint, remoteUrl)
    491
    492
    493 -    def setPerformanceMonitor(self, performanceMonitor=None, deviceNames=None, REQUEST=None):
    494          """
    495          Provide a method to set performance monitor from any organizer
    496
    497          @param performanceMonitor: DMD object that collects from a device
    498          @type performanceMonitor: DMD object
    499          @param deviceNames: list of device names
    500          @type deviceNames: list
    501          @param REQUEST: Zope REQUEST object
    502          @type REQUEST: Zope REQUEST object
    503          """
    504          if not performanceMonitor:
    505              if REQUEST:
    506                  messaging.IMessageSender(self).sendToBrowser('Error',
    507                          'No monitor was selected.',
    508                          priority=messaging.WARNING)
    509              return self.callZenScreen(REQUEST)
    510          if deviceNames is None:
    511              if REQUEST:
    512                  messaging.IMessageSender(self).sendToBrowser('Error',
    513                          'No devices were selected.',
    514                          priority=messaging.WARNING)
    515              return self.callZenScreen(REQUEST)
    516          for devName in deviceNames:
    517              dev = self.devices._getOb(devName)
    518              dev = dev.primaryAq()
    519              dev.setPerformanceMonitor(performanceMonitor)
    520              if REQUEST:
    521                  audit('UI.Device.ChangeCollector', dev, collector=performanceMonitor)
    522          if REQUEST:
    523              messaging.IMessageSender(self).sendToBrowser('Monitor Set',
    524                      'Performance monitor was set to %s.'
    525                       % performanceMonitor)
    526              if REQUEST.has_key('oneKeyValueSoInstanceIsntEmptyAndEvalToFalse'):
    527                  return REQUEST['message']
    528              else:
    529                  return self.callZenScreen(REQUEST)
    530
    531
    532      security.declareProtected('View', 'getPingDevices')
    533 -    def getPingDevices(self):
    534          """
    535          Return devices associated with this monitor configuration.
    536
    537          @return: list of devices for this monitor
    538          @rtype: list
    539          """
    540          devices = []
    541          for dev in self.devices.objectValuesAll():
    542              dev = dev.primaryAq()
    543              if dev.monitorDevice() and not dev.zPingMonitorIgnore:
    544                  devices.append(dev)
    545          return devices
    546
    547 -    def addDeviceCreationJob(self, deviceName, devicePath, title=None,
    548                               discoverProto="none", manageIp="",
    549                               performanceMonitor='localhost',
    550                               rackSlot=0, productionState=1000, comments="",
    551                               hwManufacturer="", hwProductName="",
    552                               osManufacturer="", osProductName="", priority = 3,
    553                               locationPath="", systemPaths=[], groupPaths=[],
    554                               tag="", serialNumber="", zProperties={}):
    555
    556          # Check to see if we got passed in an IPv6 address
    557          try:
    558              IPAddress(deviceName)
    559              if not title:
    560                  title = deviceName
    561              deviceName = ipwrap(deviceName)
    562          except ValueError:
    563              pass
    564
    565          zendiscCmd = self._getZenDiscCommand(deviceName, devicePath,
    566                                               performanceMonitor, productionState)
    567
    568          jobStatus = self.dmd.JobManager.addJob(DeviceCreationJob,
    569                  description="Add device %s" % deviceName,
    570                  kwargs=dict(
    571                      deviceName=deviceName,
    572                      devicePath=devicePath,
    573                      title=title,
    574                      discoverProto=discoverProto,
    575                      manageIp=manageIp,
    576                      performanceMonitor=performanceMonitor,
    577                      rackSlot=rackSlot,
    578                      productionState=productionState,
    579                      comments=comments,
    580                      hwManufacturer=hwManufacturer,
    581                      hwProductName=hwProductName,
    582                      osManufacturer=osManufacturer,
    583                      osProductName=osProductName,
    584                      priority=priority,
    585                      tag=tag,
    586                      serialNumber=serialNumber,
    587                      locationPath=locationPath,
    588                      systemPaths=systemPaths,
    589                      groupPaths=groupPaths,
    590                      zProperties=zProperties,
    591                      zendiscCmd=zendiscCmd))
    592          return jobStatus
    593
    594 -    def _executeZenDiscCommand(self, deviceName, devicePath= "/Discovered",
    595                                 performanceMonitor="localhost", productionState=1000,
    596                                 background=False, REQUEST=None):
    597          """
    598          Execute zendisc on the new device and return result
    599
    600          @param deviceName: Name of a device
    601          @type deviceName: string
    602          @param devicePath: DMD path to create the new device in
    603          @type devicePath: string
    604          @param performanceMonitor: DMD object that collects from a device
    605          @type performanceMonitor: DMD object
    606          @param background: should command be scheduled job?
    607          @type background: boolean
    608          @param REQUEST: Zope REQUEST object
    609          @type REQUEST: Zope REQUEST object
    610          @return:
    611          @rtype:
    612          """
    613          zendiscCmd = self._getZenDiscCommand(deviceName, devicePath,
    614                                               performanceMonitor,
    615                                               productionState, REQUEST)
    616          if background:
    617              log.info('queued job: %s', " ".join(zendiscCmd))
    618              result = self.dmd.JobManager.addJob(SubprocessJob,
    619                  description="Discover and model device %s" % deviceName,
    620                  args=(zendiscCmd,))
    621          else:
    622              result = executeCommand(zendiscCmd, REQUEST)
    623          return result
    624
    625 -    def _getZenDiscCommand(self, deviceName, devicePath,
    626                             performanceMonitor, productionState, REQUEST=None):
    627
    628          zm = binPath('zendisc')
    629          zendiscCmd = [zm]
    630          zendiscOptions = ['run', '--now','-d', deviceName,
    631                       '--monitor', performanceMonitor,
    632                       '--deviceclass', devicePath,
    633                       '--prod_state', str(productionState)]
    634          if REQUEST:
    635              zendiscOptions.append("--weblog")
    636          zendiscCmd.extend(zendiscOptions)
    637          log.info('local zendiscCmd is "%s"' % ' '.join(zendiscCmd))
    638          return zendiscCmd
    639
    640 -    def getCollectorCommand(self, command):
    641          return [binPath(command)]
    642
    643 -    def executeCollectorCommand(self, command, args, REQUEST=None):
    644          """
    645          Executes the collector based daemon command.
    646
    647          @param command: the collector daemon to run, should not include path
    648          @type command: string
    649          @param args: list of arguments for the command
    650          @type args: list of strings
    651          @param REQUEST: Zope REQUEST object
    652          @type REQUEST: Zope REQUEST object
    653          @return: result of the command
    654          @rtype: string
    655          """
    656          cmd = binPath(command)
    657          daemonCmd = [cmd]
    658          daemonCmd.extend(args)
    659          result = executeCommand(daemonCmd, REQUEST)
    660          return result
    661
    662
    663 -    def collectDevice(self, device=None, setlog=True, REQUEST=None,
    664          generateEvents=False, background=False, write=None):
    665          """
    666          Collect the configuration of this device AKA Model Device
    667
    668          @permission: ZEN_MANAGE_DEVICE
    669          @param device: Name of a device or entry in DMD
    670          @type device: string
    671          @param setlog: If true, set up the output log of this process
    672          @type setlog: boolean
    673          @param REQUEST: Zope REQUEST object
    674          @type REQUEST: Zope REQUEST object
    675          @param generateEvents: unused
    676          @type generateEvents: string
    677          """
    678          xmlrpc = isXmlRpc(REQUEST)
    679          zenmodelerOpts = ['run', '--now', '--monitor', self.id, '-d', device.id]
    680          result = self._executeZenModelerCommand(zenmodelerOpts, background,
    681                                                  REQUEST, write)
    682          if result and xmlrpc:
    683              return result
    684          log.info('configuration collected')
    685
    686          if xmlrpc:
    687              return 0
    688
    689
    690 -    def _executeZenModelerCommand(self, zenmodelerOpts, background=False,
    691                                    REQUEST=None, write=None):
    692          """
    693          Execute zenmodeler and return result
    694
    695          @param zenmodelerOpts: zenmodeler command-line options
    696          @type zenmodelerOpts: string
    697          @param REQUEST: Zope REQUEST object
    698          @type REQUEST: Zope REQUEST object
    699          @return: results of command
    700          @rtype: string
    701          """
    702          zm = binPath('zenmodeler')
    703          zenmodelerCmd = [zm]
    704          zenmodelerCmd.extend(zenmodelerOpts)
    705          if background:
    706              log.info('queued job: %s', " ".join(zenmodelerCmd))
    707              result = self.dmd.JobManager.addJob(SubprocessJob,
    708                  description="Run zenmodeler %s" % ' '.join(zenmodelerOpts),
    709                  args=(zenmodelerCmd,))
    710          else:
    711              result = executeCommand(zenmodelerCmd, REQUEST, write)
    712          return result
    713
    714 -class RenderURLUtil(object):
    715
    716 -    def __init__(self, renderurl):
    717          self._renderurl = renderurl
    718
    719 -    def getSanitizedRenderURL(self):
    720          """
    721          remove any keywords/directives from renderurl.
    722          example is "proxy://host:8091" is changed to "http://host:8091"
    723          """
    724          renderurl = self._renderurl
    725          if renderurl.startswith('proxy'):
    726              renderurl = renderurl.replace('proxy', 'http')
    727          elif renderurl.startswith(REVERSE_PROXY):
    728              renderurl = renderurl.replace(REVERSE_PROXY, '', 1)
    729          return renderurl
    730
    731 -    def getRemoteRenderUrl(self):
    732              """
    733              return the full render url with http protocol prepended if the renderserver is remote.
    734              Return empty string otherwise
    735              """
    736              renderurl = str(self._renderurl)
    737              if renderurl.startswith('proxy'):
    738                  renderurl = renderurl.replace('proxy', 'http')
    739              elif renderurl.startswith(REVERSE_PROXY):
    740                  renderurl =  self._get_reverseproxy_renderurl()
    741              else:
    742                  # lookup utilities from zenpacks
    743                  if renderurl.startswith('/remote-collector/'):
    744                      renderurl =  self._get_reverseproxy_renderurl(force=True)
    745
    746              if renderurl.lower().startswith('http://'):
    747                  return renderurl
    748              return ''
    749
    750 -    def proxiedByZenoss(self):
    751          """
    752          Should the render request be proxied by zenoss/zope
    753          """
    754          return self._renderurl.startswith('proxy')
    755
    756 -    def _get_reverseproxy_renderurl(self, force=False):
    757          # DistributedCollector + WebScale scenario
    758          renderurl = self._renderurl
    759          if not force and not renderurl.startswith(REVERSE_PROXY):
    760              raise Exception("Renderurl, %s, should start with %s to be proxied", renderurl, REVERSE_PROXY)
    761          kwargs = dict(fqdn=socket.getfqdn(),
    762                        port=self._get_reverseproxy_port(),
    763                        path=str(self.getSanitizedRenderURL()).strip("/") + "/")
    764          return 'http://{fqdn}:{port}/{path}'.format(**kwargs)
    765
    766 -    def _get_reverseproxy_port(self):
    767          use_ssl = False
    768          http_port = 8080
    769          ssl_port = 443
    770          conf_path = zenPath("etc", "zenwebserver.conf")
    771          if not os.path.exists(conf_path):
    772              return http_port
    773          with open(conf_path) as file_:
    774              for line in (l.strip() for l in file_):
    775                  if line and not line.startswith('#'):
    776                      key, val = line.split(' ', 1)
    777                      if key == "useSSL":
    778                          use_ssl = val.lower() == 'true'
    779                      elif key == "httpPort":
    780                          http_port = int(val.strip())
    781                      elif key == "sslPort":
    782                          ssl_port = int(val.strip())
    783          if use_ssl:
    784              return ssl_port
    785          return http_port
    786
    787  InitializeClass(PerformanceConf)
    788