def interface_classification(self, iface): """ Perform interface classification :param iface: Interface instance :return: """ if iface.profile_locked: return try: p_id = self.get_interface_profile(iface) except NotImplementedError: self.logger.error("Uses not implemented rule") return if p_id and p_id != iface.profile.id: # Change profile profile = InterfaceProfile.get_by_id(p_id) if not profile: self.logger.error( "Invalid interface profile '%s' for interface '%s'. " "Skipping", p_id, iface.name, ) return elif profile != iface.profile: self.logger.info("Interface %s has been classified as '%s'", iface.name, profile.name) iface.profile = profile iface.save()
def migrate(self): collections = [InterfaceProfile._get_collection()] for collection in collections: bulk = [] for ip in collection.find({"metrics.is_active": { "$exists": True }}): metrics = [] if "metrics" not in ip: continue # Not configured for metric in ip["metrics"]: metric["enable_periodic"] = bool( metric.get("is_active", False)) metric["enable_box"] = False if "is_active" in metric: del metric["is_active"] metrics += [metric] bulk += [ UpdateOne({"_id": ip["_id"]}, {"$set": { "metrics": metrics }}) ] if bulk: collection.bulk_write(bulk)
def _get_interface(iface, subs, links, ifcache): r = { "name": qs(iface["name"]), "type": iface["type"], "description": qs(iface.get("description")), "enabled_protocols": iface.get("enabled_protocols") or [], "admin_status": iface.get("admin_status", False), } if iface.get("ifindex"): r["snmp_ifindex"] = iface["ifindex"] if iface.get("mac"): r["mac"] = iface["mac"] if iface.get("aggregated_interface"): r["aggregated_interface"] = ifcache[ iface["aggregated_interface"]][-1] # Apply profile if iface.get("profile"): profile = InterfaceProfile.get_by_id(iface["profile"]) r["profile"] = ManagedObjectDataStream._get_interface_profile( profile) # Apply subinterfaces r["subinterfaces"] = [ ManagedObjectDataStream._get_subinterface(s) for s in sorted(subs, key=lambda x: alnum_key(x["name"])) ] # Apply links if links: r["link"] = ManagedObjectDataStream._get_link( iface, links, ifcache) return r
def handle_apply(self, moo, *args, **kwargs): # sol = config.get("interface_discovery", "get_interface_profile") # @todo Classification pyrule get_profile = None if not get_profile: get_profile = InterfaceClassificationRule get_profile = get_profile.get_classificator() # raise CommandError("No classification solution") pcache = {} for o in self.get_objects(moo): self.stdout.write( "%s (%s):\n" % (o.name, o.platform.name if o.platform else o.profile.name)) ifaces = self.get_interfaces(o) if not ifaces: self.stdout.write("No ifaces on object\n") continue tps = self.get_interface_template(ifaces) for i in ifaces: if not i.profile or not i.profile_locked: pn = get_profile(i) if pn: p = pcache.get(pn) if not p: p = InterfaceProfile.get_by_id(pn) pcache[pn] = p i.profile = p i.save() v = "Set %s" % p.name else: v = "Not matched" self.show_interface(tps, i, v)
def get_interface_profile_metrics(cls, p_id): r = {} ipr = InterfaceProfile.get_by_id(id=p_id) if not ipr: return r for m in ipr.metrics: r[m.metric_type.name] = cls.config_from_settings(m) return r
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 handle_apply_confdb(self, moo, *args, **kwargs): default_profile = InterfaceProfile.get_default_profile() for o in self.get_objects(moo): self.stdout.write( "%s (%s):\n" % (o.name, o.platform.name if o.platform else o.profile.name)) ifmap = {i.name: i for i in self.get_interfaces(o)} if not ifmap: self.stdout.write("No ifaces on object\n") continue tps = self.get_interface_template(ifmap.values()) proccessed = set() selectors_skipping = set() # if selectors has not match cdb = o.get_confdb() ifprofilemap = {} for icr in InterfaceClassificationRule.objects.filter( is_active=True).order_by("order"): if icr.selector.id in selectors_skipping: continue r = next(cdb.query(icr.selector.get_confdb_query), None) if r is None: # Selectors already fail check selectors_skipping.add(icr.selector.id) continue self.print("[%s] Check selector" % icr) for match in cdb.query(icr.get_confdb_query): if match["ifname"] in proccessed or match[ "ifname"] not in ifmap: continue self.print("[%s] Match %s" % (icr, match["ifname"])) iface = ifmap[match["ifname"]] proccessed.add(match["ifname"]) if iface.profile_locked: continue ifprofilemap[iface.name] = icr.profile # Set profile for ifname in ifmap: i = ifmap[ifname] if ifname in ifprofilemap and i.profile.id != ifprofilemap[ ifname].id: i.profile = ifprofilemap[ifname] i.save() v = "Set %s" % ifprofilemap[ifname].name elif ifname in ifprofilemap and i.profile.id == ifprofilemap[ ifname].id: v = "Already set %s" % ifprofilemap[ifname].name else: v = "Not matched" if kwargs.get( "reset_default") and i.profile != default_profile: i.profile = default_profile i.save() v = "Not matched. Reset to default" self.show_interface(tps, i, v)
def handle_reset(self, moo, *args, **kwargs): for o in self.get_objects(moo): self.stdout.write( "%s (%s):\n" % (o.name, (o.platform.name if o.platform else None) or o.profile.name)) for i in Interface.objects.filter(managed_object=o.id): if i.profile: self.stdout.write( " resetting profile on %s to default\n" % i.name) i.profile = InterfaceProfile.get_default_profile() i.save()
class Command(BaseCommand): help = "Show Links" def_iface_prof = InterfaceProfile.get_by_name("default") def add_arguments(self, parser): subparsers = parser.add_subparsers(dest="cmd") # extract command show_parser = subparsers.add_parser("show", help="Show interface profiles") show_parser.add_argument("mos", nargs=argparse.REMAINDER, help="List of object to showing") # clean command reset_parser = subparsers.add_parser("reset", help="Reset interface profile") reset_parser.add_argument("mos", nargs=argparse.REMAINDER, help="List of object to showing") # load command apply_parser = subparsers.add_parser("apply", help="Apply classification rules") apply_parser.add_argument("mos", nargs=argparse.REMAINDER, help="List of object to showing") def handle(self, cmd, *args, **options): if "mos" in options: moo = options["mos"] else: self.stdout.write("No ManagedObject for proccessed") self.die("No ManagedObject for proccessed") return False return getattr(self, "handle_%s" % cmd)(moo, *args, **options) @staticmethod def get_objects(exprs): objects = set() for s in exprs: objects.update(ManagedObjectSelector.resolve_expression(s)) return sorted(objects, key=lambda x: x.name) @staticmethod def get_interfaces(mo): return sorted(Interface.objects.filter(managed_object=mo.id, type="physical"), key=split_alnum) @staticmethod def get_interface_template(interfaces): il = max(len(i.name) for i in interfaces) il = max(il, 15) tps = " %%-%ds %%-12s %%-30s %%s\n" % il return tps def show_interface(self, tpl, i, status): if i.description: d = i.description[:30] else: d = "" self.stdout.write(tpl % (i.name, i.status, d, status)) def handle_show(self, moo, *args, **options): for o in self.get_objects(moo): self.stdout.write( "%s (%s):\n" % (o.name, (o.platform.name if o.platform else None) or o.profile.name)) ifaces = self.get_interfaces(o) if not ifaces: self.stdout.write("No ifaces on object\n") continue tps = self.get_interface_template(ifaces) for i in ifaces: self.show_interface(tps, i, i.profile.name if i.profile else "-") def handle_reset(self, moo, *args, **kwargs): for o in self.get_objects(moo): self.stdout.write( "%s (%s):\n" % (o.name, (o.platform.name if o.platform else None) or o.profile.name)) for i in Interface.objects.filter(managed_object=o.id): if i.profile: self.stdout.write( " resetting profile on %s to default\n" % i.name) i.profile = self.def_iface_prof i.save() def handle_apply(self, moo, *args, **kwargs): # sol = config.get("interface_discovery", "get_interface_profile") # @todo Classification pyrule get_profile = None if not get_profile: get_profile = InterfaceClassificationRule get_profile = get_profile.get_classificator() # raise CommandError("No classification solution") pcache = {} for o in self.get_objects(moo): self.stdout.write( "%s (%s):\n" % (o.name, o.platform.name if o.platform else o.profile.name)) ifaces = self.get_interfaces(o) if not ifaces: self.stdout.write("No ifaces on object\n") continue tps = self.get_interface_template(ifaces) for i in ifaces: if not i.profile or not i.profile_locked: pn = get_profile(i) if pn: p = pcache.get(pn) if not p: p = InterfaceProfile.get_by_id(pn) pcache[pn] = p i.profile = p i.save() v = "Set %s" % p.name else: v = "Not matched" self.show_interface(tps, i, v)
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
class CheckLinkJob(AlarmJob): name = "check_link" map_task = "get_interface_status" def get_map_task_params(self): return {"interface": self.data["interface"]} def handler(self, object, result): """ Process result like <object>, [{'interface': 'Gi 1/0', 'status': True}] :param object: :param result: :return: """ self.logger.debug("check_link returns %s (checking %s)", result, self.data) for r in result: if (r["status"] and r["interface"] == self.data["interface"]): self.clear_alarm("Interface '%s' is up" % (self.data["interface"])) break return True def get_effective_intervals(self): def parse(x): x = x.strip() if not x: return [] parts = [p.strip() for p in x.split(",")] if not parts: return [] if len(parts) % 2: self.error( "Invalid interval description '%s': Must be even size" % x) return [] try: parts = [int(p) if p else None for p in parts] except ValueError, why: self.error("Invalid interval description '%s': %s" % (x, why)) return [] if parts[-2] is not None: self.error( "Invalid interval description '%s': Next to last element must be empty" ) return [] # @todo: Check times are in ascending order # @todo: Check for additional Nones return parts mo = self.get_managed_object() ifname = mo.profile.convert_interface_name(self.data["interface"]) iface = Interface.objects.get(managed_object=mo.id, name=ifname).first() # Check interface profile first if iface and iface.profile: if iface.profile.check_link_interval: return parse(iface.profile.check_link_interval) # Check Managed object's profile if mo.object_profile.check_link_interval: return parse(iface.profile.check_link_interval) # Fallback to default interface profile # when interface profile doesn't set if iface and not iface.profile: dp = InterfaceProfile.get_default_profile() if dp and dp.check_link_interval: return parse(dp.check_link_interval) # Job disabled return []