Esempio n. 1
0
    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
Esempio n. 2
0
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):
Esempio n. 3
0
# 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))
Esempio n. 4
0
def test_stringlist_parameter(raw, config, expected):
    assert StringListParameter(**config).clean(raw) == expected
Esempio n. 5
0
    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)
Esempio n. 6
0
File: views.py Progetto: nbashev/noc
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)}
Esempio n. 7
0
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)
Esempio n. 8
0
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
Esempio n. 9
0
def test_stringlist_parameter():
    assert StringListParameter().clean(["1", "2", "3"]) == ["1", "2", "3"]
    assert StringListParameter().clean(["1", 2, "3"]) == ["1", "2", "3"]