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

Source Code for Module Products.ZenHub.services.DiscoverService

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2008, 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  import math 
 12  import re 
 13  from ipaddr import IPNetwork 
 14  import logging 
 15   
 16  log = logging.getLogger('zen.DiscoverService') 
 17   
 18  import Globals 
 19  import transaction 
 20  from twisted.spread import pb 
 21  from ZODB.transact import transact 
 22   
 23  from Products.Jobber.exceptions import NoSuchJobException 
 24  from Products.ZenUtils.IpUtil import strip, ipwrap, ipunwrap, isip 
 25  from Products.ZenEvents.Event import Event 
 26  from Products.ZenEvents.ZenEventClasses import Status_Ping 
 27  from Products.ZenModel.Device import manage_createDevice 
 28  from Products.ZenHub.PBDaemon import translateError 
 29  from Products.ZenModel.Exceptions import DeviceExistsError 
 30  from Products.ZenRelations.ZenPropertyManager import iszprop 
 31   
 32  from .ModelerService import ModelerService 
 33   
 34   
 35  DEFAULT_PING_THRESH = 168 
36 37 38 -class JobPropertiesProxy(pb.Copyable, pb.RemoteCopy):
39 - def __init__(self, jobrecord):
40 self.zProperties = {} 41 for prop in jobrecord.__dict__: 42 if iszprop(prop): 43 self.zProperties[prop] = getattr(jobrecord, prop)
44 45 pb.setUnjellyableForClass(JobPropertiesProxy, JobPropertiesProxy)
46 47 -class IpNetProxy(pb.Copyable, pb.RemoteCopy):
48 "A class that will represent a ZenModel/IpNetwork in zendisc" 49 50 id = '' 51 _children = None 52 netmask = None 53
54 - def __init__(self, ipnet):
55 self.id = ipnet.id 56 self._children = map(IpNetProxy, ipnet.children()) 57 self.netmask = ipnet.netmask 58 for prop in 'zAutoDiscover zDefaultNetworkTree zPingFailThresh'.split(): 59 if hasattr(ipnet, prop): 60 setattr(self, prop, getattr(ipnet, prop))
61
62 - def children(self):
63 return self._children
64
65 - def fullIpList(self):
66 "copied from IpNetwork" 67 log.debug("fullIpList: using ipaddr IPNetwork on %s (%s)" % (self.id, ipunwrap(self.id))) 68 net = IPNetwork(ipunwrap(self.id)) 69 if self.netmask == net.max_prefixlen: return [ipunwrap(self.id)] 70 ipnumb = long(int(net)) 71 maxip = math.pow(2, net.max_prefixlen - self.netmask) 72 start = int(ipnumb+1) 73 end = int(ipnumb+maxip-1) 74 return map(strip, range(start,end))
75
76 - def getNetworkName(self):
77 return "%s/%d" % (ipunwrap(self.id), self.netmask)
78 79 pb.setUnjellyableForClass(IpNetProxy, IpNetProxy)
80 81 82 -class DiscoverService(ModelerService):
83 84 @translateError
85 - def remote_getNetworks(self, net, includeSubNets):
86 "Get network objects to scan networks should be in CIDR form 1.1.1.0/24" 87 netObj = self.dmd.Networks.getNetworkRoot().findNet(net) 88 if not netObj: 89 return None 90 nets = [netObj] 91 if includeSubNets: 92 nets += netObj.getSubNetworks() 93 return map(IpNetProxy, nets)
94 95 @translateError
96 - def remote_pingStatus(self, net, goodips, badips, resetPtr, addInactive):
97 "Create objects based on ping results" 98 net = self.dmd.Networks.getNetworkRoot().findNet(net.id, net.netmask) 99 pingthresh = getattr(net, "zPingFailThresh", DEFAULT_PING_THRESH) 100 ips = [] 101 for ip in goodips: 102 ipobj = net.createIp(ip, net.netmask) 103 if resetPtr: 104 ipobj.setPtrName() 105 if not ipobj.device(): 106 ips.append(ip) 107 self.sendIpStatusEvent(ipobj, sev=0) 108 for ip in badips: 109 ipobj = self.dmd.Networks.getNetworkRoot().findIp(ip) 110 if not ipobj and addInactive: 111 ipobj = net.createIp(ip, net.netmask) 112 if ipobj: 113 if resetPtr: 114 ipobj.setPtrName() 115 elif ipobj.getStatus(Status_Ping) > pingthresh: 116 net.ipaddresses.removeRelation(ipobj) 117 if ipobj: 118 self.sendIpStatusEvent(ipobj) 119 transaction.commit() 120 return ips
121 122
123 - def sendIpStatusEvent(self, ipobj, sev=2):
124 """Send an ip down event. These are used to cleanup unused ips. 125 """ 126 ip = ipobj.id 127 dev = ipobj.device() 128 if sev == 0: 129 msg = "ip %s is up" % ip 130 else: 131 msg = "ip %s is down" % ip 132 if dev: 133 devname = dev.id 134 comp = ipobj.interface().id 135 else: 136 devname = comp = ip 137 self.sendEvent(dict(device=devname, ipAddress=ip, eventKey=ip, 138 component=comp, eventClass=Status_Ping, summary=msg, severity=sev, 139 agent="Discover"))
140 141 142 @translateError
143 - def remote_createDevice(self, ip, force=False, **kw):
144 """Create a device. 145 146 @param ip: The manageIp of the device 147 @param kw: The args to manage_createDevice. 148 """ 149 # During discovery, if the device 150 # shares an id with another device 151 # with a different ip, set the device 152 # title to the supplied id and replace 153 # the id with the ip 154 deviceName = kw['deviceName'] 155 if deviceName: 156 device = self.dmd.Devices.findDeviceByIdExact(deviceName) 157 if device and ip != device.manageIp: 158 kw['deviceName'] = ip 159 kw['title'] = deviceName 160 161 from Products.ZenModel.Device import getNetworkRoot 162 @transact 163 def _doDbWork(): 164 """ 165 return device object (either new or existing), and flag indicating 166 whether device was newly created, or just updated 167 """ 168 try: 169 netroot = getNetworkRoot(self.dmd, 170 kw.get('performanceMonitor', 'localhost')) 171 netobj = netroot.getNet(ip) 172 netmask = 24 173 if netobj is not None: 174 netmask = netobj.netmask 175 else: 176 defaultNetmasks = getattr(netroot, 'zDefaultNetworkTree', []) 177 if defaultNetmasks: 178 netmask = defaultNetmasks[0] 179 netroot.createIp(ip, netmask) 180 autoDiscover = getattr(netobj, 'zAutoDiscover', True) 181 # If we're not supposed to discover this IP, return None 182 if not force and not autoDiscover: 183 return None, False 184 kw['manageIp'] = ipunwrap(ip) 185 dev = manage_createDevice(self.dmd, **kw) 186 return dev, True 187 except DeviceExistsError, e: 188 # Update device with latest info from zendisc 189 e.dev.setManageIp(kw['manageIp']) 190 191 # only overwrite title if it has not been set 192 if not e.dev.title or isip(e.dev.title): 193 if not isip(kw.get('deviceName')): 194 e.dev.setTitle(kw['deviceName']) 195 196 # copy kw->updateAttributes, to keep kw intact in case 197 # we need to retry transaction 198 updateAttributes = {} 199 for k,v in kw.items(): 200 if k not in ('manageIp', 'deviceName', 'devicePath', 201 'discoverProto'): 202 updateAttributes[k] = v 203 # use updateDevice so we don't clobber existing device properties. 204 e.dev.updateDevice(**updateAttributes) 205 return e.dev, False 206 except Exception, ex: 207 log.exception("IP address %s (kw = %s) encountered error", ipunwrap(ip), kw) 208 raise pb.CopyableFailure(ex)
209 210 dev, deviceIsNew = _doDbWork() 211 if dev is not None: 212 return self.createDeviceProxy(dev), deviceIsNew 213 else: 214 return None, False
215 216 @translateError
217 - def remote_getJobProperties(self, jobid):
218 try: 219 jobrecord = self.dmd.JobManager.getJob(jobid) 220 if jobrecord: 221 return JobPropertiesProxy(jobrecord) 222 except NoSuchJobException: 223 pass
224 225 @translateError
226 - def remote_succeedDiscovery(self, id):
227 dev = self.dmd.Devices.findDeviceByIdOrIp(id) 228 if dev: 229 dev._temp_device = False 230 transaction.commit() 231 return True
232 233 @translateError
234 - def remote_followNextHopIps(self, device):
235 """ 236 Return the ips that the device's indirect routes point to 237 which aren't currently connected to devices. 238 """ 239 dev = self.getPerformanceMonitor().findDevice(device) 240 ips = [] 241 for r in dev.os.routes(): 242 ipobj = r.nexthop() 243 if ipobj: ips.append(ipobj.id) 244 return ips
245 246 247 @translateError
248 - def remote_getSubNetworks(self):
249 "Fetch proxies for all the networks" 250 return map(IpNetProxy, 251 self.dmd.Networks.getNetworkRoot().getSubNetworks())
252 253 254 @translateError
255 - def remote_getSnmpConfig(self, devicePath):
256 "Get the snmp configuration defaults for scanning a device" 257 devroot = self.dmd.Devices.createOrganizer(devicePath) 258 return (devroot.zSnmpCommunities, 259 devroot.zSnmpPort, 260 devroot.zSnmpVer, 261 devroot.zSnmpTimeout, 262 devroot.zSnmpTries)
263 264 265 @translateError
266 - def remote_moveDevice(self, dev, path):
267 self.dmd.Devices.moveDevices(path, [dev]) 268 transaction.commit()
269 270 @translateError
271 - def remote_getDefaultNetworks(self):
272 monitor = self.dmd.Monitors.Performance._getOb(self.instance) 273 return [net for net in monitor.discoveryNetworks]
274