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

Source Code for Module Products.ZenHub.services.CommandPerformanceConfig

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, 2010 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  __doc__ = '''CommandPerformanceConfig 
 15   
 16  Provides configuration to zencommand clients. 
 17  ''' 
 18  import logging 
 19  log = logging.getLogger('zen.HubService.CommandPerformanceConfig') 
 20  import traceback 
 21   
 22  import Globals 
 23  from ZODB.POSException import ConflictError 
 24   
 25  from Products.ZenCollector.services.config import CollectorConfigService 
 26  from Products.ZenRRD.zencommand import Cmd, DataPointConfig 
 27  from Products.DataCollector.Plugins import getParserLoader 
 28  from Products.ZenEvents.ZenEventClasses import Error, Clear, Cmd_Fail 
 29   
 30   
31 -class CommandPerformanceConfig(CollectorConfigService):
32 dsType = 'COMMAND' 33
34 - def __init__(self, dmd, instance):
35 deviceProxyAttributes = ('zCommandPort', 36 'zCommandUsername', 37 'zCommandPassword', 38 'zCommandLoginTimeout', 39 'zCommandCommandTimeout', 40 'zKeyPath', 41 'zSshConcurrentSessions', 42 ) 43 CollectorConfigService.__init__(self, dmd, instance, 44 deviceProxyAttributes)
45 46 # Use case: create a dummy device to act as a placeholder to execute commands 47 # So don't filter out devices that don't have IP addresses. 48
49 - def _getDsDatapoints(self, comp, ds, ploader, perfServer):
50 """ 51 Given a component a data source, gather its data points 52 """ 53 parser = ploader.create() 54 points = [] 55 component_name = ds.getComponent(comp) 56 basepath = comp.rrdPath() 57 for dp in ds.getRRDDataPoints(): 58 dpc = DataPointConfig() 59 dpc.id = dp.id 60 dpc.component = component_name 61 dpc.rrdPath = "/".join((basepath, dp.name())) 62 dpc.rrdType = dp.rrdtype 63 dpc.rrdCreateCommand = dp.getRRDCreateCommand(perfServer) 64 dpc.rrdMin = dp.rrdmin 65 dpc.rrdMax = dp.rrdmax 66 dpc.data = parser.dataForParser(comp, dp) 67 points.append(dpc) 68 69 return points
70
71 - def _getDsCycleTime(self, comp, templ, ds):
72 cycleTime = 300 73 try: 74 cycleTime = int(ds.cycletime) 75 except ValueError: 76 message = "Unable to convert the cycle time '%s' to an " \ 77 "integer for %s/%s on %s" \ 78 " -- setting to 300 seconds" % ( 79 ds.cycletime, templ.id, ds.id, comp.device().id) 80 log.error(message) 81 component = ds.getPrimaryUrlPath() 82 dedupid = "Unable to convert cycletime for %s" % component 83 self.sendEvent(dict( 84 device=comp.device().id, component=component, 85 eventClass='/Cmd', severity=Warning, summary=message, 86 dedupid=dedupid, 87 )) 88 return cycleTime
89
90 - def _safeGetComponentConfig(self, comp, device, perfServer, 91 commands, thresholds):
92 """ 93 Catchall wrapper for things not caught at previous levels 94 """ 95 if not comp.monitorDevice(): 96 return None 97 98 try: 99 threshs = self._getComponentConfig(comp, device, perfServer, commands) 100 if threshs: 101 thresholds.extend(threshs) 102 except ConflictError: raise 103 except Exception, ex: 104 msg = "Unable to process %s datasource(s) for device %s -- skipping" % ( 105 self.dsType, device.id) 106 log.exception(msg) 107 details = dict(traceback=traceback.format_exc(), 108 msg=msg) 109 self._sendCmdEvent(device.id, details)
110
111 - def _getComponentConfig(self, comp, device, perfServer, cmds):
112 for templ in comp.getRRDTemplates(): 113 for ds in templ.getRRDDataSources(self.dsType): 114 if not ds.enabled: 115 continue 116 117 # Ignore SSH datasources if no username set 118 useSsh = getattr(ds, 'usessh', False) 119 if useSsh and not device.zCommandUsername: 120 self._warnUsernameNotSet(device) 121 continue 122 123 parserName = getattr(ds, "parser", "Auto") 124 ploader = getParserLoader(self.dmd, parserName) 125 if ploader is None: 126 log.error("Could not load %s plugin", parserName) 127 continue 128 129 cmd = Cmd() 130 cmd.useSsh = useSsh 131 cmd.name = "%s/%s" % (templ.id, ds.id) 132 cmd.cycleTime = self._getDsCycleTime(comp, templ, ds) 133 cmd.component = ds.getComponent(comp) 134 cmd.eventClass = ds.eventClass 135 cmd.eventKey = ds.eventKey or ds.id 136 cmd.severity = ds.severity 137 cmd.parser = ploader 138 cmd.ds = ds.titleOrId() 139 cmd.points = self._getDsDatapoints(comp, ds, ploader, perfServer) 140 141 # If the datasource supports an environment dictionary, use it 142 cmd.env = getattr(ds, 'env', None) 143 144 try: 145 cmd.command = ds.getCommand(comp) 146 except ConflictError: raise 147 except Exception: # TALES error 148 msg = "TALES error for device %s datasource %s" % ( 149 device.id, ds.id) 150 details = dict( 151 msg=msg, 152 template=templ.id, 153 datasource=ds.id, 154 affected_device=device.id, 155 affected_component=comp.id, 156 resolution='Could not create a command to send to zencommand' \ 157 ' because TALES evaluation failed. The most likely' \ 158 ' cause is unescaped special characters in the command.' \ 159 ' eg $ or %') 160 # This error might occur many, many times 161 self._sendCmdEvent('localhost', details) 162 continue 163 164 self.enrich(cmd, templ, ds) 165 cmds.add(cmd) 166 167 return comp.getThresholdInstances(self.dsType)
168
169 - def enrich(self, cmd, template, ds):
170 """ 171 Hook routine available for subclassed services 172 """ 173 pass
174
175 - def _createDeviceProxy(self, device):
176 proxy = CollectorConfigService._createDeviceProxy(self, device) 177 178 proxy.configCycleInterval = self._prefs.perfsnmpCycleInterval 179 proxy.name = device.id 180 proxy.device = device.id 181 proxy.lastmodeltime = device.getLastChangeString() 182 proxy.lastChangeTime = float(device.getLastChange()) 183 184 # Only send one event per warning type 185 self._sentNoUsernameSetWarning = False 186 self._sentNoUsernameSetClear = False 187 188 perfServer = device.getPerformanceServer() 189 commands = set() 190 191 # First for the device.... 192 proxy.thresholds = [] 193 self._safeGetComponentConfig(device, device, perfServer, 194 commands, proxy.thresholds) 195 196 # And now for its components 197 for comp in device.getMonitoredComponents(collector='zencommand'): 198 self._safeGetComponentConfig(comp, device, perfServer, 199 commands, proxy.thresholds) 200 201 if commands: 202 proxy.datasources = list(commands) 203 return proxy 204 return None
205
206 - def _sendCmdEvent(self, name, details=None):
207 msg = 'zCommandUsername is not set so SSH-based commands will not run' 208 ev = dict( 209 device=name, 210 eventClass=Cmd_Fail, 211 eventKey='zCommandUsername', 212 severity=Error, 213 component='zencommand', 214 summary=msg, 215 ) 216 if details: 217 ev.update(details) 218 self.sendEvent(ev)
219
220 - def _warnUsernameNotSet(self, device):
221 """ 222 Warn that the username is not set for device and the SSH command cannot be 223 executed. 224 """ 225 if self._sentNoUsernameSetWarning: 226 return 227 228 msg = 'zCommandUsername is not set so SSH-based commands will not run' 229 name = device.titleOrId() 230 log.error('%s for %s', msg, name) 231 self._sendCmdEvent(name) 232 self._sentNoUsernameSetWarning = True
233
234 - def _clearUsernameNotSet(self, device):
235 if self._sentNoUsernameSetClear: 236 return 237 238 self._sendCmdEvent(device.titleOrId(), {'severity':Clear}) 239 self._sentNoUsernameSetClear = True
240 241 if __name__ == '__main__': 242 from Products.ZenHub.ServiceTester import ServiceTester 243 tester = ServiceTester(CommandPerformanceConfig)
244 - def printer(proxy):
245 print '\t'.join([ '', 'Name', 'Use SSH?', 'CycleTime', 246 'Component', 'Points']) 247 for cmd in sorted(proxy.datasources): 248 print '\t'.join( map(str, [ '', cmd.name, cmd.useSsh, 249 cmd.cycleTime, cmd.component, cmd.points ]) )
250 tester.printDeviceProxy = printer 251 tester.showDeviceInfo() 252