def init_plugin(self): super(ConduitsPlugin, self).init_plugin() self.add_view("api_plugin_%s_get_neighbors" % self.name, self.api_get_neighbors, url="^(?P<id>[0-9a-f]{24})/plugin/%s/get_neighbors/$" % self.name, method=["GET"]) self.add_view( "api_plugin_%s_create_ducts" % self.name, self.api_create_ducts, url="^(?P<id>[0-9a-f]{24})/plugin/%s/$" % self.name, method=["POST"], validate={ "ducts": DictListParameter( attrs={ "target": DocumentParameter(Object), "project_distance": FloatParameter(), "conduits": DictListParameter( attrs={ "id": DocumentParameter(Object, required=False), "n": IntParameter(), "x": IntParameter(), "y": IntParameter(), "status": BooleanParameter() }) }) }) # self.conduits_model = ObjectModel.objects.filter( name=self.CONDUITS_MODEL).first()
def test_dictlist_parameter(): assert DictListParameter().clean([{ "1": 2 }, { "2": 3, "4": 1 }]) == [{ "1": 2 }, { "2": 3, "4": 1 }] assert DictListParameter(attrs={ "i": IntParameter(), "s": StringParameter() }).clean([{ "i": 10, "s": "ten" }, { "i": "5", "s": "five" }]) == [{ "i": 10, "s": "ten" }, { "i": 5, "s": "five" }] assert DictListParameter(attrs={ "i": IntParameter(), "s": StringParameter() }, convert=True).clean({ "i": "10", "s": "ten" }) == [{ "i": 10, "s": "ten" }]
from noc.core.clickhouse.connect import ClickhouseClient from noc.core.clickhouse.error import ClickhouseError from noc.sa.models.profile import Profile from ..base import NBIAPI Request = DictParameter( attrs={ "from": DateTimeShiftParameter(required=True), "to": DateTimeShiftParameter(required=True), "metrics": DictListParameter( attrs={ "object": StringParameter(required=True), "interfaces": StringListParameter(required=False), "metric_types": StringListParameter(required=True), }, required=True, ), }) S_INTERFACE = "interface" class ObjectMetricsAPI(NBIAPI): name = "objectmetrics" @authenticated @tornado.gen.coroutine def post(self): code, result = yield self.executor.submit(self.handler)
def test_dictlist_parameter(raw, config, expected): assert DictListParameter(**config).clean(raw) == expected
class ProbeApplication(ExtDocApplication): """ PMProbe application """ title = "Probe" menu = "Setup | Probes" model = Probe query_fields = ["name"] REFRESH_CHUNK = config.getint("pm", "expired_refresh_chunk") REFRESH_TIMEOUT = config.getint("pm", "expired_refresh_timeout") @view(url="^(?P<name>[^/]+)/(?P<instance>\d+)/config/$", method=["GET"], validate={"last": DateTimeParameter(required=False)}, access="config", api=True) def api_config(self, request, name, instance, last=None): """ Get full probe configuration """ probe = self.get_object_or_404(Probe, name=name) if not probe.user or request.user.id != probe.user.id: return self.response_forbidden() instance = int(instance) if instance >= probe.n_instances: return self.response_not_found("Invalid instance") probe_id = str(probe.id) now = datetime.datetime.now() # Refresh expired congfigs t0 = time.time() nr = 0 dt = 0 stopped = False for pc in ProbeConfig.objects.filter(probe_id=probe_id, instance_id=instance, expire__lt=now): pc.refresh() nr += 1 if nr % self.REFRESH_CHUNK: # Check execution time dt = time.time() - t0 if dt > self.REFRESH_TIMEOUT: self.logger.info( "%d configs has been refreshed in %s seconds. Giving up", nr, dt) stopped = True break if nr and not stopped: self.logger.info("%d configs has been refreshed in %s seconds.", nr, dt) # Get configs q = {"probe_id": probe_id, "instance_id": instance} if last: fmt = "%Y-%m-%dT%H:%M:%S.%f" if "." in last else "%Y-%m-%dT%H:%M:%S" last = datetime.datetime.strptime(last, fmt) q["changed"] = {"$gte": last} config = [{ "uuid": pc["uuid"], "handler": pc["handler"], "interval": pc["interval"], "metrics": [{ "metric": m["metric"], "metric_type": m["metric_type"], "thresholds": m["thresholds"], "convert": m["convert"], "scale": m["scale"], "collectors": { "policy": m["collectors"]["policy"], "write_concern": m["collectors"]["write_concern"], "collectors": [{ "proto": c["proto"], "address": c["address"], "port": c["port"] } for c in m["collectors"]["collectors"]] } } for m in pc["metrics"]], "config": pc["config"], "managed_object": pc.get("managed_object", None), "changed": pc["changed"].isoformat(), "expire": pc["expire"].isoformat() } for pc in ProbeConfig._get_collection().find(q)] if config: expire = min(c["expire"] for c in config) # Wipe out deleted configs deleted = [ c["uuid"] for c in config if c["changed"] == c["expire"] ] if deleted: ProbeConfig.objects.filter(uuid__in=deleted).delete() else: expire = None return { "now": now.isoformat(), "last": last.isoformat() if last else None, "expire": expire, "config": config } @view(url="^(?P<name>[^/]+)/(?P<instance>\d+)/feed/$", method=["POST"], validate={ "thresholds": DictListParameter( attrs={ "managed_object": IntParameter(), "metric": StringParameter(), "metric_type": StringParameter(), "ts": IntParameter(), "value": FloatParameter(), "old_state": StringParameter(), "new_state": StringParameter() }) }, access="config", api=True) def api_fmfeed(self, request, name, instance, thresholds): if thresholds: cnt = itertools.count() batch = NewEvent._get_collection().initialize_unordered_bulk_op() for t in thresholds: seq = struct.pack("!II", int(time.time()), cnt.next() & 0xFFFFFFFFL) batch.insert({ "timestamp": datetime.datetime.fromtimestamp(t["ts"]), "managed_object": t["managed_object"], "raw_vars": { "source": "system", "metric": t["metric"], "metric_type": t["metric_type"], "value": str(t["value"]), "old_state": t["old_state"], "new_state": t["new_state"] }, "seq": Binary(seq) }) batch.execute(0)
from noc.sa.interfaces.base import DictListParameter, ObjectIdParameter, BooleanParameter from noc.core.bi.decorator import bi_sync from noc.ip.models.prefixprofile import PrefixProfile from noc.ip.models.addressprofile import AddressProfile from noc.vc.models.vpnprofile import VPNProfile from noc.main.models.extstorage import ExtStorage from noc.main.models.template import Template from noc.core.datastream.decorator import datastream from noc.cm.models.objectvalidationpolicy import ObjectValidationPolicy from .authprofile import AuthProfile from .capsprofile import CapsProfile m_valid = DictListParameter( attrs={ "metric_type": ObjectIdParameter(required=True), "enable_box": BooleanParameter(default=False), "enable_periodic": BooleanParameter(default=True), "is_stored": BooleanParameter(default=True), "threshold_profile": ObjectIdParameter(required=False), }) id_lock = Lock() @on_init @on_save @bi_sync @datastream @on_delete_check(check=[ ("sa.ManagedObject", "object_profile"), ("sa.ManagedObjectProfile", "cpe_profile"), ("sa.ManagedObjectSelector", "filter_object_profile"),
class ValidationPolicySettingsApplication(ExtDocApplication): """ ValidationPolicySettings application """ title = _("Validation Policy Settings") model = ValidationPolicySettings MODEL_SCOPES = { "sa.ManagedObject": 2, "sa.ManagedObjectProfile": 2, "inv.Interface": 2, "inv.InterfaceProfile": 2, } @view( "^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["GET"], access="read", api=True, ) def api_get_settings(self, request, model_id, object_id): if model_id not in self.MODEL_SCOPES: return self.response_not_found("Invalid model") o = ValidationPolicySettings.objects.filter( model_id=model_id, object_id=object_id).first() if o: # Policy settings return [{ "policy": str(p.policy.id), "policy__label": p.policy.name, "is_active": p.is_active, } for p in o.policies] else: return {} @view( "^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["POST"], access="read", api=True, validate={ "policies": DictListParameter( attrs={ "policy": DocumentParameter(ValidationPolicy), "is_active": BooleanParameter(), }) }, ) def api_save_settings(self, request, model_id, object_id, policies): def save_settings(o): o.save() return self.response({"status": True}, self.OK) o = ValidationPolicySettings.objects.filter( model_id=model_id, object_id=object_id).first() seen = set() ps = [] for p in policies: if p["policy"].id in seen: continue ps += [ ValidationPolicyItem(policy=p["policy"], is_active=p["is_active"]) ] seen.add(p["policy"].id) if o: o.policies = ps else: o = ValidationPolicySettings(model_id=model_id, object_id=object_id, policies=ps) self.submit_slow_op(request, save_settings, o)
StringListParameter, IntParameter, ListOfParameter, ListParameter, ) from noc.pm.models.metrictype import MetricType from ..base import NBIAPI Request = DictParameter( attrs={ "bi_id": IntParameter(required=True), "metrics": DictListParameter( attrs={ "metric_type": StringParameter(required=True), "path": StringListParameter(required=True), "values": ListOfParameter(ListParameter(), required=True), }, required=True, ), } ) class TelemetryAPI(NBIAPI): name = "telemetry" @authenticated @tornado.gen.coroutine def post(self): code, result = yield self.executor.submit(self.handler) self.set_status(code)
class WorkflowApplication(ExtDocApplication): """ Workflow application """ title = _("Workflows") menu = [_("Setup"), _("Workflow")] model = Workflow NEW_ID = "000000000000000000000000" @view(r"^(?P<id>[0-9a-f]{24})/config/", method=["GET"], access="write", api=True) def api_get_config(self, request, id): wf = self.get_object_or_404(Workflow, id=id) r = { "id": str(wf.id), "name": wf.name, "is_active": wf.is_active, "description": wf.description, "states": [], "transitions": [], } for state in State.objects.filter(workflow=wf.id): sr = { "id": str(state.id), "name": state.name, "description": state.description, "is_default": state.is_default, "is_productive": state.is_productive, "update_last_seen": state.update_last_seen, "ttl": state.ttl, "update_expired": state.update_expired, "on_enter_handlers": state.on_enter_handlers, "job_handler": state.job_handler, "on_leave_handlers": state.on_leave_handlers, "bi_id": str(state.bi_id) if state.bi_id else None, "x": state.x, "y": state.y, } r["states"] += [sr] for t in Transition.objects.filter(workflow=wf.id): tr = { "id": str(t.id), "from_state": t.from_state.name, "to_state": t.to_state.name, "is_active": t.is_active, "event": t.event, "label": t.label, "description": t.description, "enable_manual": t.enable_manual, "handlers": t.handlers, "vertices": [{ "x": v.x, "y": v.y } for v in t.vertices], "bi_id": str(t.bi_id) if t.bi_id else None, } r["transitions"] += [tr] return r @view( r"^(?P<id>[0-9a-f]{24})/config/", method=["POST"], access="write", api=True, validate={ "name": StringParameter(), "description": StringParameter(default=""), "is_active": BooleanParameter(default=False), "states": DictListParameter( attrs={ "id": StringParameter(default=""), "name": StringParameter(), "description": StringParameter(default=""), "is_default": BooleanParameter(default=False), "is_productive": BooleanParameter(default=False), "update_last_seen": BooleanParameter(default=False), "ttl": IntParameter(default=0), "update_expired": BooleanParameter(default=False), "on_enter_handlers": StringListParameter(), "job_handler": StringParameter(required=False), "on_leave_handlers": StringListParameter(), "x": IntParameter(), "y": IntParameter(), }), "transitions": DictListParameter( attrs={ "id": StringParameter(default=""), "from_state": StringParameter(), "to_state": StringParameter(), "is_active": BooleanParameter(default=False), "event": StringParameter(), "label": StringParameter(), "description": StringParameter(default=""), "enable_manual": BooleanParameter(), "handlers": StringListParameter(), "vertices": DictListParameter(attrs={ "x": IntParameter(), "y": IntParameter() }), }), }, ) def api_save_config(self, request, id, name, description, states, transitions, **kwargs): if id == self.NEW_ID: wf = Workflow() else: wf = self.get_object_or_404(Workflow, id=id) # Update workflow wf.name = name wf.description = description wf.save() # Get current state current_states = {} # str(id) -> state for st in State.objects.filter(workflow=wf.id): current_states[str(st.id)] = st # Synchronize states seen_states = set() state_names = {} # name -> state for s in states: state = None if s["id"]: # Existing state seen_states.add(s["id"]) state = current_states.get(s["id"]) if not hasattr(s, "workflow"): s["workflow"] = wf.id # Update state attributes if not state: state = State() changed = True else: changed = False for k in s: if k in ("id", "bi_id"): continue if getattr(state, k) != s[k]: setattr(state, k, s[k]) changed = True if changed: state.save() state_names[state.name] = state # Get current transitions current_transitions = {} # str(id) -> transition for ct in Transition.objects.filter(workflow=wf.id): current_transitions[str(ct.id)] = ct # Synchronize transitions seen_transitions = set() for t in transitions: transition = None if t["id"]: # Existing transitions seen_transitions.add(t["id"]) transition = current_transitions.get(t["id"]) # Update transition attributes if not transition: transition = Transition(workflow=wf) changed = True else: changed = False for k in t: if k in ("id", "bi_id"): continue elif k in ("from_state", "to_state"): t[k] = state_names[t[k]] elif k == "vertices": t[k] = [ TransitionVertex(x=vx["x"], y=vx["y"]) for vx in t[k] ] old = getattr(transition, k) if old != t[k]: setattr(transition, k, t[k]) changed = True if changed: transition.save() # Delete hanging transitions for tid in set(current_transitions) - seen_transitions: current_transitions[tid].delete() # Delete hanging state for sid in set(current_states) - seen_states: current_states[sid].delete() rx_clone_name = re.compile(r"\(Copy #(\d+)\)$") @view(r"^(?P<id>[0-9a-f]{24})/clone/", method=["POST"], access="write", api=True) def api_clone(self, request, id): wf = self.get_object_or_404(Workflow, id=id) # Get all clone names m = 0 for d in Workflow._get_collection().find( { "name": { "$regex": re.compile( r"^%s\(Copy #\d+\)$" % re.escape(wf.name)) } }, { "_id": 0, "name": 1 }, ): match = self.rx_clone_name.search(d["name"]) if match: n = int(match.group(1)) if n > m: m = n # Generate name name = "%s (Copy #%d)" % (wf.name, m + 1) # Clone workflow new_wf = deepcopy(wf) new_wf.name = name new_wf.id = None new_wf.bi_id = None new_wf.save() # Clone states smap = {} # old id -> new state for state in State.objects.filter(workflow=wf.id): new_state = deepcopy(state) new_state.workflow = new_wf new_state.id = None new_state.bi_id = None new_state.save() smap[state.id] = new_state # Clone transitions for transition in Transition.objects.filter(workflow=wf.id): new_transition = deepcopy(transition) new_transition.workflow = new_wf new_transition.from_state = smap[transition.from_state.id] new_transition.to_state = smap[transition.to_state.id] new_transition.id = None new_transition.bi_id = None new_transition.save() # return {"id": str(new_wf.id)}
from noc.sa.interfaces.base import DictListParameter, DictParameter, IntParameter, StringParameter from noc.core.perf import metrics from noc.core.translation import ugettext as _ # Access items validations I_VALID = DictListParameter( attrs={ "group": DictParameter( attrs={ "id": IntParameter(required=True), "name": StringParameter(required=False) }, required=False, ), "user": DictParameter( attrs={ "id": IntParameter(required=True), "name": StringParameter(required=False) }, required=False, ), "level": IntParameter(min_value=-1, max_value=3, default=-1), }) ds_lock = threading.Lock() model_lock = threading.Lock()
class MapApplication(ExtApplication): """ inv.net application """ title = _("Network Map") menu = _("Network Map") glyph = "globe" implied_permissions = {"launch": ["inv:networksegment:lookup"]} # Object statuses ST_UNKNOWN = 0 # Object state is unknown ST_OK = 1 # Object is OK ST_ALARM = 2 # Object is reachable, Active alarms ST_UNREACH = 3 # Object is unreachable due to other's object failure ST_DOWN = 4 # Object is down ST_MAINTENANCE = 32 # Maintenance bit @view(r"^(?P<id>[0-9a-f]{24})/data/$", method=["GET"], access="read", api=True) def api_data(self, request, id): def q_mo(d): x = d.copy() if x["type"] == "managedobject": del x["mo"] x["external"] = x["id"] not in mos if is_view else x.get( "role") != "segment" elif d["type"] == "cloud": del x["link"] x["external"] = False return x # Find segment segment = self.get_object_or_404(NetworkSegment, id=id) if segment.managed_objects.count() > segment.max_objects: # Too many objects return { "id": str(segment.id), "name": segment.name, "error": _("Too many objects") } # if we set selector in segment is_view = segment.selector if is_view: mos = segment.selector.managed_objects.values_list("id", flat=True) # Load settings settings = MapSettings.objects.filter(segment=id).first() node_hints = {} link_hints = {} if settings: self.logger.info("Using stored positions") for n in settings.nodes: node_hints[n.id] = { "type": n.type, "id": n.id, "x": n.x, "y": n.y } for ll in settings.links: link_hints[ll.id] = { "connector": ll.connector if len(ll.vertices) else "normal", "vertices": [{ "x": v.x, "y": v.y } for v in ll.vertices], } else: self.logger.info("Generating positions") # Generate topology topology = SegmentTopology( segment, node_hints, link_hints, force_spring=request.GET.get("force") == "spring") topology.layout() # Build output r = { "id": str(segment.id), "max_links": int(segment.max_shown_downlinks), "name": segment.name, "caps": list(topology.caps), "nodes": [q_mo(x) for x in topology.G.nodes.values()], "links": [topology.G[u][v] for u, v in topology.G.edges()], } # Parent info if segment.parent: r["parent"] = { "id": str(segment.parent.id), "name": segment.parent.name } # Save settings if not settings: self.logger.debug("Saving first-time layout") MapSettings.load_json({ "id": str(segment.id), "nodes": [{ "type": n["type"], "id": n["id"], "x": n["x"], "y": n["y"] } for n in r["nodes"] if n.get("x") is not None and n.get("y") is not None], "links": [{ "type": n["type"], "id": n["id"], "vertices": n.get("vertices", []), "connector": n.get("connector", "normal"), } for n in r["links"]], }) return r @view(r"^(?P<id>[0-9a-f]{24})/data/$", method=["POST"], access="write", api=True) def api_save(self, request, id): self.get_object_or_404(NetworkSegment, id=id) data = self.deserialize(request.body) data["id"] = id MapSettings.load_json(data, request.user.username) return {"status": True} @view(url=r"^(?P<id>[0-9a-f]{24})/info/segment/$", method=["GET"], access="read", api=True) def api_info_segment(self, request, id): segment = self.get_object_or_404(NetworkSegment, id=id) r = { "name": segment.name, "description": segment.description, "objects": segment.managed_objects.count(), } return r @view( url=r"^(?P<id>[0-9a-f]{24})/info/managedobject/(?P<mo_id>\d+)/$", method=["GET"], access="read", api=True, ) def api_info_managedobject(self, request, id, mo_id): segment = self.get_object_or_404(NetworkSegment, id=id) object = self.get_object_or_404(ManagedObject, id=int(mo_id)) s = {1: "telnet", 2: "ssh", 3: "http", 4: "https"}[object.scheme] r = { "id": object.id, "name": object.name, "description": object.description, "address": object.address, "platform": object.platform.full_name if object.platform else "", "profile": object.profile.name, "external": object.segment.id != segment.id, "external_segment": { "id": str(object.segment.id), "name": object.segment.name }, "caps": object.get_caps(), "console_url": "%s://%s/" % (s, object.address), } return r @view( url=r"^(?P<id>[0-9a-f]{24})/info/link/(?P<link_id>[0-9a-f]{24})/$", method=["GET"], access="read", api=True, ) def api_info_link(self, request, id, link_id): def q(s): if isinstance(s, str): s = s.encode("utf-8") return s self.get_object_or_404(NetworkSegment, id=id) link = self.get_object_or_404(Link, id=link_id) r = { "id": str(link.id), "name": link.name or None, "description": link.description or None, "objects": [], "method": link.discovery_method, } o = defaultdict(list) for i in link.interfaces: o[i.managed_object] += [i] for mo in sorted(o, key=lambda x: x.name): r["objects"] += [{ "id": mo.id, "name": mo.name, "interfaces": [{ "name": i.name, "description": i.description or None, "status": i.status } for i in sorted(o[mo], key=lambda x: alnum_key(x.name))], }] # Get link bandwidth mo_in = defaultdict(float) mo_out = defaultdict(float) mos = [ManagedObject.get_by_id(mo["id"]) for mo in r["objects"]] metric_map, last_ts = get_interface_metrics(list(o)) for mo in o: if mo not in metric_map: continue for i in o[mo]: if i.name not in metric_map[mo]: continue mo_in[mo] += metric_map[mo][i.name]["Interface | Load | In"] mo_out[mo] += metric_map[mo][i.name]["Interface | Load | Out"] if len(mos) == 2: mo1, mo2 = mos r["utilisation"] = [ int(max(mo_in[mo1], mo_out[mo2])), int(max(mo_in[mo2], mo_out[mo1])), ] else: mv = list(mo_in.values()) + list(mo_out.values()) if mv: r["utilisation"] = [int(max(mv))] else: r["utilisation"] = 0 return r @view( url=r"^(?P<id>[0-9a-f]{24})/info/cloud/(?P<link_id>[0-9a-f]{24})/$", method=["GET"], access="read", api=True, ) def api_info_cloud(self, request, id, link_id): self.get_object_or_404(NetworkSegment, id=id) link = self.get_object_or_404(Link, id=link_id) r = { "id": str(link.id), "name": link.name or None, "description": link.description or None, "objects": [], "method": link.discovery_method, } o = defaultdict(list) for i in link.interfaces: o[i.managed_object] += [i] for mo in sorted(o, key=lambda x: x.name): r["objects"] += [{ "id": mo.id, "name": mo.name, "interfaces": [{ "name": i.name, "description": i.description or None, "status": i.status } for i in sorted(o[mo], key=lambda x: alnum_key(x.name))], }] return r @view( url=r"^objects_statuses/$", method=["POST"], access="read", api=True, validate={"objects": ListOfParameter(IntParameter())}, ) def api_objects_statuses(self, request, objects: List[int]): def get_alarms(objects: List[int]) -> Set[int]: """ Returns a set of objects with alarms """ alarms: Set[int] = set() coll = ActiveAlarm._get_collection() while objects: chunk, objects = objects[:500], objects[500:] a = coll.aggregate([ { "$match": { "managed_object": { "$in": chunk } } }, { "$group": { "_id": "$managed_object", "count": { "$sum": 1 } } }, ]) alarms.update(d["_id"] for d in a) return alarms def get_maintenance(objects: List[int]) -> Set[int]: """ Returns a set of objects currently in maintenance :param objects: :return: """ now = datetime.datetime.now() so = set(objects) mnt_objects = set() pipeline = [ { "$match": { "affected_objects.object": { "$in": list(so) } } }, { "$unwind": "$affected_objects" }, { "$lookup": { "from": "noc.maintenance", "as": "m", "let": { "maintenance": "_id" }, "pipeline": [{ "$match": { "m.is_completed": False, "m.start": { "$lte": now }, "m.stop": { "gte": now }, }, }], }, }, { "$project": { "_id": 0, "object": "$affected_objects.object", } }, { "$group": { "_id": "$object" } }, ] mnt_objects |= so & { x["_id"] for x in AffectedObjects._get_collection().aggregate(pipeline) } return mnt_objects # Mark all as unknown r = {o: self.ST_UNKNOWN for o in objects} sr = ObjectStatus.get_statuses(objects) sa = get_alarms(objects) mo = get_maintenance(objects) for o in sr: if sr[o]: # Check for alarms if o in sa: r[o] = self.ST_ALARM else: r[o] = self.ST_OK else: r[o] = self.ST_DOWN if o in mo: r[o] |= self.ST_MAINTENANCE return r @classmethod @cachedmethod(key="managedobject-name-to-id-%s", lock=lambda _: tags_lock) def managedobject_name_to_id(cls, name): r = ManagedObject.objects.filter(name=name).values_list("id") if r: return r[0][0] return None @classmethod @cachedmethod(key="interface-tags-to-id-%s-%s", lock=lambda _: tags_lock) 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 @view( url=r"^metrics/$", method=["POST"], access="read", api=True, validate={ "metrics": DictListParameter( attrs={ "id": StringParameter(), "metric": StringParameter(), "tags": DictParameter(), }) }, ) 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 @view(r"^(?P<id>[0-9a-f]{24})/data/$", method=["DELETE"], access="write", api=True) def api_reset(self, request, id): self.get_object_or_404(NetworkSegment, id=id) MapSettings.objects.filter(segment=id).delete() return {"status": True} @view( url=r"^stp/status/$", method=["POST"], access="read", api=True, validate={"objects": ListOfParameter(IntParameter())}, ) def api_objects_stp_status(self, request, objects): def get_stp_status(object_id): roots = set() blocked = set() object = ManagedObject.get_by_id(object_id) sr = object.scripts.get_spanning_tree() for instance in sr["instances"]: ro = DiscoveryID.find_object(instance["root_id"]) if ro: roots.add(ro) for i in instance["interfaces"]: if i["state"] == "discarding" and i["role"] == "alternate": iface = object.get_interface(i["interface"]) if iface: link = iface.link if link: blocked.add(str(link.id)) return object_id, roots, blocked r = {"roots": [], "blocked": []} futures = [] with ThreadPoolExecutor(max_workers=10) as executor: for o in objects: futures += [executor.submit(get_stp_status, o)] for future in as_completed(futures): try: obj, roots, blocked = future.result() for ro in roots: if ro.id not in r["roots"]: r["roots"] += [ro.id] r["blocked"] += blocked except Exception as e: self.logger.error("[stp] Exception: %s", e) return r
from noc.core.datastream.decorator import datastream from .authprofile import AuthProfile from .capsprofile import CapsProfile m_valid = DictListParameter(attrs={ "metric_type": ObjectIdParameter(required=True), "enable_box": BooleanParameter(default=False), "enable_periodic": BooleanParameter(default=True), "is_stored": BooleanParameter(default=True), "window_type": StringParameter( choices=["m", "t"], default="m"), "window": IntParameter(default=1), "window_function": StringParameter(choices=[x[0] for x in wf_choices], default="last"), "window_config": StringParameter(default=""), "window_related": BooleanParameter(default=False), "low_error": IntParameter(required=False), "high_error": IntParameter(required=False), "low_warn": IntParameter(required=False), "high_warn": IntParameter(required=False), "low_error_weight": IntParameter(default=10), "low_warn_weight": IntParameter(default=1), "high_warn_weight": IntParameter(default=1), "high_error_weight": IntParameter(default=10), "threshold_profile": ObjectIdParameter(required=False) }) id_lock = Lock() @on_init
class MetricSettingsApplication(ExtDocApplication): """ MetricSettings application """ title = "Metric Settings" model = MetricSettings @view("^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["GET"], access="read", api=True) def api_get_settings(self, request, model_id, object_id): o = MetricSettings.objects.filter(model_id=model_id, object_id=object_id).first() if o: return [{ "metric_set": str(ms.metric_set.id), "metric_set__label": ms.metric_set.name, "is_active": ms.is_active } for ms in o.metric_sets] else: return [] @view("^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/settings/$", method=["POST"], access="read", api=True, validate={ "metric_sets": DictListParameter( attrs={ "metric_set": DocumentParameter(MetricSet), "is_active": BooleanParameter() }) }) def api_save_settings(self, request, model_id, object_id, metric_sets): def save_settings(o): o.save() return self.response({"status": True}, self.OK) o = MetricSettings.objects.filter(model_id=model_id, object_id=object_id).first() seen = set() mset = [] for ms in metric_sets: if ms["metric_set"].id in seen: continue mset += [ MetricSettingsItem(metric_set=ms["metric_set"], is_active=ms["is_active"]) ] seen.add(ms["metric_set"].id) if o: o.metric_sets = mset else: o = MetricSettings(model_id=model_id, object_id=object_id, metric_sets=mset) self.submit_slow_op(request, save_settings, o) @view("^(?P<model_id>[^/]+)/(?P<object_id>[^/]+)/effective/trace/$", method=["GET"], access="read", api=True) def api_trace_effective(self, request, model_id, object_id): o = MetricSettings(model_id=model_id, object_id=object_id).get_object() if not o: return self.response_not_found() r = [] for es in MetricSettings.get_effective_settings(o, trace=True, recursive=True): for m in es.metrics: r += [{ "metric": m.metric or None, "metric_type": m.metric_type.name, "is_active": es.is_active, "probe": es.probe.name if es.probe else None, "interval": es.interval if es.interval else None, "thresholds": m.thresholds, "handler": es.handler, "config": es.config, "errors": es.errors, "traces": es.traces }] return r