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

# Source Code for Module Products.ZenModel.PerformanceConf

      1  #! /usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  # ##########################################################################
      4  #
      5  # This program is part of Zenoss Core, an open source monitoring platform.
      6  # Copyright (C) 2006-2009 Zenoss Inc.
      7  #
      8  # This program is free software; you can redistribute it and/or modify it
      9  # under the terms of the GNU General Public License version 2 as published by
     10  # the Free Software Foundation.
     11  #
     12  # For complete information please visit: http://www.zenoss.com/oss/
     13  #
     14  # ##########################################################################
     15
     16  __doc__ = """PerformanceConf
     17  The configuration object for Performance servers
     18  """
     19
     20  import os
     21  import zlib
     22  import socket
     23  import logging
     24  log = logging.getLogger('zen.PerformanceConf')
     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.PythonScripts.standard import url_quote
     58  from Products.ZenModel.ZenossSecurity import *
     59  from Products.ZenRelations.RelSchema import *
     60  from Products.ZenUtils.Utils import basicAuthUrl, zenPath, binPath
     61  from Products.ZenUtils.Utils import unused
     62  from Products.ZenUtils.Utils import isXmlRpc
     63  from Products.ZenUtils.Utils import setupLoggingHeader
     64  from Products.ZenUtils.Utils import executeCommand
     65  from Products.ZenUtils.Utils import clearWebLoggingStream
     66  from Products.ZenModel.Device import manage_createDevice
     67  from Products.ZenWidgets import messaging
     68  from StatusColor import StatusColor
     69
     70  PERF_ROOT = None
     71
     72
     73 -def performancePath(target):
     74      """
     75      Return the base directory where RRD performance files are kept.
     76
     77      @param target: path to performance file
     78      @type target: string
     79      @return: sanitized path to performance file
     80      @rtype: string
     81      """
     82      global PERF_ROOT
     83      if PERF_ROOT is None:
     84          PERF_ROOT = zenPath('perf')
     85      if target.startswith('/'):
     86          target = target[1:]
     87      return os.path.join(PERF_ROOT, target)
     88
     89
     90 -def manage_addPerformanceConf(context, id, title=None, REQUEST=None,):
     91      """
     92      Make a device class
     93
     94      @param context: Where you are in the Zope acquisition path
     95      @type context: Zope context object
     96      @param id: unique identifier
     97      @type id: string
     98      @param title: user readable label (unused)
     99      @type title: string
    100      @param REQUEST: Zope REQUEST object
    101      @type REQUEST: Zope REQUEST object
    102      @return:
    103      @rtype:
    104      """
    105      unused(title)
    106      dc = PerformanceConf(id)
    107      context._setObject(id, dc)
    108
    109      if REQUEST is not None:
    110          REQUEST['RESPONSE'].redirect(context.absolute_url()
    111                   + '/manage_main')
    112
    113
    114  addPerformanceConf = DTMLFile('dtml/addPerformanceConf', globals())
    115
    116
    117 -class PerformanceConf(Monitor, StatusColor):
    118      """
    119      Configuration for Performance servers
    120      """
    121      portal_type = meta_type = 'PerformanceConf'
    122
    123      monitorRootName = 'Performance'
    124
    125      security = ClassSecurityInfo()
    126      security.setDefaultAccess('allow')
    127
    128      eventlogCycleInterval = 60
    129      perfsnmpCycleInterval = 300
    130      processCycleInterval = 180
    131      statusCycleInterval = 60
    132      winCycleInterval = 60
    133      winmodelerCycleInterval = 60
    134      wmibatchSize = 10
    135      wmiqueryTimeout = 100
    136      configCycleInterval = 6 * 60
    137
    138      zenProcessParallelJobs = 10
    139
    140      pingTimeOut = 1.5
    141      pingTries = 2
    142      pingChunk = 75
    143      pingCycleInterval = 60
    144      maxPingFailures = 1440
    145
    146      modelerCycleInterval = 720
    147
    148      renderurl = '/zport/RenderServer'
    149      renderuser = ''
    150      renderpass = ''
    151
    152      discoveryNetworks = ()
    153
    154      # make the default rrdfile size smaller
    155      # we need the space to live within the disk cache
    156      defaultRRDCreateCommand = (
    157          'RRA:AVERAGE:0.5:1:600',   # every 5 mins for 2 days
    158          'RRA:AVERAGE:0.5:6:600',   # every 30 mins for 12 days
    159          'RRA:AVERAGE:0.5:24:600',  # every 2 hours for 50 days
    160          'RRA:AVERAGE:0.5:288:600', # every day for 600 days
    161          'RRA:MAX:0.5:6:600',
    162          'RRA:MAX:0.5:24:600',
    163          'RRA:MAX:0.5:288:600',
    164          )
    165
    166      _properties = (
    167          {'id': 'eventlogCycleInterval', 'type': 'int', 'mode': 'w'},
    168          {'id': 'perfsnmpCycleInterval', 'type': 'int', 'mode': 'w'},
    169          {'id': 'processCycleInterval', 'type': 'int', 'mode': 'w'},
    170          {'id': 'statusCycleInterval', 'type': 'int', 'mode': 'w'},
    171          {'id': 'winCycleInterval', 'type': 'int', 'mode': 'w'},
    172          {'id': 'winmodelerCycleInterval', 'type': 'int', 'mode': 'w'},
    173          {'id': 'wmibatchSize', 'type': 'int', 'mode': 'w',
    174           'description':"Number of data objects to retrieve in a single WMI query",},
    175          {'id': 'wmiqueryTimeout', 'type': 'int', 'mode': 'w',
    176           'description':"Number of milliseconds to wait for WMI query to respond",},
    177          {'id': 'configCycleInterval', 'type': 'int', 'mode': 'w'},
    178          {'id': 'renderurl', 'type': 'string', 'mode': 'w'},
    179          {'id': 'renderuser', 'type': 'string', 'mode': 'w'},
    180          {'id': 'renderpass', 'type': 'string', 'mode': 'w'},
    181          {'id': 'defaultRRDCreateCommand', 'type': 'lines', 'mode': 'w'
    182           },
    183          {'id': 'zenProcessParallelJobs', 'type': 'int', 'mode': 'w'},
    184          {'id': 'pingTimeOut', 'type': 'float', 'mode': 'w'},
    185          {'id': 'pingTries', 'type': 'int', 'mode': 'w'},
    186          {'id': 'pingChunk', 'type': 'int', 'mode': 'w'},
    187          {'id': 'pingCycleInterval', 'type': 'int', 'mode': 'w'},
    188          {'id': 'maxPingFailures', 'type': 'int', 'mode': 'w'},
    189          {'id': 'modelerCycleInterval', 'type': 'int', 'mode': 'w'},
    190          {'id': 'discoveryNetworks', 'type': 'lines', 'mode': 'w'},
    191          )
    192
    193      _relations = Monitor._relations + (
    194          ("devices", ToMany(ToOne,"Products.ZenModel.Device","perfServer")),
    195          )
    196
    197      # Screen action bindings (and tab definitions)
    198      factory_type_information = (
    199          {
    200              'immediate_view' : 'viewPerformanceConfOverview',
    201              'actions'        :
    202              (
    203                  { 'id'            : 'overview'
    204                  , 'name'          : 'Overview'
    205                  , 'action'        : 'viewPerformanceConfOverview'
    206                  , 'permissions'   : (
    207                    permissions.view, )
    208                  },
    209                  { 'id'            : 'edit'
    210                  , 'name'          : 'Edit'
    211                  , 'action'        : 'editPerformanceConf'
    212                  , 'permissions'   : ("Manage DMD",)
    213                  },
    214                  { 'id'            : 'performance'
    215                  , 'name'          : 'Performance'
    216                  , 'action'        : 'viewDaemonPerformance'
    217                  , 'permissions'   : (permissions.view,)
    218                  },
    219                  { 'id'            : 'viewHistory'
    220                  , 'name'          : 'Modifications'
    221                  , 'action'        : 'viewHistory'
    222                  , 'permissions'   : (ZEN_VIEW_MODIFICATIONS,)
    223                  },
    224              )
    225            },
    226          )
    227
    228
    229      security.declareProtected('View', 'getDefaultRRDCreateCommand')
    230 -    def getDefaultRRDCreateCommand(self):
    231          """
    232          Get the default RRD Create Command, as a string.
    233          For example:
    234          '''RRA:AVERAGE:0.5:1:600
    235          RRA:AVERAGE:0.5:6:600
    236          RRA:AVERAGE:0.5:24:600
    237          RRA:AVERAGE:0.5:288:600
    238          RRA:MAX:0.5:288:600'''
    239
    240          @return: RRD create command
    241          @rtype: string
    242          """
    243          return '\n'.join(self.defaultRRDCreateCommand)
    244
    245
    246 -    def findDevice(self, deviceName):
    247          """
    248          Return the object given the name
    249
    250          @param deviceName: Name of a device
    251          @type deviceName: string
    252          @return: device corresponding to the name, or None
    253          @rtype: device object
    254          """
    255          brains = self.dmd.Devices._findDevice(deviceName)
    256          if brains:
    257              return brains[0].getObject()
    258
    259
    260 -    def getNetworkRoot(self):
    261          """
    262          Get the root of the Network object in the DMD
    263
    264          @return: base DMD Network object
    265          @rtype: Network object
    266          """
    267          return self.dmd.Networks
    268
    269
    270 -    def buildGraphUrlFromCommands(self, gopts, drange):
    271          """
    272          Return an URL for the given graph options and date range
    273
    274          @param gopts: graph options
    275          @type gopts: string
    276          @param drange: time range to use
    277          @type drange: string
    278          @return: URL to a graphic
    279          @rtype: string
    280          """
    281          newOpts = []
    282          width = 0
    283          for o in gopts:
    284              if o.startswith('--width'):
    285                  width = o.split('=')[1].strip()
    286                  continue
    287              newOpts.append(o)
    288          encodedOpts = urlsafe_b64encode(
    289                           zlib.compress('|'.join(newOpts), 9))
    290          url = '%s/render?gopts=%s&drange=%d&width=%s' % (
    291                   self.renderurl, encodedOpts, drange, width)
    292          if self.renderurl.startswith('proxy'):
    293              url = url.replace('proxy', 'http')
    294              return '/zport/RenderServer/render?remoteUrl=%s&gopts=%s&drange=%d&width=%s' % (
    295                   url_quote(url), encodedOpts, drange, width)
    296          else:
    297              return url
    298
    299
    300 -    def performanceGraphUrl(self, context, targetpath, targettype, view, drange):
    301          """
    302          Set the full path of the target and send to view
    303
    304          @param context: Where you are in the Zope acquisition path
    305          @type context: Zope context object
    306          @param targetpath: device path of performance metric
    307          @type targetpath: string
    308          @param targettype: unused
    309          @type targettype: string
    310          @param view: view object
    311          @type view: Zope object
    312          @param drange: date range
    313          @type drange: string
    314          @return: URL to graph
    315          @rtype: string
    316          """
    317          unused(targettype)
    318          targetpath = performancePath(targetpath)
    319          gopts = view.getGraphCmds(context, targetpath)
    320          return self.buildGraphUrlFromCommands(gopts, drange)
    321
    322
    323 -    def performanceMGraphUrl(self, context, targetsmap, view, drange):
    324          """
    325          Set the full paths for all targts in map and send to view
    326
    327          @param context: Where you are in the Zope acquisition path
    328          @type context: Zope context object
    329          @param targetsmap: list of (target, targettype) tuples
    330          @type targetsmap: list
    331          @param view: view object
    332          @type view: Zope object
    333          @param drange: date range
    334          @type drange: string
    335          @return: URL to graph
    336          @rtype: string
    337          """
    338          ntm = []
    339          for (target, targettype) in targetsmap:
    340              if target.find('.rrd') == -1:
    341                  target += '.rrd'
    342              fulltarget = performancePath(target)
    343              ntm.append((fulltarget, targettype))
    344          gopts = view.multiGraphOpts(context, ntm)
    345          gopts = url_quote('|'.join(gopts))
    346          url = '%s/render?gopts=%s&drange=%d' % (self.renderurl, gopts, drange)
    347          if self.renderurl.startswith('http'):
    348              return '/zport/RenderServer/render?remoteUrl=%s&gopts=%s&drange=%d' % (
    349                   url_quote(url), gopts, drange)
    350          else:
    351              return url
    352
    353
    354 -    def renderCustomUrl(self, gopts, drange):
    355          """
    356          Return the URL for a list of custom gopts for a graph
    357
    358          @param gopts: graph options
    359          @type gopts: string
    360          @param drange: date range
    361          @type drange: string
    362          @return: URL to graph
    363          @rtype: string
    364          """
    365          gopts = self._fullPerformancePath(gopts)
    366          gopts = url_quote('|'.join(gopts))
    367          url = '%s/render?gopts=%s&drange=%d' % (self.renderurl, gopts,
    368                  drange)
    369          if self.renderurl.startswith('http'):
    370              return '/zport/RenderServer/render?remoteUrl=%s&gopts=%s&drange=%d'\
    371                   % (url_quote(url), gopts, drange)
    372          else:
    373              return url
    374
    375
    376 -    def performanceCustomSummary(self, gopts):
    377          """
    378          Fill out full path for custom gopts and call to server
    379
    380          @param gopts: graph options
    381          @type gopts: string
    382          @return: URL
    383          @rtype: string
    384          """
    385          gopts = self._fullPerformancePath(gopts)
    386          renderurl = str(self.renderurl)
    387          if renderurl.startswith('proxy'):
    388              renderurl = self.renderurl.replace('proxy', 'http')
    389          if renderurl.startswith('http'):
    390              url = basicAuthUrl(str(self.renderuser),
    391                                 str(self.renderpass), renderurl)
    392              server = xmlrpclib.Server(url)
    393          else:
    394              server = self.getObjByPath(renderurl)
    395          return server.summary(gopts)
    396
    397
    398 -    def fetchValues(self, paths, cf, resolution, start, end=""):
    399          """
    400          Return values
    401
    402          @param paths: paths to performance metrics
    403          @type paths: list
    404          @param cf: RRD CF
    405          @type cf: string
    406          @param resolution: resolution
    407          @type resolution: string
    408          @param start: start time
    409          @type start: string
    410          @param end: end time
    411          @type end: string
    412          @return: values
    413          @rtype: list
    414          """
    415          url = self.renderurl
    416          if url.startswith("http"):
    417              url = basicAuthUrl(self.renderuser, self.renderpass, self.renderurl)
    418              server = xmlrpclib.Server(url, allow_none=True)
    419          else:
    420              if not self.renderurl:
    421                  raise KeyError
    422              server = self.getObjByPath(self.renderurl)
    423          return server.fetchValues(map(performancePath, paths), cf,
    424                                    resolution, start, end)
    425
    426
    427 -    def currentValues(self, paths):
    428          """
    429          Fill out full path and call to server
    430
    431          @param paths: paths to performance metrics
    432          @type paths: list
    433          @return: values
    434          @rtype: list
    435          """
    436          url = self.renderurl
    437          if url.startswith('proxy'):
    438              url = self.renderurl.replace('proxy', 'http')
    439          if url.startswith('http'):
    440              url = basicAuthUrl(self.renderuser, self.renderpass,
    441                                 self.renderurl)
    442              server = xmlrpclib.Server(url)
    443          else:
    444              if not self.renderurl:
    445                  raise KeyError
    446              server = self.getObjByPath(self.renderurl)
    447          return server.currentValues(map(performancePath, paths))
    448
    449
    450 -    def _fullPerformancePath(self, gopts):
    451          """
    452          Add full path to a list of custom graph options
    453
    454          @param gopts: graph options
    455          @type gopts: string
    456          @return: full path + graph options
    457          @rtype: string
    458          """
    459          for i in range(len(gopts)):
    460              opt = gopts[i]
    461              if opt.find('DEF') == 0:
    462                  opt = opt.split(':')
    463                  (var, file) = opt[1].split('=')
    464                  file = performancePath(file)
    465                  opt[1] = '%s=%s' % (var, file)
    466                  opt = ':'.join(opt)
    467                  gopts[i] = opt
    468          return gopts
    469
    470
    471      security.declareProtected('View', 'performanceDeviceList')
    472 -    def performanceDeviceList(self, force=True):
    473          """
    474          Return a list of URLs that point to our managed devices
    475
    476          @param force: unused
    477          @type force: boolean
    478          @return: list of device objects
    479          @rtype: list
    480          """
    481          unused(force)
    482          devlist = []
    483          for dev in self.devices():
    484              dev = dev.primaryAq()
    485              if not dev.pastSnmpMaxFailures() and dev.monitorDevice():
    486                  devlist.append(dev.getPrimaryUrlPath(full=True))
    487          return devlist
    488
    489
    490      security.declareProtected('View', 'performanceDataSources')
    491 -    def performanceDataSources(self):
    492          """
    493          Return a string that has all the definitions for the performance DS's.
    494
    495          @return: list of Data Sources
    496          @rtype: string
    497          """
    498          dses = []
    499          oidtmpl = 'OID %s %s'
    500          dstmpl = """datasource %s
    501          rrd-ds-type = %s
    502          ds-source = snmp://%%snmp%%/%s%s
    503          """
    504          rrdconfig = self.getDmdRoot('Devices').rrdconfig
    505          for ds in rrdconfig.objectValues(spec='RRDDataSource'):
    506              if ds.isrow:
    507                  inst = '.%inst%'
    508              else:
    509                  inst = ''
    510              dses.append(oidtmpl % (ds.getName(), ds.oid))
    511              dses.append(dstmpl % (ds.getName(), ds.rrdtype,
    512                          ds.getName(), inst))
    513          return '\n'.join(dses)
    514
    515 -    def deleteRRDFiles(self, device, datasource=None, datapoint=None):
    516          """
    517          Remove RRD performance data files
    518
    519          @param device: Name of a device or entry in DMD
    520          @type device: string
    521          @param datasource: datasource name
    522          @type datasource: string
    523          @param datapoint: datapoint name
    524          @type datapoint: string
    525          """
    526          remoteUrl = None
    527          if self.renderurl.startswith('http'):
    528              if datapoint:
    529                  remoteUrl = '%s/deleteRRDFiles?device=%s&datapoint=%s' % (
    530                       self.renderurl, device, datapoint)
    531              elif datasource:
    532                  remoteUrl = '%s/deleteRRDFiles?device=%s&datasource=%s' % (
    533                       self.renderurl, device, datasource)
    534              else:
    535                  remoteUrl = '%s/deleteRRDFiles?device=%s' % (
    536                       self.renderurl, device)
    537          rs = self.getDmd().getParentNode().RenderServer
    538          rs.deleteRRDFiles(device, datasource, datapoint, remoteUrl)
    539
    540
    541 -    def setPerformanceMonitor(self, performanceMonitor=None, deviceNames=None, REQUEST=None):
    542          """
    543          Provide a method to set performance monitor from any organizer
    544
    545          @param performanceMonitor: DMD object that collects from a device
    546          @type performanceMonitor: DMD object
    547          @param deviceNames: list of device names
    548          @type deviceNames: list
    549          @param REQUEST: Zope REQUEST object
    550          @type REQUEST: Zope REQUEST object
    551          """
    552          if not performanceMonitor:
    553              if REQUEST:
    554                  messaging.IMessageSender(self).sendToBrowser('Error',
    555                          'No monitor was selected.',
    556                          priority=messaging.WARNING)
    557              return self.callZenScreen(REQUEST)
    558          if deviceNames is None:
    559              if REQUEST:
    560                  messaging.IMessageSender(self).sendToBrowser('Error',
    561                          'No devices were selected.',
    562                          priority=messaging.WARNING)
    563              return self.callZenScreen(REQUEST)
    564          for devName in deviceNames:
    565              dev = self.devices._getOb(devName)
    566              dev = dev.primaryAq()
    567              dev.setPerformanceMonitor(performanceMonitor)
    568          if REQUEST:
    569              messaging.IMessageSender(self).sendToBrowser('Monitor Set',
    570                      'Performance monitor was set to %s.'
    571                       % performanceMonitor)
    572              if REQUEST.has_key('oneKeyValueSoInstanceIsntEmptyAndEvalToFalse'):
    573                  return REQUEST['message']
    574              else:
    575                  return self.callZenScreen(REQUEST)
    576
    577
    578      security.declareProtected('View', 'getPingDevices')
    579 -    def getPingDevices(self):
    580          """
    581          Return devices associated with this monitor configuration.
    582
    583          @return: list of devices for this monitor
    584          @rtype: list
    585          """
    586          devices = []
    587          for dev in self.devices.objectValuesAll():
    588              dev = dev.primaryAq()
    589              if dev.monitorDevice() and not dev.zPingMonitorIgnore:
    590                  devices.append(dev)
    591          return devices
    592
    593 -    def _executeZenDiscCommand(self, deviceName, devicePath= "/Discovered",
    594                        performanceMonitor="localhost", discoverProto="snmp",
    595                        zSnmpPort=161,zSnmpCommunity="", REQUEST=None):
    596          """
    597          Execute zendisc on the new device and return result
    598
    599          @param deviceName: Name of a device
    600          @type deviceName: string
    601          @param devicePath: DMD path to create the new device in
    602          @type devicePath: string
    603          @param performanceMonitor: DMD object that collects from a device
    604          @type performanceMonitor: DMD object
    605          @param discoverProto: auto or none
    606          @type discoverProto: string
    607          @param zSnmpPort: zSnmpPort
    608          @type zSnmpPort: string
    609          @param zSnmpCommunity: SNMP community string
    610          @type zSnmpCommunity: string
    611          @param REQUEST: Zope REQUEST object
    612          @type REQUEST: Zope REQUEST object
    613          @return:
    614          @rtype:
    615          """
    616          zm = binPath('zendisc')
    617          zendiscCmd = [zm]
    618          zendiscOptions = ['run', '--now','-d', deviceName,
    619                       '--monitor', performanceMonitor,
    620                       '--deviceclass', devicePath]
    621          if REQUEST:
    622              zendiscOptions.append("--weblog")
    623          zendiscCmd.extend(zendiscOptions)
    624          result = executeCommand(zendiscCmd, REQUEST)
    625          return result
    626
    627 -    def executeCollectorCommand(self, command, args, REQUEST=None):
    628          """
    629          Executes the collector based daemon command.
    630
    631          @param command: the collector daemon to run, should not include path
    632          @type command: string
    633          @param args: list of arguments for the command
    634          @type args: list of strings
    635          @param REQUEST: Zope REQUEST object
    636          @type REQUEST: Zope REQUEST object
    637          @return: result of the command
    638          @rtype: string
    639          """
    640          cmd = binPath(command)
    641          daemonCmd = [cmd]
    642          daemonCmd.extend(args)
    643          result = executeCommand(daemonCmd, REQUEST)
    644          return result
    645
    646
    647 -    def collectDevice(self, device=None, setlog=True, REQUEST=None,
    648          generateEvents=False):
    649          """
    650          Collect the configuration of this device AKA Model Device
    651
    652          @permission: ZEN_MANAGE_DEVICE
    653          @param device: Name of a device or entry in DMD
    654          @type device: string
    655          @param setlog: If true, set up the output log of this process
    656          @type setlog: boolean
    657          @param REQUEST: Zope REQUEST object
    658          @type REQUEST: Zope REQUEST object
    659          @param generateEvents: unused
    660          @type generateEvents: string
    661          """
    662          xmlrpc = isXmlRpc(REQUEST)
    663          if setlog and REQUEST and not xmlrpc:
    664              handler = setupLoggingHeader(device, REQUEST)
    665
    666          zenmodelerOpts = ['run', '--now', '--monitor', self.id, '-F', '-d', device.id]
    667          if REQUEST:
    668              zenmodelerOpts.append('--weblog')
    669          result = self._executeZenModelerCommand(zenmodelerOpts, REQUEST)
    670          if result and xmlrpc:
    671              return result
    672          log.info('configuration collected')
    673
    674          if setlog and REQUEST and not xmlrpc:
    675              clearWebLoggingStream(handler)
    676
    677          if xmlrpc:
    678              return 0
    679
    680 -    def _executeZenModelerCommand(self, zenmodelerOpts, REQUEST=None):
    681          """
    682          Execute zenmodeler and return result
    683
    684          @param zenmodelerOpts: zenmodeler command-line options
    685          @type zenmodelerOpts: string
    686          @param REQUEST: Zope REQUEST object
    687          @type REQUEST: Zope REQUEST object
    688          @return: results of command
    689          @rtype: string
    690          """
    691          zm = binPath('zenmodeler')
    692          zenmodelerCmd = [zm]
    693          zenmodelerCmd.extend(zenmodelerOpts)
    694          result = executeCommand(zenmodelerCmd, REQUEST)
    695          return result
    696
    697
    698  InitializeClass(PerformanceConf)
    699