def _apply_interfaces(mo, r): # id -> (object id, name) ifcache = {} # Get interfaces interfaces = sorted( Interface._get_collection().find({"managed_object": mo.id}), key=lambda x: split_alnum(x["name"]), ) # Populate cache for i in interfaces: ifcache[i["_id"]] = (i["managed_object"], i["name"]) # Get subs subs = defaultdict(list) for s in SubInterface._get_collection().find({"managed_object": mo.id}): subs[s["interface"]] += [s] # Get links links = defaultdict(list) for l in Link._get_collection().find({"linked_objects": mo.id}): for li in l.get("interfaces", []): links[li] += [l] # Populate cache with linked interfaces if links: for i in Interface._get_collection().find( {"_id": {"$in": list(links)}}, {"_id": 1, "managed_object": 1, "name": 1} ): ifcache[i["_id"]] = (i["managed_object"], i["name"]) # Populate r["interfaces"] = [ ManagedObjectDataStream._get_interface(i, subs[i["_id"]], links[i["_id"]], ifcache) for i in interfaces ]
def unbind_interface(self): from noc.inv.models.interface import Interface Interface._get_collection().update({"service": self.id}, {"$unset": { "service": "" }}) self._refresh_managed_object()
def load(mo_ids, zero, def_profile, interface_profile): match = { "managed_object": {"$in": mo_ids}, "type": {"$in": ["physical"]}, "admin_status": True, } if interface_profile: match["profile"] = {"$in": [ObjectId(str(interface_profile))]} if zero: match["oper_status"] = True if def_profile and interface_profile is None: def_prof = [pr.id for pr in InterfaceProfile.objects.filter(name__contains="default")] match["profile"] = {"$nin": def_prof} lookup = { "from": "noc.subinterfaces", "localField": "_id", "foreignField": "interface", "as": "subs", } result = ( Interface._get_collection() .with_options(read_preference=ReadPreference.SECONDARY_PREFERRED) .aggregate([{"$match": match}, {"$lookup": lookup}]) ) return result
def extract(self): mos_id = dict(ManagedObject.objects.filter().values_list("id", "bi_id")) iface_prof = { i[0]: (i[1], int(i[2] or 0)) for i in InterfaceProfile.objects.filter().values_list("id", "name", "is_uni") } ifs = Interface._get_collection().with_options( read_preference=ReadPreference.SECONDARY_PREFERRED ) for iface in ifs.find( {"type": "physical"}, { "_id": 0, "managed_object": 1, "name": 1, "description": 1, "profile": 1, "in_speed": 1, }, ).sort("managed_object"): yield ( mos_id[iface["managed_object"]], iface["name"], iface.get("description", ""), iface_prof[iface["profile"]][0], abs(iface.get("in_speed", 0)) * 1000, # iface speed in kbit/s convert to bit/s, # some vendors set speed -1 for iface down iface_prof[iface["profile"]][1], )
def extract(self): mos_id = dict(ManagedObject.objects.filter().values_list( "id", "bi_id")) iface_prof = { i[0]: (i[1], int(i[2] or 0)) for i in InterfaceProfile.objects.filter().values_list( "id", "name", "is_uni") } ifs = Interface._get_collection().with_options( read_preference=ReadPreference.SECONDARY_PREFERRED) for iface in ifs.find({ "description": { "$exists": True } }, { "_id": 0, "managed_object": 1, "name": 1, "description": 1, "profile": 1, "in_speed": 1 }).sort("managed_object"): yield (mos_id[iface["managed_object"]], iface["name"], iface.get("description", ""), iface_prof[iface["profile"]][0], iface.get("in_speed", 0), iface_prof[iface["profile"]][1])
def set_nri_aliases(self, mo): """ Fill interface alias cache with nri names :param mo: :return: """ if mo in self.seen_neighbors: return seen = False for d in Interface._get_collection().find( { "managed_object": mo.id, "nri_name": { "$exists": True } }, { "_id": 0, "name": 1, "nri_name": 1 }, ): self.set_interface_alias(mo, d["name"], d["nri_name"]) seen = True self.seen_neighbors.add(mo) if not seen: self.logger.info( "[%s] Object has no nri interface name. Topology may be incomplete", mo.name)
def get_linked_pops(self): linked = set() self.pops = set(self.get_pop_objects()) self_interfaces = set( Interface.objects.filter( managed_object__in=self.pops).values_list("id")) r_ifaces = set() for ld in Link._get_collection().find( {"interfaces": { "$in": list(self_interfaces) }}, { "_id": 0, "interfaces": 1 }): r_ifaces |= set(ld.get("interfaces", [])) r_ifaces -= self_interfaces r_mos = set(i["managed_object"] for i in Interface._get_collection().find( {"_id": { "$in": list(r_ifaces) }}, { "_id": 0, "managed_object": 1 })) for o in Object.objects.filter( data__match={ "interface": "management", "attr": "managed_object", "value__in": list(r_mos), }): pop = o.get_pop() if pop: linked.add(pop) return linked
def _get_loopback_addresses(cls, mo_id): from noc.inv.models.interface import Interface from noc.inv.models.subinterface import SubInterface # Get all loopbacks if_ids = [] for d in Interface._get_collection().find( { "managed_object": int(mo_id), "type": "loopback" }, {"_id": 1}): if_ids += [d["_id"]] if not if_ids: return [] # Get loopback's addresses r = [] for d in SubInterface._get_collection().find( { "managed_object": int(mo_id), "interface": { "$in": if_ids }, "ipv4_addresses": { "$exists": True }, }, { "_id": 0, "ipv4_addresses": 1 }, ): for a in d.get("ipv4_addresses", []): r += [str(a).split("/")[0]] return r
def bulk_field_interface_count(self, data): """ Apply interface_count fields :param data: :return: """ mo_ids = [x["id"] for x in data] if not mo_ids: return data # Collect interface counts r = Interface._get_collection().aggregate([ { "$match": { "managed_object": { "$in": mo_ids }, "type": "physical" } }, { "$group": { "_id": "$managed_object", "total": { "$sum": 1 } } }, ]) ifcount = dict((x["_id"], x["total"]) for x in r) # Apply interface counts for x in data: x["interface_count"] = ifcount.get(x["id"]) or 0 return data
def handler(self): self.logger.info("NRI Portmapper") if not self.object.remote_system: self.logger.info("Created directly. No NRI integration. Skipping check") return nri = self.object.remote_system.name # Check object has interfaces if not self.has_capability("DB | Interfaces"): self.logger.info("No interfaces discovered. " "Skipping interface status check") return # Get portmapper instance portmapper = portmapper_loader.get_loader(self.object.remote_system.name)(self.object) if not portmapper: self.logger.info("[%s] No portmapper for NRI. Skipping checks", nri) return # Process interfaces bulk = [] icol = Interface._get_collection() for d in icol.find( {"managed_object": self.object.id, "type": "physical"}, {"_id": 1, "name": 1, "nri_name": 1}, ): nri_name = portmapper.to_remote(d["name"]) self.logger.debug("[%s] Port mapping %s <-> %s", nri, d["name"], nri_name) if not nri_name: self.logger.info("[%s] Cannot map port name '%s'", nri, d["name"]) elif d.get("nri_name") != nri_name: self.logger.info("[%s] Mapping '%s' to '%s'", nri, nri_name, d["name"]) bulk += [UpdateOne({"_id": d["_id"]}, {"$set": {"nri_name": nri_name}})] if bulk: self.logger.info("Sending %d updates", len(bulk)) icol.bulk_write(bulk)
def refine_ifindexes(self): missed_ifindexes = [ x["name"] for x in Interface._get_collection().find( { "managed_object": self.object.id, "ifindex": None }, {"name": 1}) ] if not missed_ifindexes: return self.logger.info("Missed ifindexes for: %s", ", ".join(missed_ifindexes)) r = self.object.scripts.get_ifindexes() if not r: return updates = {} for n in missed_ifindexes: if n in r: updates[n] = r[n] if not updates: return for n, i in updates.iteritems(): iface = Interface.objects.filter(managed_object=self.object.id, name=n).first() if iface: self.logger.info("Set infindex for %s: %s", n, i) iface.ifindex = i iface.save() # Signals will be sent
def get_interface_metrics(self): """ Populate metrics list with interface metrics :return: """ subs = None metrics = [] for i in (Interface._get_collection().with_options( read_preference=ReadPreference.SECONDARY_PREFERRED).find( { "managed_object": self.object.id, "type": "physical" }, { "_id": 1, "name": 1, "ifindex": 1, "profile": 1 }, )): ipr = self.get_interface_profile_metrics(i["profile"]) self.logger.debug("Interface %s. ipr=%s", i["name"], ipr) if not ipr: continue # No metrics configured i_profile = InterfaceProfile.get_by_id(i["profile"]) if i_profile.allow_subinterface_metrics and subs is None: # Resolve subinterfaces subs = self.get_subinterfaces() ifindex = i.get("ifindex") for metric in ipr: if (self.is_box and not ipr[metric].enable_box) or ( self.is_periodic and not ipr[metric].enable_periodic): continue m_id = next(self.id_count) m = { "id": m_id, "metric": metric, "path": ["", "", "", i["name"]] } if ifindex is not None: m["ifindex"] = ifindex metrics += [m] self.id_metrics[m_id] = ipr[metric] if i_profile.allow_subinterface_metrics: for si in subs[i["_id"]]: m_id = next(self.id_count) m = { "id": m_id, "metric": metric, "path": ["", "", "", i["name"], si["name"]], } if si["ifindex"] is not None: m["ifindex"] = si["ifindex"] metrics += [m] self.id_metrics[m_id] = ipr[metric] if not metrics: self.logger.info("Interface metrics are not configured. Skipping") return metrics
def interface_tags_to_id(cls, object_name, interface_name): mo = cls.managedobject_name_to_id(object_name) i = Interface._get_collection().find_one({ "managed_object": mo, "name": interface_name }) if i: return i["_id"] return None
def api_metrics(self, request, metrics): def q(s): if isinstance(s, str): s = s.encode("utf-8") return s def qt(t): return "|".join(["%s=%s" % (v, t[v]) for v in sorted(t)]) # Build query tag_id = {} # object, interface -> id if_ids = {} # id -> port id mlst = [] # (metric, object, interface) for m in metrics: if "object" in m["tags"] and "interface" in m["tags"]: if not m["tags"]["object"]: continue try: if_ids[ self.interface_tags_to_id(m["tags"]["object"], m["tags"]["interface"]) ] = m["id"] object = ManagedObject.objects.get(name=m["tags"]["object"]) tag_id[object, m["tags"]["interface"]] = m["id"] mlst += [(m["metric"], object, m["tags"]["interface"])] except KeyError: pass # @todo: Get last values from cache if not mlst: return {} r = {} # Apply interface statuses for d in Interface._get_collection().find( {"_id": {"$in": list(if_ids)}}, {"_id": 1, "admin_status": 1, "oper_status": 1} ): r[if_ids[d["_id"]]] = { "admin_status": d.get("admin_status", True), "oper_status": d.get("oper_status", True), } metric_map, last_ts = get_interface_metrics([m[1] for m in mlst]) # Apply metrics for rq_mo, rq_iface in tag_id: pid = tag_id.get((rq_mo, rq_iface)) if not pid: continue if pid not in r: r[pid] = {} if rq_mo not in metric_map: continue if rq_iface not in metric_map[rq_mo]: continue r[pid]["Interface | Load | In"] = metric_map[rq_mo][rq_iface]["Interface | Load | In"] r[pid]["Interface | Load | Out"] = metric_map[rq_mo][rq_iface]["Interface | Load | Out"] return r
def get_interfaces(self): """ Build interface counts :return: """ r = Interface._get_collection().aggregate( [ {"$match": {"type": "physical"}}, {"$group": {"_id": "$managed_object", "total": {"$sum": 1}}}, ] ) return dict((d["_id"], {"n_interfaces": d["total"]}) for d in r)
def refresh_interface_profiles(sp_id, ip_id): from .service import Service from noc.inv.models.interface import Interface svc = [ x["_id"] for x in Service._get_collection().find({"profile": sp_id}, {"_id": 1}) ] if not svc: return collection = Interface._get_collection() bulk = [] bulk += [UpdateOne({"_id": {"$in": svc}}, {"$set": {"profile": ip_id}})] collection.bulk_write(bulk, ordered=False)
def _apply_interfaces(mo: ManagedObject, r): # id -> (object id, name) ifcache = {} # Get interfaces interfaces = sorted( Interface._get_collection().find({"managed_object": mo.id}), key=lambda x: alnum_key(x["name"]), ) # Populate cache for i in interfaces: ifcache[i["_id"]] = (i["managed_object"], i["name"]) # Get subs subs = defaultdict(list) for s in SubInterface._get_collection().find({"managed_object": mo.id}): subs[s["interface"]] += [s] # Get links links = defaultdict(list) for link in Link._get_collection().find({"linked_objects": mo.id}): for li in link.get("interfaces", []): links[li] += [link] # Populate cache with linked interfaces if links: for i in Interface._get_collection().find( {"_id": {"$in": list(links)}}, {"_id": 1, "managed_object": 1, "name": 1} ): ifcache[i["_id"]] = (i["managed_object"], i["name"]) # Get services svc_ids = [i["service"] for i in interfaces if i.get("service")] if svc_ids: services = {svc.id: svc for svc in Service.objects.filter(id__in=svc_ids)} else: services = {} # Populate r["interfaces"] = [ ManagedObjectDataStream._get_interface( i, subs[i["_id"]], links[i["_id"]], ifcache, set(mo.data.uplinks), services ) for i in interfaces ]
def handle_portmap(self, portmap_objects=[]): for po in portmap_objects: for o in ManagedObjectSelector.get_objects_from_expression(po): if not o.remote_system: self.stdout.write("%s (%s, %s) NRI: N/A\n" % (o.name, o.address, o.platform)) continue portmapper = loader.get_loader(o.remote_system.name)(o) nri = o.remote_system.name self.stdout.write("%s (%s, %s) NRI: %s\n" % (o.name, o.address, o.platform, nri)) r = [] for i in Interface._get_collection().find( { "managed_object": o.id, "type": "physical" }, { "_id": 1, "name": 1, "nri_name": 1 }, ): rn = portmapper.to_remote(i["name"]) or self.PORT_ERROR if rn == self.PORT_ERROR: ln = self.PORT_ERROR else: ln = portmapper.to_local(rn) or self.PORT_ERROR if i.get("nri_name") == rn and ln != self.PORT_ERROR: status = "OK" elif not i.get("nri_name") and ln != self.PORT_ERROR: status = "Not in database" elif rn == self.PORT_ERROR: status = "Failed to convert to remote name" else: self.print(ln, rn, i.get("nri_name")) status = "Failed to convert to local name" r += [(i["name"], rn, i.get("nri_name", "--"), status)] r = [("Local", "Remote", "Interface NRI", "Status")] + list( sorted(r, key=lambda x: alnum_key(x[0]))) self.stdout.write( "%s\n" % format_table([0, 0, 0, 0], r, sep=" | ", hsep="-+-"))
def load(self): """ Load all managed objects from segment """ def get_bandwidth(if_list): """ Calculate bandwidth for list of interfaces :param if_list: :return: total in bandwidth, total out bandwidth """ in_bw = 0 out_bw = 0 for iface in if_list: bw = iface.get("bandwidth") or 0 in_speed = iface.get("in_speed") or 0 out_speed = iface.get("out_speed") or 0 in_bw += bandwidth(in_speed, bw) out_bw += bandwidth(out_speed, bw) return in_bw, out_bw def bandwidth(speed, if_bw): if speed and if_bw: return min(speed, if_bw) elif speed and not if_bw: return speed elif if_bw: return if_bw else: return 0 # Get all links, belonging to segment links = list( Link.objects.filter( linked_segments__in=[s.id for s in self.segment_siblings])) # All linked interfaces from map all_ifaces = list( itertools.chain.from_iterable(link.interface_ids for link in links)) # Bulk fetch all interfaces data ifs = dict((i["_id"], i) for i in Interface._get_collection().find( {"_id": { "$in": all_ifaces }}, { "_id": 1, "managed_object": 1, "name": 1, "bandwidth": 1, "in_speed": 1, "out_speed": 1, }, )) # Bulk fetch all managed objects segment_mos = set( self.segment.managed_objects.values_list("id", flat=True)) all_mos = list( set(i["managed_object"] for i in six.itervalues(ifs) if "managed_object" in i) | segment_mos) mos = dict( (mo.id, mo) for mo in ManagedObject.objects.filter(id__in=all_mos)) self.segment_objects = set(mo_id for mo_id in all_mos if mos[mo_id].segment.id == self.segment.id) for mo in six.itervalues(mos): self.add_object(mo) # Process all segment's links pn = 0 for link in links: if link.is_loop: continue # Loops are not shown on map # Group interfaces by objects # avoiding non-bulk dereferencing mo_ifaces = defaultdict(list) for if_id in link.interface_ids: iface = ifs[if_id] mo_ifaces[mos[iface["managed_object"]]] += [iface] # Pairs of managed objects are pseudo-links if len(mo_ifaces) == 2: # ptp link pseudo_links = [list(mo_ifaces)] is_pmp = False else: # pmp # Create virtual cloud self.add_cloud(link) # Create virtual links to cloud pseudo_links = [(link, mo) for mo in mo_ifaces] # Create virtual cloud interface mo_ifaces[link] = [{"name": "cloud"}] is_pmp = True # Link all pairs for mo0, mo1 in pseudo_links: mo0_id = str(mo0.id) mo1_id = str(mo1.id) # Create virtual ports for mo0 self.G.node[mo0_id]["ports"] += [{ "id": pn, "ports": [i["name"] for i in mo_ifaces[mo0]] }] # Create virtual ports for mo1 self.G.node[mo1_id]["ports"] += [{ "id": pn + 1, "ports": [i["name"] for i in mo_ifaces[mo1]] }] # Calculate bandwidth t_in_bw, t_out_bw = get_bandwidth(mo_ifaces[mo0]) d_in_bw, d_out_bw = get_bandwidth(mo_ifaces[mo1]) in_bw = bandwidth(t_in_bw, d_out_bw) * 1000 out_bw = bandwidth(t_out_bw, d_in_bw) * 1000 # Add link if is_pmp: link_id = "%s-%s-%s" % (link.id, pn, pn + 1) else: link_id = str(link.id) self.add_link( mo0_id, mo1_id, { "id": link_id, "type": "link", "method": link.discovery_method, "ports": [pn, pn + 1], # Target to source "in_bw": in_bw, # Source to target "out_bw": out_bw, # Max bandwidth "bw": max(in_bw, out_bw), }, ) pn += 2
def get_ajax_data(self, **kwargs): # Parse query params query = self.decode_query( self.handler.get_argument("key") ) # type: List[Tuple[int, int, str]] # Get metrics from_ts = datetime.datetime.now() - datetime.timedelta(seconds=1800) from_ts = from_ts.replace(microsecond=0) interface_sql = """ SELECT managed_object, path[4] AS iface, argMax(load_in, ts) AS load_in, argMax(load_out, ts) AS load_out, argMax(packets_in, ts) AS packets_in, argMax(packets_out, ts) AS packets_out, argMax(errors_in, ts) AS errors_in, argMax(errors_out, ts) AS errors_out FROM interface WHERE date >= toDate('%s') AND ts >= toDateTime('%s') AND (%s) GROUP BY managed_object, iface """ % ( from_ts.date().isoformat(), from_ts.isoformat(sep=" "), " OR ".join( "(managed_object=%d AND path[4]='%s')" % (q[1], q[2].replace("'", "''")) for q in query ), ) # Get data metrics = [] # type: List[Tuple[int, str, str, str, str, str]] ch = ch_connection() try: for ( mo, iface, load_in, load_out, packets_in, packets_out, errors_in, errors_out, ) in ch.execute(post=interface_sql): if_hash = str(bi_hash(iface)) metrics += [ # (mo, if_hash, "speed", self.humanize_metric(speed)), (mo, if_hash, "load_in", self.humanize_metric(load_in)), (mo, if_hash, "load_out", self.humanize_metric(load_out)), (mo, if_hash, "packets_in", self.humanize_metric(packets_in)), (mo, if_hash, "packets_out", self.humanize_metric(packets_out)), (mo, if_hash, "errors_in", self.humanize_metric(errors_in)), (mo, if_hash, "errors_out", self.humanize_metric(errors_out)), ] except ClickhouseError: pass # Set defaults m_index = set() # type: Set[Tuple[int, str]] for mo_bi_id, iface, _, _ in metrics: m_index.add((int(mo_bi_id), iface)) interface_metrics = { "speed", "load_in", "load_out", "packets_in", "packets_out", "errors_in", "errors_out", } for _, mo_bi_id, iface in query: if (int(mo_bi_id), str(bi_hash(iface))) not in m_index: for metric in interface_metrics: metrics += [(str(mo_bi_id), str(bi_hash(iface)), metric, "-")] # managed object id -> bi id mo_map = {q[0]: q[1] for q in query} # type: Dict[int, int] # Get interface statuses for doc in Interface._get_collection().find( {"$or": [{"managed_object": q[0], "name": q[2]} for q in query]}, { "_id": 0, "managed_object": 1, "name": 1, "admin_status": 1, "oper_status": 1, "in_speed": 1, "out_speed": 1, "full_duplex": 1, }, ): mo = str(mo_map[doc["managed_object"]]) if_hash = str(bi_hash(doc["name"])) status = 0 if "admin_status" in doc and doc["admin_status"]: status = 2 if doc["oper_status"] else 1 duplex = "-" if "full_duplex" in doc: duplex = "Full" if doc["full_duplex"] else "Half" speed = "-" if "in_speed" in doc: speed = self.humanize_metric(doc["in_speed"] * 1000) metrics += [ (mo, if_hash, "speed", speed), (mo, if_hash, "duplex", duplex), (mo, if_hash, "status", status), ] # Get current object statuses obj_statuses = ObjectStatus.get_statuses(list(mo_map)) statuses = {str(mo_map[mo_id]): obj_statuses.get(mo_id, True) for mo_id in obj_statuses} return {"metrics": metrics, "statuses": list(statuses.items())}
def get_data(self, request, pool, obj_profile=None, **kwargs): problems = {} # id -> problem if not obj_profile: # Get all managed objects mos = dict( (mo.id, mo) for mo in ManagedObject.objects.filter(is_managed=True, pool=pool) ) if not request.user.is_superuser: mos = dict( (mo.id, mo) for mo in ManagedObject.objects.filter(is_managed=True, pool=pool, administrative_domain__in=UserAccess.get_domains(request.user)) ) else: # Get all managed objects mos = dict( (mo.id, mo) for mo in ManagedObject.objects.filter(is_managed=True, pool=pool, object_profile=obj_profile) ) if not request.user.is_superuser: mos = dict( (mo.id, mo) for mo in ManagedObject.objects.filter(is_managed=True, pool=pool, object_profile=obj_profile, administrative_domain__in=UserAccess.get_domains(request.user)) ) mos_set = set(mos) # Get all managed objects with generic profile for mo in mos: if mos[mo].profile.name == GENERIC_PROFILE: problems[mo] = _("Profile check failed") # Get all managed objects without interfaces if_mo = dict( (x["_id"], x.get("managed_object")) for x in Interface._get_collection().find( {}, {"_id": 1, "managed_object": 1} ) ) for mo in (mos_set - set(problems) - set(if_mo.itervalues())): problems[mo] = _("No interfaces") # Get all managed objects without links linked_mos = set() for d in Link._get_collection().find({}): for i in d["interfaces"]: linked_mos.add(if_mo.get(i)) for mo in (mos_set - set(problems) - linked_mos): problems[mo] = _("No links") # Get all managed objects without uplinks uplinks = {} for d in ObjectData._get_collection().find(): nu = len(d.get("uplinks", [])) if nu: uplinks[d["_id"]] = nu for mo in (mos_set - set(problems) - set(uplinks)): problems[mo] = _("No uplinks") # data = [] for mo_id in problems: if mo_id not in mos: continue mo = mos[mo_id] data += [[ mo.name, mo.address, mo.profile.name, mo.platform.name if mo.platform else "", mo.segment.name if mo.segment else "", problems[mo_id] ]] data = sorted(data) return self.from_dataset( title=self.title, columns=[ "Name", "Address", "Profile", "Platform", "Segment", "Problem" ], data=data, enumerate=True )
def handler(self): def get_interface(name): if_name = interfaces.get(name) if if_name: return if_name for iname in self.object.get_profile().get_interface_names( i["interface"]): if_name = interfaces.get(iname) if if_name: return if_name return None has_interfaces = "DB | Interfaces" in self.object.get_caps() if not has_interfaces: self.logger.info("No interfaces discovered. " "Skipping interface status check") return self.logger.info("Checking interface statuses") interfaces = dict((i.name, i) for i in Interface.objects.filter( managed_object=self.object.id, type="physical", profile__in=self.get_profiles(None), read_preference=ReadPreference.SECONDARY_PREFERRED, )) if not interfaces: self.logger.info( "No interfaces with status discovery enabled. Skipping") return hints = [{ "interface": key, "ifindex": v.ifindex } for key, v in six.iteritems(interfaces) if getattr(v, "ifindex", None) is not None] or None result = self.object.scripts.get_interface_status_ex(interfaces=hints) collection = Interface._get_collection() bulk = [] for i in result: iface = get_interface(i["interface"]) if not iface: continue kwargs = { "admin_status": i.get("admin_status"), "full_duplex": i.get("full_duplex"), "in_speed": i.get("in_speed"), "out_speed": i.get("out_speed"), "bandwidth": i.get("bandwidth"), } changes = self.update_if_changed(iface, kwargs, ignore_empty=list( six.iterkeys(kwargs)), bulk=bulk) self.log_changes( "Interface %s status has been changed" % i["interface"], changes) ostatus = i.get("oper_status") if iface.oper_status != ostatus and ostatus is not None: self.logger.info("[%s] set oper status to %s", i["interface"], ostatus) iface.set_oper_status(ostatus) if bulk: self.logger.info("Committing changes to database") try: collection.bulk_write(bulk, ordered=False) # 1 bulk operations complete in 0ms: inserted=0, updated=1, removed=0 self.logger.info("Database has been synced") except BulkWriteError as e: self.logger.error("Bulk write error: '%s'", e.details)
def get_data(self, request, pool=None, obj_profile=None, **kwargs): problems = {} # id -> problem mos = ManagedObject.objects.filter(is_managed=True, pool=pool) if not request.user.is_superuser: mos = mos.filter(administrative_domain__in=UserAccess.get_domains(request.user)) if obj_profile: # Get all managed objects mos = mos.filter(object_profile=obj_profile) mos = { mo[0]: (mo[1], mo[2], Profile.get_by_id(mo[3]), mo[4], mo[5]) for mo in mos.values_list("id", "name", "address", "profile", "platform", "segment") } mos_set = set(mos) # Get all managed objects with generic profile for mo in mos: if mos[mo][2] == GENERIC_PROFILE: problems[mo] = _("Profile check failed") # Get all managed objects without interfaces if_mo = dict( (x["_id"], x.get("managed_object")) for x in Interface._get_collection().find({}, {"_id": 1, "managed_object": 1}) ) for mo in mos_set - set(problems) - set(six.itervalues(if_mo)): problems[mo] = _("No interfaces") # Get all managed objects without links linked_mos = set() for d in Link._get_collection().find({}): for i in d["interfaces"]: linked_mos.add(if_mo.get(i)) for mo in mos_set - set(problems) - linked_mos: problems[mo] = _("No links") # Get all managed objects without uplinks uplinks = {} for d in ObjectData._get_collection().find(): nu = len(d.get("uplinks", [])) if nu: uplinks[d["_id"]] = nu for mo in mos_set - set(problems) - set(uplinks): problems[mo] = _("No uplinks") # data = [] for mo_id in problems: if mo_id not in mos: continue name, address, profile, platform, segment = mos[mo_id] data += [ [ name, address, profile.name, Platform.get_by_id(platform).name if platform else "", NetworkSegment.get_by_id(segment).name if segment else "", problems[mo_id], ] ] data = sorted(data) return self.from_dataset( title=self.title, columns=["Name", "Address", "Profile", "Platform", "Segment", "Problem"], data=data, enumerate=True, )
def handler(self): self.logger.info("NRI Portmapper") if not self.object.remote_system: self.logger.info( "Created directly. No NRI integration. Skipping check") return nri = self.object.remote_system.name # Check object has interfaces if not self.has_capability("DB | Interfaces"): self.logger.info("No interfaces discovered. " "Skipping interface status check") return # Get portmapper instance pm_cls = portmapper_loader.get_loader(self.object.remote_system.name) if not pm_cls: self.logger.info("[%s] No portmapper for NRI. Skipping checks", nri) return portmapper = pm_cls(self.object) # Process interfaces bulk = [] icol = Interface._get_collection() ifaces_hints = tuple( IFHint(name=iface["name"], ifindex=iface.get("ifindex")) for iface in icol.find( { "managed_object": self.object.id, "type": "physical" }, { "_id": 1, "name": 1, "ifindex": 1 }, )) for d in icol.find( { "managed_object": self.object.id, "type": "physical" }, { "_id": 1, "name": 1, "nri_name": 1 }, ): try: nri_name = portmapper.to_remote(d["name"], iface_hints=ifaces_hints) except Exception as e: self.logger.error( "[%s] Unhandled exception on portmapper handler '%s'. Skipping checks.", nri, e) break self.logger.debug("[%s] Port mapping %s <-> %s", nri, d["name"], nri_name) if not nri_name: self.logger.info("[%s] Cannot map port name '%s'", nri, d["name"]) elif d.get("nri_name") != nri_name: self.logger.info("[%s] Mapping '%s' to '%s'", nri, nri_name, d["name"]) bulk += [ UpdateOne({"_id": d["_id"]}, {"$set": { "nri_name": nri_name }}) ] if bulk: self.logger.info("Sending %d updates", len(bulk)) icol.bulk_write(bulk)
def handler(self): self.logger.info("NRI Service Mapper") if not self.object.remote_system: self.logger.info( "Created directly. No NRI integration. Skipping check") return if not self.object.remote_system.enable_service: self.logger.info( "NRI does not provide link information. Skipping check") return # Check object has interfaces if not self.has_capability("DB | Interfaces"): self.logger.info( "No interfaces discovered. Skipping interface status check") return # Get services related to Managed object scol = Service._get_collection() slist = [ s for s in scol.find( { "managed_object": self.object.id, "nri_port": { "$exists": True } }, { "_id": 1, "nri_port": 1, "profile": 1 }, ) ] # nri_port -> service_id smap = {s["nri_port"]: s["_id"] for s in slist} # service id -> service profile prof_map = { s["_id"]: ServiceProfile.get_by_id(s["profile"]) for s in slist } icol = Interface._get_collection() nmap = {} bulk = [] for i in icol.find({ "managed_object": self.object.id, "nri_name": { "$exists": True } }): if not i.get("nri_name"): continue if i["nri_name"] in smap: svc = smap[i["nri_name"]] p = prof_map.get(svc) if svc != i.get("service"): self.logger.info("Binding service %s to interface %s", svc, i["name"]) op = {"service": svc} if p and p.interface_profile: op["profile"] = p.interface_profile.id bulk += [UpdateOne({"_id": i["_id"]}, {"$set": op})] elif p and p.interface_profile and p.interface_profile.id != i[ "profile"]: self.logger.info("Replace profile to %s on intertace %s", p.interface_profile, i["name"]) bulk += [ UpdateOne( {"_id": i["_id"]}, {"$set": { "profile": p.interface_profile.id }}) ] del smap[i["nri_name"]] elif i.get("service"): self.logger.info("Removing service %s from interface %s", i["service"], i["name"]) op = {"$unset": {"service": ""}} if i["service"] in prof_map: op["$set"] = { "profile": InterfaceProfile.get_default_profile().id } bulk += [UpdateOne({"_id": i["_id"]}, op)] nmap[i["nri_name"]] = i # Report hanging interfaces for n in smap: svc = smap[n] if n not in nmap: self.logger.info( "Cannot bind service %s. Cannot find NRI interface %s", svc, n) continue i = nmap[n] self.logger.info("Binding service %s to interface %s", svc, i["name"]) op = {"service": svc} p = prof_map.get(svc) if p: op["profile"] = p.interface_profile.id bulk += [UpdateOne({"_id": i["_id"]}, {"$set": op})] if bulk: self.logger.info("Sending %d updates", len(bulk)) icol.bulk_write(bulk) ServiceSummary.refresh_object(self.object.id) change_tracker.register([("managedobject", self.object.id)])
def get_interface_metrics(self): """ Populate metrics list with interface metrics :return: """ # @todo: Inject Interface.effective_labels subs = None metrics = [] for i in ( Interface._get_collection() .with_options(read_preference=ReadPreference.SECONDARY_PREFERRED) .find( {"managed_object": self.object.id, "type": "physical"}, { "_id": 1, "name": 1, "ifindex": 1, "profile": 1, "in_speed": 1, "out_speed": 1, "bandwidth": 1, }, ) ): ipr = self.get_interface_profile_metrics(i["profile"]) self.logger.debug("Interface %s. ipr=%s", i["name"], ipr) if not ipr: continue # No metrics configured i_profile = InterfaceProfile.get_by_id(i["profile"]) if i_profile.allow_subinterface_metrics and subs is None: # Resolve subinterfaces subs = self.get_subinterfaces() ifindex = i.get("ifindex") for metric in ipr: if (self.is_box and not ipr[metric].enable_box) or ( self.is_periodic and not ipr[metric].enable_periodic ): continue m_id = next(self.id_count) m = {"id": m_id, "metric": metric, "labels": [f"noc::interface::{i['name']}"]} if ifindex is not None: m["ifindex"] = ifindex metrics += [m] self.id_metrics[m_id] = ipr[metric] if i_profile.allow_subinterface_metrics: for si in subs[i["_id"]]: if si["name"] != i["name"]: m_id = next(self.id_count) m = { "id": m_id, "metric": metric, "labels": [ f"noc::interface::{i['name']}", f"noc::subinterface::{si['name']}", ], } if si["ifindex"] is not None: m["ifindex"] = si["ifindex"] metrics += [m] self.id_metrics[m_id] = ipr[metric] threshold_profile = ipr[metric].threshold_profile if threshold_profile and threshold_profile.value_handler: # Fill window context in_speed: int = i.get("in_speed") or 0 out_speed: int = i.get("out_speed") or 0 bandwidth: int = i.get("bandwidth") or 0 if in_speed and not out_speed: out_speed = in_speed elif not in_speed and out_speed: in_speed = out_speed if not bandwidth: bandwidth = max(in_speed, out_speed) self.id_ctx[m_id] = { "in_speed": in_speed, "out_speed": out_speed, "bandwidth": bandwidth, } if not metrics: self.logger.info("Interface metrics are not configured. Skipping") return metrics
def get_data(self, request, reporttype=None, from_date=None, to_date=None, object_profile=None, percent=None, filter_default=None, zero=None, interface_profile=None, managed_object=None, selectors=None, administrative_domain=None, allow_archive=True, **kwargs): map_table = { "load_interfaces": "/Interface\s\|\sLoad\s\|\s[In|Out]/", "load_cpu": "/[CPU|Memory]\s\|\sUsage/", "errors": "/Interface\s\|\s[Errors|Discards]\s\|\s[In|Out]/", "ping": "/Ping\s\|\sRTT/" } # Date Time Block if not from_date: from_date = datetime.datetime.now() - datetime.timedelta(days=1) else: from_date = datetime.datetime.strptime(from_date, "%d.%m.%Y") if not to_date or from_date == to_date: to_date = from_date + datetime.timedelta(days=1) else: to_date = datetime.datetime.strptime( to_date, "%d.%m.%Y") + datetime.timedelta(days=1) interval = (to_date - from_date).days ts_from_date = time.mktime(from_date.timetuple()) ts_to_date = time.mktime(to_date.timetuple()) # Load managed objects mos = ManagedObject.objects.filter(is_managed=True) if not request.user.is_superuser: mos = mos.filter( administrative_domain__in=UserAccess.get_domains(request.user)) if managed_object: mos = [managed_object] else: if selectors: mos = mos.filter(selectors.Q) if administrative_domain: # @todo fix mos = mos.filter(administrative_domain=administrative_domain) if object_profile: mos = mos.filter(object_profile=object_profile) columns = [_("Managed Object"), _("Address")] iface_dict = {} d_url = { "path": "/ui/grafana/dashboard/script/report.js", "rname": map_table[reporttype], "from": str(int(ts_from_date * 1000)), "to": str(int(ts_to_date * 1000)), # o.name.replace("#", "%23") "biid": "", "oname": "", "iname": "" } report_map = { "load_interfaces": { "url": '%(path)s?title=interface&biid=%(biid)s' '&obj=%(oname)s&iface=%(iname)s&from=%(from)s&to=%(to)s', "q_group": ["interface"], "columns": [ _("Int Name"), _("Int Descr"), TableColumn(_("IN bps"), align="right"), TableColumn(_("OUT bps"), align="right"), ] }, "errors": { "url": """%(path)s?title=errors&biid=%(biid)s&obj=%(oname)s&iface=%(iname)s&from=%(from)s&to=%(to)s""", "columns": [ _("Int Name"), TableColumn(_("Errors IN"), align="right"), TableColumn(_("Errors OUT"), align="right"), TableColumn(_("Discards IN"), align="right"), TableColumn(_("Discards OUT"), align="right") ], "q_group": ["interface"] }, "load_cpu": { "url": """%(path)s?title=cpu&biid=%(biid)s&obj=%(oname)s&from=%(from)s&to=%(to)s""", "columns": [ TableColumn(_("Memory | Usage %"), align="right"), TableColumn(_("CPU | Usage %"), align="right") ] }, "ping": { "url": """%(path)s?title=ping&biid=%(biid)s&obj=%(oname)s&from=%(from)s&to=%(to)s""", "columns": [ TableColumn(_("Ping | RTT (ms)"), align="right"), TableColumn(_("Ping | Attempts"), align="right") ] } } if not allow_archive: report_map["load_interfaces"].update({ "q_select": [ "arrayStringConcat(path)", "round(quantile(0.98)(load_in), 0) as l_in", "round(quantile(0.98)(load_out), 0) as l_out" ], "q_group": ["path"], "q_where": ["(load_in != 0 and load_out != 0)"] if zero else [] }) report_map["errors"].update({ "q_select": [ "arrayStringConcat(path)", "quantile(0.98)(errors_in) as err_in", "quantile(0.98)(errors_out) as err_out", "quantile(0.98)(discards_in) as dis_in", "quantile(0.98)(discards_out) as dis_out" ], "q_group": ["path"], "q_where": [ "(errors_in != 0 or errors_out != 0 or discards_in != 0 or discards_out != 0)" ] if zero else [] }) report_map["load_cpu"].update({ "q_select": ["arrayStringConcat(path)", "quantile(0.98)(usage) as usage"], "q_group": ["path"] }) report_map["ping"].update({ "q_select": [ "managed_object", "round(quantile(0.98)(rtt) / 1000, 2)", "avg(attempts)" ] }) moss = { str(mo[0]): mo for mo in mos.values_list("bi_id", "id", "name", "address") } else: moss = { mo[0]: mo for mo in mos.values_list("name", "id", "name", "address") } # mos_s = set(mos.values_list("id", flat=True)) if reporttype in ["load_interfaces", "errors"]: ifaces = Interface._get_collection() xx = set(mos.values_list("id", flat=True)) for iface in ifaces.find({"type": "physical"}, { "managed_object": 1, "name": 1, "description": 1, "in_speed": 1, "out_speed": 1 }): if iface["managed_object"] not in xx: continue iface_dict[(iface["managed_object"], iface["name"])] = (iface.get("description", ""), iface.get("in_speed", 0), iface.get("out_speed", 0)) columns += report_map[reporttype]["columns"] if percent: columns.insert(-1, TableColumn(_("IN %"), align="right")) columns += [TableColumn(_("OUT %"), align="right")] columns += [ TableColumn(_("Graphic"), format="url"), TableColumn(_("Interval days"), align="right") ] url = report_map[reporttype].get("url", "") rm = ReportMetric() rm.reporttype = reporttype r = [] if allow_archive: rm_data = rm.do_query(moss, report_map[reporttype], from_date, to_date) else: rm_data = rm.do_query_ch(moss, report_map[reporttype], from_date, to_date) for l, data in rm_data: if not l: continue mo = moss[l[0]] d_url["biid"] = l[0] d_url["oname"] = mo[2].replace("#", "%23") if zero and allow_archive and not sum(data): # For InfluxDB query continue if reporttype in ["load_interfaces", "errors"]: d_url["iname"] = l[1] res = [mo[2], mo[3], l[1]] res += data if "load_interfaces" in reporttype: i_d = iface_dict.get((mo[1], l[1]), ["", "", ""]) res.insert(3, i_d[0]) if percent: in_p = float(data[0]) in_p = round( (in_p / 1000.0) / (i_d[1] / 100.0), 2) if i_d[1] and in_p > 0 else 0 # in res.insert(-1, in_p) # out out_p = float(data[1]) res += [ round((out_p / 1000.0) / (i_d[2] / 100.0), 2) if i_d[2] and out_p > 0 else 0 ] else: res = [mo[2], mo[3]] res += data res += [url % d_url, interval] r += [res] return self.from_dataset(title=self.title, columns=columns, data=r, enumerate=True)
def _get_interface(object, name): Interface._get_collection().update({"managed_object": object.id})
def build_summary_for_object(cls, managed_object): """ Build active services summary for managed object :param managed_object: Managed Object id :return: dict of interface id -> {service: ..., subscriber: ....} interface None means unbound or box-wise services """ from noc.inv.models.interface import Interface from noc.sa.models.service import Service def iter_services(sd): yield sd for cs in Service._get_collection().find( { "parent": sd["_id"], "logical_status": "R" }, { "_id": 1, "subscriber": 1, "profile": 1 }): for ns in iter_services(cs): yield ns def add_dict(d1, d2): """ Add all d2 values to d1 :param d1: :param d2: :return: """ for k in d2: d1[k] = d1.get(k, 0) + d2[k] # service -> interface bindings svc_interface = dict(( x["service"], x["_id"] ) for x in Interface._get_collection().find( { "managed_object": managed_object, "service": { "$exists": True } }, { "_id": 1, "service": 1 }, comment= "[servicesummary.build_summary_for_object] Getting services for interfaces" )) # Iterate over object's services # And walk underlying tree ri = {} for svc in Service._get_collection( ).find({ "managed_object": managed_object, "logical_status": "R" }, { "_id": 1, "subscriber": 1, "profile": 1 }, comment= "[servicesummary.build_summary_for_object] Getting object services for object" ): # All subscribers for underlying tree subscribers = set() # profile_id -> count svc_profiles = defaultdict(int) for s in iter_services(svc): subscribers.add(s["subscriber"]) svc_profiles[s["profile"]] += 1 # Get subscriber profiles count ra = Subscriber._get_collection().aggregate([{ "$match": { "_id": { "$in": list(subscribers) } } }, { "$group": { "_id": "$profile", "total": { "$sum": 1 } } }]) subscriber_profiles = dict((x["_id"], x["total"]) for x in ra) # Bind to interface # None for unbound services iface = svc_interface.get(svc["_id"]) if iface in ri: add_dict(ri[iface]["service"], svc_profiles) add_dict(ri[iface]["subscriber"], subscriber_profiles) else: ri[iface] = { "service": dict(svc_profiles), # defaultdict -> dict "subscriber": subscriber_profiles } return ri