def find_object(self, v): """ Find object by remote system/remote id :param v: :return: """ if not v.get("remote_system") or not v.get("remote_id"): self.logger.warning("RS or RID not found") return None if not hasattr(self, "_service_remote_ids"): self.logger.info("Filling service collection") coll = ServiceModel._get_collection() self._service_remote_ids = { c["remote_id"]: c["_id"] for c in coll.find( { "remote_system": v["remote_system"].id, "remote_id": { "$exists": True } }, { "remote_id": 1, "_id": 1 }, ) } if v["remote_id"] in self._service_remote_ids: return ServiceModel.objects.get( id=self._service_remote_ids[v["remote_id"]]) return None
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 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 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