def get_validator(self, field): """ Returns Parameter instance or None to clean up field :param field: :type field: Field :return: """ from noc.core.model.fields import TagsField, TextArrayField if isinstance(field, BooleanField): return BooleanParameter() elif isinstance(field, IntegerField): return IntParameter() elif isinstance(field, FloatField): return FloatParameter() elif isinstance(field, DateField): return DateParameter() elif isinstance(field, DateTimeField): return DateTimeParameter() elif isinstance(field, TagsField): return TagsParameter(required=not field.null) elif isinstance(field, TextArrayField): return StringListParameter(required=not field.null) elif isinstance(field, related.ForeignKey): self.fk_fields[field.name] = field.remote_field.model return ModelParameter(field.remote_field.model, required=not field.null) else: return None
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):
# Python modules from __future__ import absolute_import # Third-party modules import tornado.gen import ujson import six # NOC modules from noc.core.service.apiaccess import authenticated from noc.sa.interfaces.base import DictParameter, StringListParameter from noc.sa.models.objectstatus import ObjectStatus from ..base import NBIAPI Request = DictParameter(attrs={"objects": StringListParameter(required=True)}) class ObjectStatusAPI(NBIAPI): name = "objectstatus" @authenticated @tornado.gen.coroutine def post(self): code, result = yield self.executor.submit(self.handler) self.set_status(code) if isinstance(result, six.string_types): self.write(result) else: self.write(ujson.dumps(result))
def test_stringlist_parameter(raw, config, expected): assert StringListParameter(**config).clean(raw) == expected
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)
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 error import ModelDataError from noc.lib.utils import deep_copy from noc.lib.escape import json_escape as q from noc.sa.interfaces.base import (StringParameter, BooleanParameter, FloatParameter, IntParameter, StringListParameter) id_lock = Lock() T_MAP = { "str": StringParameter(), "int": IntParameter(), "float": FloatParameter(), "bool": BooleanParameter(), "strlist": StringListParameter() } A_TYPE = ["str", "int", "float", "bool", "objectid", "ref", "strlist"] class ModelInterfaceAttr(EmbeddedDocument): meta = { "strict": False, "auto_create_index": False } name = StringField() type = StringField(choices=[(t, t) for t in A_TYPE]) description = StringField() required = BooleanField(default=False) is_const = BooleanField(default=False)
class AlarmApplication(ExtApplication): """ fm.alarm application """ title = _("Alarm") menu = _("Alarms") glyph = "exclamation-triangle" implied_permissions = {"launch": ["sa:managedobject:alarm"]} model_map = {"A": ActiveAlarm, "C": ArchivedAlarm} clean_fields = { "managed_object": ModelParameter(ManagedObject), "timestamp": DateTimeParameter(), } ignored_params = ["status", "_dc"] diagnostic_plugin = AlarmPlugin(name="diagnostic", config={}) advanced_filter_params = { "service_profile": "total_services", "subscribers_profile": "total_subscribers", "profile": get_advanced_field, } DEFAULT_ARCH_ALARM = datetime.timedelta( seconds=config.web.api_arch_alarm_limit) rx_oper_splitter = re.compile(r"^(?P<field>\S+)(?P<f_num>\d+)__in") def __init__(self, *args, **kwargs): ExtApplication.__init__(self, *args, **kwargs) from .plugins.base import AlarmPlugin # Load plugins self.plugins = {} for f in os.listdir("services/web/apps/fm/alarm/plugins/"): if not f.endswith(".py") or f == "base.py" or f.startswith("_"): continue mn = "noc.services.web.apps.fm.alarm.plugins.%s" % f[:-3] m = __import__(mn, {}, {}, "*") for on in dir(m): o = getattr(m, on) if (inspect.isclass(o) and issubclass(o, AlarmPlugin) and o.__module__.startswith(mn)): assert o.name self.plugins[o.name] = o(self) def cleaned_query(self, q): q = q.copy() status = q["status"] if "status" in q else "A" for p in self.ignored_params: if p in q: del q[p] for p in ( self.limit_param, self.page_param, self.start_param, self.format_param, self.sort_param, self.query_param, self.only_param, ): if p in q: del q[p] # Extract IN # extjs not working with same parameter name in query for p in list(q): if p.endswith("__in") and self.rx_oper_splitter.match(p): field = self.rx_oper_splitter.match(p).group("field") + "__in" if field not in q: q[field] = [q[p]] else: q[field] += [q[p]] del q[p] # Normalize parameters for p in list(q): qp = p.split("__")[0] if qp in self.clean_fields: q[p] = self.clean_fields[qp].clean(q[p]) # Advanced filter for p in self.advanced_filter_params: params = [] for x in list(q): if x.startswith(p): params += [q[x]] del q[x] if params: af = self.advanced_filter(self.advanced_filter_params[p], params) if "__raw__" in q and "__raw__" in af: # Multiple raw query q["__raw__"].update(af["__raw__"]) del af["__raw__"] q.update(af) # Exclude maintenance if "maintenance" not in q: q["maintenance"] = "hide" if q["maintenance"] == "hide" and status == "A": q["managed_object__nin"] = Maintenance.currently_affected() elif q["maintenance"] == "only" and status == "A": q["managed_object__in"] = Maintenance.currently_affected() del q["maintenance"] if "administrative_domain" in q: if q["administrative_domain"] != "_root_": q["adm_path"] = int(q["administrative_domain"]) q.pop("administrative_domain") if "administrative_domain__in" in q: if "_root_" not in q["administrative_domain__in"]: q["adm_path__in"] = q["administrative_domain__in"] q.pop("administrative_domain__in") if "segment" in q: if q["segment"] != "_root_": q["segment_path"] = bson.ObjectId(q["segment"]) q.pop("segment") if "managedobjectselector" in q: s = SelectorCache.objects.filter( selector=q["managedobjectselector"]).values_list("object") if "managed_object__in" in q: q["managed_object__in"] = list( set(q["managed_object__in"]).intersection(s)) else: q["managed_object__in"] = s q.pop("managedobjectselector") if "cleared_after" in q: q["clear_timestamp__gte"] = datetime.datetime.now( ) - datetime.timedelta(seconds=int(q["cleared_after"])) q.pop("cleared_after") # if "wait_tt" in q: q["wait_tt__exists"] = True q["wait_ts__exists"] = False del q["wait_tt"] # if "collapse" in q: c = q["collapse"] del q["collapse"] if c != "0": q["root__exists"] = False if status == "C": if ("timestamp__gte" not in q and "timestamp__lte" not in q and "escalation_tt__contains" not in q and "managed_object" not in q): q["timestamp__gte"] = datetime.datetime.now( ) - self.DEFAULT_ARCH_ALARM return q def advanced_filter(self, field, params): """ Field: field0=ProfileID,field1=ProfileID:true.... cq - caps query mq - main_query field0=ProfileID - Profile is exists field0=!ProfileID - Profile is not exists field0=ProfileID:true - Summary value equal True field0=ProfileID:2~50 - Summary value many then 2 and less then 50 :param field: Query Field name :param params: Query params :return: """ q = {} c_in = [] c_nin = [] for c in params: if not c: continue if "!" in c: # @todo Добавить исключение (только этот) !ID c_id = c[1:] c_query = "nexists" elif ":" not in c: c_id = c c_query = "exists" else: c_id, c_query = c.split(":", 1) try: if callable(field): field, c_id = field(c_id) c_id = bson.ObjectId(c_id) except bson.errors.InvalidId as e: self.logger.warning(e) continue if "~" in c_query: l, r = c_query.split("~") if not l: cond = {"$lte": int(r)} elif not r: cond = {"$gte": int(l)} else: cond = {"$lte": int(r), "$gte": int(l)} q["__raw__"] = { field: { "$elemMatch": { "profile": c_id, "summary": cond } } } elif c_query == "exists": c_in += [c_id] continue elif c_query == "nexists": c_nin += [c_id] continue else: try: c_query = int(c_query) q["__raw__"] = { field: { "$elemMatch": { "profile": c_id, "summary": int(c_query) } } } except ValueError: q["__raw__"] = { field: { "$elemMatch": { "profile": c_id, "summary": { "$regex": c_query } } } } if c_in: q["%s__profile__in" % field] = c_in if c_nin: q["%s__profile__nin" % field] = c_nin return q def instance_to_dict(self, o, fields=None): s = AlarmSeverity.get_severity(o.severity) n_events = (ActiveEvent.objects.filter(alarms=o.id).count() + ArchivedEvent.objects.filter(alarms=o.id).count()) d = { "id": str(o.id), "status": o.status, "managed_object": o.managed_object.id, "managed_object__label": o.managed_object.name, "administrative_domain": o.managed_object.administrative_domain_id, "administrative_domain__label": o.managed_object.administrative_domain.name, "severity": o.severity, "severity__label": s.name, "alarm_class": str(o.alarm_class.id), "alarm_class__label": o.alarm_class.name, "timestamp": self.to_json(o.timestamp), "subject": o.subject, "events": n_events, "duration": o.duration, "clear_timestamp": self.to_json(o.clear_timestamp) if o.status == "C" else None, "row_class": s.style.css_class_name, "segment__label": o.managed_object.segment.name, "segment": str(o.managed_object.segment.id), "location_1": self.location(o.managed_object.container.id)[0] if o.managed_object.container else "", "location_2": self.location(o.managed_object.container.id)[1] if o.managed_object.container else "", "escalation_tt": o.escalation_tt, "escalation_error": o.escalation_error, "platform": o.managed_object.platform.name if o.managed_object.platform else "", "address": o.managed_object.address, "ack_ts": self.to_json(o.ack_ts), "ack_user": o.ack_user, "summary": self.f_glyph_summary({ "subscriber": SummaryItem.items_to_dict(o.total_subscribers), "service": SummaryItem.items_to_dict(o.total_services), }), "total_objects": sum(x.summary for x in o.total_objects), "total_subscribers": self.f_summary( {"subscriber": SummaryItem.items_to_dict(o.total_subscribers)}), "total_services": self.f_summary( {"service": SummaryItem.items_to_dict(o.total_services)}), "logs": [{ "timestamp": self.to_json(ll.timestamp), "user": ll.source or "NOC", "message": ll.message, } for ll in o.log if getattr(ll, "source", None) ][:config.web.api_alarm_comments_limit], } if fields: d = {k: d[k] for k in fields} return d def queryset(self, request, query=None): """ Filter records for lookup """ status = request.GET.get("status", "A") if status not in self.model_map: raise Exception("Invalid status") model = self.model_map[status] if request.user.is_superuser: return model.objects.filter().read_preference( ReadPreference.SECONDARY_PREFERRED).all() else: return model.objects.filter(adm_path__in=UserAccess.get_domains( request.user), ).read_preference( ReadPreference.SECONDARY_PREFERRED) @view(url=r"^$", access="launch", method=["GET"], api=True) def api_list(self, request): return self.list_data(request, self.instance_to_dict) @view(url=r"^(?P<id>[a-z0-9]{24})/$", method=["GET"], api=True, access="launch") def api_alarm(self, request, id): alarm = get_alarm(id) if not alarm: self.response_not_found() user = request.user d = self.instance_to_dict(alarm) d["body"] = alarm.body d["symptoms"] = alarm.alarm_class.symptoms d["probable_causes"] = alarm.alarm_class.probable_causes d["recommended_actions"] = alarm.alarm_class.recommended_actions d["vars"] = sorted(alarm.vars.items()) d["status"] = alarm.status d["status__label"] = {"A": "Active", "C": "Cleared"}[alarm.status] # Managed object properties mo = alarm.managed_object d["managed_object_address"] = mo.address d["managed_object_profile"] = mo.profile.name d["managed_object_platform"] = mo.platform.name if mo.platform else "" d["managed_object_version"] = mo.version.version if mo.version else "" d["segment"] = mo.segment.name d["segment_id"] = str(mo.segment.id) d["segment_path"] = " | ".join( NetworkSegment.get_by_id(p).name for p in NetworkSegment.get_path(mo.segment)) if mo.container: cp = [] c = mo.container.id while c: try: o = Object.objects.get(id=c) if o.container: cp.insert(0, o.name) c = o.container.id if o.container else None except DoesNotExist: break d["container_path"] = " | ".join(cp) if not self.location(mo.container.id)[0]: d["address_path"] = None else: d["address_path"] = ", ".join(self.location(mo.container.id)) d["tags"] = mo.labels # Log if alarm.log: d["log"] = [{ "timestamp": self.to_json(ll.timestamp), "from_status": ll.from_status, "to_status": ll.to_status, "source": getattr(ll, "source", ""), "message": ll.message, } for ll in alarm.log] # Events events = [] for ec in ActiveEvent, ArchivedEvent: for e in ec.objects.filter(alarms=alarm.id): events += [{ "id": str(e.id), "event_class": str(e.event_class.id), "event_class__label": e.event_class.name, "timestamp": self.to_json(e.timestamp), "status": e.status, "managed_object": e.managed_object.id, "managed_object__label": e.managed_object.name, "subject": e.subject, }] if events: d["events"] = events # Alarms children = self.get_nested_alarms(alarm) if children: d["alarms"] = {"expanded": True, "children": children} # Subscribers if alarm.status == "A": d["subscribers"] = self.get_alarm_subscribers(alarm) d["is_subscribed"] = user in alarm.subscribers # Apply plugins plugins = [] acp = alarm.alarm_class.plugins or [] acp += [self.diagnostic_plugin] for p in acp: if p.name in self.plugins: plugin = self.plugins[p.name] dd = plugin.get_data(alarm, p.config) if "plugins" in dd: plugins += dd["plugins"] del dd["plugins"] d.update(dd) if plugins: d["plugins"] = plugins return d def get_alarm_subscribers(self, alarm): """ JSON-serializable subscribers :param alarm: :return: """ subscribers = [] for u in alarm.subscribers: try: u = User.objects.get(id=u) subscribers += [{ "id": u.id, "name": " ".join([u.first_name, u.last_name]), "login": u.username }] except User.DoesNotExist: pass return subscribers def get_nested_alarms(self, alarm): """ Return nested alarms as a part of NodeInterface :param alarm: :return: """ children = [] for ac in (ActiveAlarm, ArchivedAlarm): for a in ac.objects.filter(root=alarm.id): s = AlarmSeverity.get_severity(a.severity) c = { "id": str(a.id), "subject": a.subject, "alarm_class": str(a.alarm_class.id), "alarm_class__label": a.alarm_class.name, "managed_object": a.managed_object.id, "managed_object__label": a.managed_object.name, "timestamp": self.to_json(a.timestamp), "iconCls": "icon_error", "row_class": s.style.css_class_name, } nc = self.get_nested_alarms(a) if nc: c["children"] = nc c["expanded"] = True else: c["leaf"] = True children += [c] return children @view( url=r"^(?P<id>[a-z0-9]{24})/post/", method=["POST"], api=True, access="launch", validate={"msg": UnicodeParameter()}, ) def api_post(self, request, id, msg): alarm = get_alarm(id) if not alarm: self.response_not_found() alarm.log_message(msg, source=request.user.username) return True @view( url=r"^comment/post/", method=["POST"], api=True, access="launch", validate={ "ids": StringListParameter(required=True), "msg": UnicodeParameter(), }, ) def api_comment_post(self, request, ids, msg): alarms = list(ActiveAlarm.objects.filter(id__in=ids)) alarms += list(ArchivedAlarm.objects.filter(id__in=ids)) if not alarms: self.response_not_found() for alarm in alarms: alarm.log_message(msg, source=request.user.username) return True @view( url=r"^(?P<id>[a-z0-9]{24})/acknowledge/", method=["POST"], api=True, access="acknowledge", validate={ "msg": UnicodeParameter(default=""), }, ) def api_acknowledge(self, request, id, msg=""): alarm = get_alarm(id) if not alarm: return self.response_not_found() if alarm.status != "A": return self.response_not_found() if alarm.ack_ts: return { "status": False, "message": "Already acknowledged by %s" % alarm.ack_user } alarm.acknowledge(request.user, msg) return {"status": True} @view( url=r"^(?P<id>[a-z0-9]{24})/unacknowledge/", method=["POST"], api=True, access="acknowledge", validate={ "msg": UnicodeParameter(default=""), }, ) def api_unacknowledge(self, request, id, msg=""): alarm = get_alarm(id) if not alarm: return self.response_not_found() if alarm.status != "A": return self.response_not_found() if not alarm.ack_ts: return {"status": False, "message": "Already unacknowledged"} alarm.unacknowledge(request.user, msg=msg) return {"status": True} @view(url=r"^(?P<id>[a-z0-9]{24})/subscribe/", method=["POST"], api=True, access="launch") def api_subscribe(self, request, id): alarm = get_alarm(id) if not alarm: return self.response_not_found() if alarm.status == "A": alarm.subscribe(request.user) return self.get_alarm_subscribers(alarm) else: return [] @view(url=r"^(?P<id>[a-z0-9]{24})/unsubscribe/", method=["POST"], api=True, access="launch") def api_unsubscribe(self, request, id): alarm = get_alarm(id) if not alarm: return self.response_not_found() if alarm.status == "A": alarm.unsubscribe(request.user) return self.get_alarm_subscribers(alarm) else: return [] @view( url=r"^(?P<id>[a-z0-9]{24})/clear/", method=["POST"], api=True, access="launch", validate={ "msg": UnicodeParameter(default=""), }, ) def api_clear(self, request, id, msg=""): alarm = get_alarm(id) if not alarm.alarm_class.user_clearable: return {"status": False, "error": "Deny clear alarm by user"} if alarm.status == "A": alarm.clear_alarm("Cleared by %s: %s" % (request.user, msg), source=request.user.username) return True @view( url=r"^(?P<id>[a-z0-9]{24})/set_root/", method=["POST"], api=True, access="launch", validate={"root": StringParameter()}, ) def api_set_root(self, request, id, root): alarm = get_alarm(id) r = get_alarm(root) if not r: return self.response_not_found() alarm.set_root(r) return True @view(url=r"notification/$", method=["GET"], api=True, access="launch") def api_notification(self, request): delta = request.GET.get("delta") n = 0 sound = None volume = 0 if delta: dt = datetime.timedelta(seconds=int(delta)) t0 = datetime.datetime.now() - dt r = list(ActiveAlarm._get_collection().aggregate([ { "$match": { "timestamp": { "$gt": t0 } } }, { "$group": { "_id": "$item", "severity": { "$max": "$severity" } } }, ])) if r: s = AlarmSeverity.get_severity(r[0]["severity"]) if s and s.sound and s.volume: sound = "/ui/pkg/nocsound/%s.mp3" % s.sound volume = float(s.volume) / 100.0 return {"new_alarms": n, "sound": sound, "volume": volume} @classmethod def f_glyph_summary(cls, s, collapse=False): def be_true(p): return True def be_show(p): return p.show_in_summary def get_summary(d, profile): v = [] if hasattr(profile, "show_in_summary"): show_in_summary = be_show else: show_in_summary = be_true for p, c in d.items(): pv = profile.get_by_id(p) if pv and show_in_summary(pv): if collapse and c < 2: badge = "" else: badge = '<span class="x-display-tag">%s</span>' % c order = getattr(pv, "display_order", 100) v += [( (order, -c), '<i class="%s" title="%s"></i>%s' % (pv.glyph, pv.name, badge), )] return "<span class='x-summary'>%s</span>" % "".join( i[1] for i in sorted(v, key=operator.itemgetter(0))) if not isinstance(s, dict): return "" r = [] if "subscriber" in s: from noc.crm.models.subscriberprofile import SubscriberProfile r += [get_summary(s["subscriber"], SubscriberProfile)] if "service" in s: from noc.sa.models.serviceprofile import ServiceProfile r += [get_summary(s["service"], ServiceProfile)] r = [x for x in r if x] return "".join(r) @view(url=r"^(?P<id>[a-z0-9]{24})/escalate/", method=["GET"], api=True, access="escalate") def api_escalation_alarm(self, request, id): alarm = get_alarm(id) if alarm.status == "A": AlarmEscalation.watch_escalations(alarm) return {"status": True} else: return { "status": False, "error": "The alarm is not active at the moment" } def location(self, id): """ Return geo address for Managed Objects """ def chunkIt(seq, num): avg = len(seq) / float(num) out = [] last = 0.0 while last < len(seq): out.append(seq[int(last):int(last + avg)]) last += avg return out location = [] address = Object.get_by_id(id).get_address_text() if address: for res in address.split(","): adr = normalize_division(smart_text(res).strip().lower()) if None in adr and "" in adr: continue if None in adr: location += [adr[1].title().strip()] else: location += [" ".join(adr).title().strip()] res = chunkIt(location, 2) location_1 = ", ".join(res[0]) location_2 = ", ".join(res[1]) return [location_1, location_2] return ["", ""] @classmethod def f_summary(cls, s): def be_true(p): return True def be_show(p): return p.show_in_summary def get_summary(d, profile): v = [] if hasattr(profile, "show_in_summary"): show_in_summary = be_show else: show_in_summary = be_true for p, c in sorted(d.items(), key=lambda x: -x[1]): pv = profile.get_by_id(p) if pv and show_in_summary(pv): v += [{ "profile": str(pv.id), "glyph": pv.glyph, "display_order": pv.display_order, "profile__label": pv.name, "summary": c, }] return v if not isinstance(s, dict): return "" r = [] if "subscriber" in s: from noc.crm.models.subscriberprofile import SubscriberProfile r += get_summary(s["subscriber"], SubscriberProfile) if "service" in s: from noc.sa.models.serviceprofile import ServiceProfile r += get_summary(s["service"], ServiceProfile) r = [x for x in r if x] return r def bulk_field_isinmaintenance(self, data): if not data: return data if data[0]["status"] == "A": mtc = set(Maintenance.currently_affected()) for x in data: x["isInMaintenance"] = x["managed_object"] in mtc else: mos = set([x["managed_object"] for x in data]) mtc = {} for mo in list(mos): interval = [] for ao in AffectedObjects._get_collection().find( {"affected_objects.object": { "$eq": mo }}, { "_id": 0, "maintenance": 1 }): m = Maintenance.get_by_id(ao["maintenance"]) interval += [(m.start, m.stop)] if interval: mtc[mo] = interval for x in data: if x["managed_object"] in mtc: left, right = list(zip(*mtc[x["managed_object"]])) x["isInMaintenance"] = bisect.bisect( right, dateutil.parser.parse(x["timestamp"]).replace( tzinfo=None)) != bisect.bisect( left, dateutil.parser.parse( x["clear_timestamp"]).replace(tzinfo=None)) else: x["isInMaintenance"] = False return data @view(url=r"profile_lookup/$", access="launch", method=["GET"], api=True) def api_profile_lookup(self, request): r = [] for model, short_type, field_id in ( (ServiceProfile, _("Service"), "total_services"), (SubscriberProfile, _("Subscribers"), "total_subscribers"), ): # "%s|%s" % (field_id, r += [{ "id": str(o.id), "type": short_type, "display_order": o.display_order, "icon": o.glyph, "label": o.name, } for o in model.objects.all() if getattr(o, "show_in_summary", True)] return r
def test_stringlist_parameter(): assert StringListParameter().clean(["1", "2", "3"]) == ["1", "2", "3"] assert StringListParameter().clean(["1", 2, "3"]) == ["1", "2", "3"]