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

Source Code for Module Products.ZenHub.services.CommandPerformanceConfig

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