Ejemplo n.º 1
0
 def lookup_vcfilter(self, q, name, value):
     """
     Resolve __vcflter lookups
     :param q:
     :param name:
     :param value:
     :return:
     """
     value = ModelParameter(VCFilter).clean(value)
     x = value.to_sql(name)
     try:
         q[None] += [x]
     except KeyError:
         q[None] = [x]
Ejemplo n.º 2
0
class NotificationGroupApplication(ExtModelApplication):
    """
    NotificationGroup application
    """

    title = _("Notification Group")
    menu = [_("Setup"), _("Notification Groups")]
    model = NotificationGroup
    glyph = "envelope-o"

    users = ModelInline(NotificationGroupUser)
    other = ModelInline(NotificationGroupOther)

    @view(
        url="^actions/test/$",
        method=["POST"],
        access="update",
        api=True,
        validate={
            "ids": ListOfParameter(element=ModelParameter(NotificationGroup)),
            "subject": UnicodeParameter(),
            "body": UnicodeParameter(),
        },
    )
    def api_action_test(self, request, ids, subject, body):
        for g in ids:
            g.notify(subject=subject, body=body)
        return "Notification message has been sent"
Ejemplo n.º 3
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
Ejemplo n.º 4
0
Archivo: views.py Proyecto: nbashev/noc
class TimePatternApplication(ExtModelApplication):
    """
    TimePattern application
    """

    title = _("Time Pattern")
    menu = [_("Setup"), _("Time Patterns")]
    model = TimePattern
    glyph = "clock-o"

    terms = ModelInline(TimePatternTerm)

    @view(
        url="^actions/test/",
        method=["POST"],
        access="read",
        api=True,
        validate={
            "ids": ListOfParameter(element=ModelParameter(TimePattern)),
            "date": StringParameter(required=True),
            "time": StringParameter(required=True),
        },
    )
    def api_action_test(self, request, ids, date=None, time=None):
        d = "%sT%s" % (date, time)
        dt = datetime.datetime.strptime(d, "%Y-%m-%dT%H:%M")
        return {
            "ts":
            dt.isoformat(),
            "result": [{
                "id": p.id,
                "name": p.name,
                "result": p.match(dt)
            } for p in ids],
        }
Ejemplo n.º 5
0
class PrefixTableApplication(ExtModelApplication):
    """
    PrefixTable application
    """

    title = _("Prefix Table")
    menu = [_("Setup"), _("Prefix Tables")]
    model = PrefixTable

    prefixes = ModelInline(PrefixTablePrefix)

    @view(
        url="^actions/test/$",
        method=["POST"],
        access="update",
        api=True,
        validate={
            "ids": ListOfParameter(element=ModelParameter(PrefixTable)),
            "ip": IPParameter()
        },
    )
    def api_action_test(self, request, ids, ip):
        return {
            "ip":
            ip,
            "result": [{
                "id": pt.id,
                "name": pt.name,
                "result": ip in pt
            } for pt in ids],
        }
Ejemplo n.º 6
0
 def api_action_group_edit(self, request):
     validator = DictParameter(
         attrs={"ids": ListOfParameter(element=ModelParameter(self.model), convert=True)}
     )
     rv = self.deserialize(request.body)
     try:
         v = validator.clean(rv)
     except InterfaceTypeError as e:
         self.logger.info("Bad request: %r (%s)", request.body, e)
         return self.render_json(
             {"status": False, "message": "Bad request", "traceback": str(e)},
             status=self.BAD_REQUEST,
         )
     objects = v["ids"]
     del v["ids"]
     try:
         v = self.clean(v)
     except ValueError as e:
         return self.render_json(
             {"status": False, "message": "Bad request", "traceback": str(e)},
             status=self.BAD_REQUEST,
         )
     for o in objects:
         for p in v:
             setattr(o, p, v[p])
         o.save()
     return "%d records has been updated" % len(objects)
Ejemplo n.º 7
0
Archivo: views.py Proyecto: nbashev/noc
class VRFApplication(ExtModelApplication):
    """
    VRF application
    """

    title = _("VRF")
    menu = _("VRF")
    model = VRF
    query_fields = ["name", "rd", "description"]

    mrt_config = {
        "get_vrfs": {
            "map_script": "get_mpls_vpn",
            "access": "import"
        }
    }

    def field_row_class(self, o):
        return o.profile.style.css_class_name if o.profile.style else ""

    def clean(self, data):
        if not data.get("vpn_id"):
            vdata = {"type": "VRF", "name": data["name"], "rd": data.get("rd")}
            data["vpn_id"] = get_vpn_id(vdata)
        return super().clean(data)

    @view(
        url="^bulk/import/$",
        method=["POST"],
        access="import",
        api=True,
        validate={
            "items":
            ListOfParameter(element=DictParameter(
                attrs={
                    "name": StringParameter(),
                    "rd": RDParameter(),
                    "vrf_group": ModelParameter(model=VRFGroup),
                    "afi_ipv4": BooleanParameter(default=False),
                    "afi_ipv6": BooleanParameter(default=False),
                    "description": StringParameter(required=False),
                }))
        },
    )
    def api_bulk_import(self, request, items):
        n = 0
        for i in items:
            if not VRF.objects.filter(name=i["name"], rd=i["rd"]).exists():
                # Add only new
                VRF(
                    name=i["name"],
                    vrf_group=i["vrf_group"],
                    rd=i["rd"],
                    afi_ipv4=i["afi_ipv4"],
                    afi_ipv6=i["afi_ipv6"],
                    description=i.get("description"),
                ).save()
                n += 1
        return {"status": True, "imported": n}
Ejemplo n.º 8
0
class ASSetApplication(ExtModelApplication):
    """
    ASSet application
    """
    title = "AS Sets"
    menu = "AS Sets"
    model = ASSet
    query_fields = ["name__icontains","description__icontains",
                    "members__icontains"]


    @view(url="^actions/rpsl/$", method=["POST"],
        access="read", api=True,
        validate={
            "ids": ListOfParameter(element=ModelParameter(ASSet))
        })

    def api_action_rpsl(self,request,ids):
        return "</br></br>".join([o.rpsl.replace("\n", "</br>") for o in ids])
    api_action_rpsl.short_description="RPSL for selected objects"
Ejemplo n.º 9
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 AutoCompleteTagsField

        if isinstance(field, BooleanField):
            return BooleanParameter()
        elif isinstance(field, IntegerField):
            return IntParameter()
        elif isinstance(field, FloatField):
            return FloatParameter()
        elif isinstance(field, AutoCompleteTagsField):
            return TagsParameter(required=not field.null)
        elif isinstance(field, related.ForeignKey):
            self.fk_fields[field.name] = field.rel.to
            return ModelParameter(field.rel.to, required=not field.null)
        else:
            return None
Ejemplo n.º 10
0
class PrefixListBuilderApplication(ExtApplication):
    """
    Interactive prefix list builder
    """
    title = "Prefix List Builder"
    menu = "Prefix List Builder"
    # implied_permissions = {
    #    "read": ["peer:peeringpoint:lookup"]
    #}

    @view(method=["GET"],
          url=r"^$",
          access="read",
          api=True,
          validate={
              "peering_point": ModelParameter(PeeringPoint),
              "name": UnicodeParameter(required=False),
              "as_set": UnicodeParameter()
          })
    def api_list(self, request, peering_point, name, as_set):
        prefixes = WhoisCache.resolve_as_set_prefixes_maxlen(as_set)
        pl = peering_point.profile.generate_prefix_list(name, prefixes)
        return {"name": name, "prefix_list": pl, "success": True}
Ejemplo n.º 11
0
class ManagedObjectApplication(ExtModelApplication):
    """
    ManagedObject application
    """

    title = _("Managed Objects")
    menu = _("Managed Objects")
    model = ManagedObject
    query_condition = "icontains"
    query_fields = ["name", "description"]
    secret_fields = {"password", "super_password", "snmp_ro", "snmp_rw"}
    # Inlines
    attrs = ModelInline(ManagedObjectAttribute)
    cfg = RepoInline("config", access="config")

    extra_permissions = ["alarm", "change_interface"]
    implied_permissions = {
        "read": ["inv:networksegment:lookup", "main:handler:lookup"]
    }
    diverged_permissions = {"config": "read", "console": "script"}
    order_map = {
        "address":
        " cast_test_to_inet(address) ",
        "-address":
        " cast_test_to_inet(address) ",
        "profile":
        "CASE %s END" % " ".join([
            "WHEN %s='%s' THEN %s" % ("profile", pk, i) for i, pk in enumerate(
                Profile.objects.filter().order_by("name").values_list("id"))
        ]),
        "-profile":
        "CASE %s END" % " ".join([
            "WHEN %s='%s' THEN %s" % ("profile", pk, i) for i, pk in enumerate(
                Profile.objects.filter().order_by("-name").values_list("id"))
        ]),
        "platform":
        "CASE %s END" % " ".join([
            "WHEN %s='%s' THEN %s" % ("platform", pk, i)
            for i, pk in enumerate(Platform.objects.filter().order_by(
                "name").values_list("id"))
        ]),
        "-platform":
        "CASE %s END" % " ".join([
            "WHEN %s='%s' THEN %s" % ("platform", pk, i)
            for i, pk in enumerate(Platform.objects.filter().order_by(
                "-name").values_list("id"))
        ]),
        "version":
        "CASE %s END" % " ".join([
            "WHEN %s='%s' THEN %s" % ("version", pk, i)
            for i, pk in enumerate(Firmware.objects.filter().order_by(
                "version").values_list("id"))
        ]),
        "-version":
        "CASE %s END" % " ".join([
            "WHEN %s='%s' THEN %s" % ("version", pk, i)
            for i, pk in enumerate(Firmware.objects.filter().order_by(
                "-version").values_list("id"))
        ]),
    }
    resource_group_fields = [
        "static_service_groups",
        "effective_service_groups",
        "static_client_groups",
        "effective_client_groups",
    ]

    DISCOVERY_JOBS = [
        ("box", "noc.services.discovery.jobs.box.job.BoxDiscoveryJob"),
        ("periodic",
         "noc.services.discovery.jobs.periodic.job.PeriodicDiscoveryJob"),
    ]

    def field_row_class(self, o):
        return o.object_profile.style.css_class_name if o.object_profile.style else ""

    def bulk_field_interface_count(self, data):
        """
        Apply interface_count fields
        :param data:
        :return:
        """
        mo_ids = [x["id"] for x in data]
        if not mo_ids:
            return data
        # Collect interface counts
        r = Interface._get_collection().aggregate([
            {
                "$match": {
                    "managed_object": {
                        "$in": mo_ids
                    },
                    "type": "physical"
                }
            },
            {
                "$group": {
                    "_id": "$managed_object",
                    "total": {
                        "$sum": 1
                    }
                }
            },
        ])
        ifcount = dict((x["_id"], x["total"]) for x in r)
        # Apply interface counts
        for x in data:
            x["interface_count"] = ifcount.get(x["id"]) or 0
        return data

    def bulk_field_link_count(self, data):
        """
        Apply link_count fields
        :param data:
        :return:
        """
        mo_ids = [x["id"] for x in data]
        if not mo_ids:
            return data
        # Collect interface counts
        r = Link._get_collection().aggregate([
            {
                "$match": {
                    "linked_objects": {
                        "$in": mo_ids
                    }
                }
            },
            {
                "$unwind": "$linked_objects"
            },
            {
                "$group": {
                    "_id": "$linked_objects",
                    "total": {
                        "$sum": 1
                    }
                }
            },
        ])
        links_count = dict((x["_id"], x["total"]) for x in r)
        # Apply interface counts
        for x in data:
            x["link_count"] = links_count.get(x["id"]) or 0
        return data

    def instance_to_dict(self, o, fields=None):
        def sg_to_list(items):
            return [{
                "group": x,
                "group__label": unicode(ResourceGroup.get_by_id(x))
            } for x in items]

        data = super(ManagedObjectApplication,
                     self).instance_to_dict(o, fields)
        # Expand resource groups fields
        for fn in self.resource_group_fields:
            data[fn] = sg_to_list(data.get(fn) or [])
        return data

    def clean(self, data):
        # Clean resource groups
        for fn in self.resource_group_fields:
            if fn.startswith("effective_") and fn in data:
                del data[fn]
                continue
            data[fn] = [x["group"] for x in (data.get(fn) or [])]
        # Clean other
        return super(ManagedObjectApplication, self).clean(data)

    def cleaned_query(self, q):
        if "administrative_domain" in q:
            ad = AdministrativeDomain.get_nested_ids(
                int(q["administrative_domain"]))
            if ad:
                del q["administrative_domain"]
        else:
            ad = None
        if "selector" in q:
            s = self.get_object_or_404(ManagedObjectSelector,
                                       id=int(q["selector"]))
            del q["selector"]
        else:
            s = None
        r = super(ManagedObjectApplication, self).cleaned_query(q)
        if s:
            r["id__in"] = ManagedObject.objects.filter(s.Q)
        if ad:
            r["administrative_domain__in"] = ad
        return r

    def get_Q(self, request, query):
        q = super(ManagedObjectApplication, self).get_Q(request, query)
        sq = ManagedObject.get_search_Q(query)
        if sq:
            q |= sq
        return q

    def queryset(self, request, query=None):
        qs = super(ManagedObjectApplication, self).queryset(request, query)
        if not request.user.is_superuser:
            qs = qs.filter(UserAccess.Q(request.user))
        qs = qs.exclude(name__startswith="wiping-")
        return qs

    @view(url=r"^(?P<id>\d+)/links/$", method=["GET"], access="read", api=True)
    def api_links(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        # Get links
        result = []
        for link in Link.object_links(o):
            ifaces = []
            r = []
            for i in link.interfaces:
                if i.managed_object.id == o.id:
                    ifaces += [i]
                else:
                    r += [i]
            for li, ri in zip(ifaces, r):
                result += [{
                    "link_id":
                    str(link.id),
                    "local_interface":
                    str(li.id),
                    "local_interface__label":
                    li.name,
                    "remote_object":
                    ri.managed_object.id,
                    "remote_object__label":
                    ri.managed_object.name,
                    "remote_platform":
                    ri.managed_object.platform.name
                    if ri.managed_object.platform else "",
                    "remote_interface":
                    str(ri.id),
                    "remote_interface__label":
                    ri.name,
                    "discovery_method":
                    link.discovery_method,
                    "local_description":
                    li.description,
                    "remote_description":
                    ri.description,
                    "first_discovered":
                    link.first_discovered.isoformat()
                    if link.first_discovered else None,
                    "last_seen":
                    link.last_seen.isoformat() if link.last_seen else None,
                }]
        return result

    @view(url=r"^(?P<id>\d+)/discovery/$",
          method=["GET"],
          access="read",
          api=True)
    def api_discovery(self, request, id):
        from noc.core.scheduler.job import Job

        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        link_count = defaultdict(int)
        for link in Link.object_links(o):
            m = link.discovery_method or ""
            if "+" in m:
                m = m.split("+")[0]
            link_count[m] += 1
        r = [{
            "name": "ping",
            "enable_profile": o.object_profile.enable_ping,
            "status": o.get_status(),
            "last_run": None,
            "last_status": None,
            "next_run": None,
            "jcls": None,
        }]

        for name, jcls in self.DISCOVERY_JOBS:
            job = Job.get_job_data(
                "discovery", jcls=jcls, key=o.id, pool=o.pool.name) or {}
            d = {
                "name":
                name,
                "enable_profile":
                getattr(o.object_profile, "enable_%s_discovery" % name),
                "status":
                job.get(Job.ATTR_STATUS),
                "last_run":
                self.to_json(job.get(Job.ATTR_LAST)),
                "last_status":
                job.get(Job.ATTR_LAST_STATUS),
                "next_run":
                self.to_json(job.get(Job.ATTR_TS)),
                "jcls":
                jcls,
            }
            r += [d]
        return r

    @view(
        url=r"^actions/set_managed/$",
        method=["POST"],
        access="create",
        api=True,
        validate={
            "ids":
            ListOfParameter(element=ModelParameter(ManagedObject),
                            convert=True)
        },
    )
    def api_action_set_managed(self, request, ids):
        for o in ids:
            if not o.has_access(request.user):
                continue
            o.is_managed = True
            o.save()
        return "Selected objects set to managed state"

    @view(
        url=r"^actions/set_unmanaged/$",
        method=["POST"],
        access="create",
        api=True,
        validate={
            "ids":
            ListOfParameter(element=ModelParameter(ManagedObject),
                            convert=True)
        },
    )
    def api_action_set_unmanaged(self, request, ids):
        for o in ids:
            if not o.has_access(request.user):
                continue
            o.is_managed = False
            o.save()
        return "Selected objects set to unmanaged state"

    @view(url=r"^(?P<id>\d+)/discovery/run/$",
          method=["POST"],
          access="change_discovery",
          api=True)
    def api_run_discovery(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = ujson.loads(request.body).get("names", [])
        for name, jcls in self.DISCOVERY_JOBS:
            if name not in r:
                continue
            if not getattr(o.object_profile, "enable_%s_discovery" % name):
                continue  # Disabled by profile
            Job.submit("discovery", jcls, key=o.id, pool=o.pool.name)
        return {"success": True}

    @view(url=r"^(?P<id>\d+)/discovery/stop/$",
          method=["POST"],
          access="change_discovery",
          api=True)
    def api_stop_discovery(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = ujson.loads(request.body).get("names", [])
        for name, jcls in self.DISCOVERY_JOBS:
            if name not in r:
                continue
            if not getattr(o.object_profile, "enable_%s_discovery" % name):
                continue  # Disabled by profile
            Job.remove("discovery", jcls, key=o.id, pool=o.pool.name)
        return {"success": True}

    @view(url=r"^(?P<id>\d+)/interface/$",
          method=["GET"],
          access="read",
          api=True)
    def api_interface(self, request, id):
        """
        GET interfaces
        :param managed_object:
        :return:
        """
        def sorted_iname(s):
            return sorted(s, key=lambda x: split_alnum(x["name"]))

        def get_style(i):
            profile = i.profile
            if profile:
                try:
                    return style_cache[profile.id]
                except KeyError:
                    pass
                if profile.style:
                    s = profile.style.css_class_name
                else:
                    s = ""
                style_cache[profile.id] = s
                return s
            else:
                return ""

        def get_link(i):
            link = i.link
            if not link:
                return None
            if link.is_ptp:
                # ptp
                o = link.other_ptp(i)
                label = "%s:%s" % (o.managed_object.name, o.name)
            elif link.is_lag:
                # unresolved LAG
                o = [
                    ii for ii in link.other(i)
                    if ii.managed_object.id != i.managed_object.id
                ]
                label = "LAG %s: %s" % (o[0].managed_object.name, ", ".join(
                    ii.name for ii in o))
            else:
                # Broadcast
                label = ", ".join("%s:%s" % (ii.managed_object.name, ii.name)
                                  for ii in link.other(i))
            return {"id": str(link.id), "label": label}

        # Get object
        o = self.get_object_or_404(ManagedObject, id=int(id))
        if not o.has_access(request.user):
            return self.response_forbidden("Permission denied")
        # Physical interfaces
        # @todo: proper ordering
        default_state = ResourceState.get_default()
        style_cache = {}  # profile_id -> css_style
        l1 = [{
            "id":
            str(i.id),
            "name":
            i.name,
            "description":
            i.description,
            "status":
            i.status,
            "mac":
            i.mac,
            "ifindex":
            i.ifindex,
            "lag":
            (i.aggregated_interface.name if i.aggregated_interface else ""),
            "link":
            get_link(i),
            "profile":
            str(i.profile.id) if i.profile else None,
            "profile__label":
            unicode(i.profile) if i.profile else None,
            "enabled_protocols":
            i.enabled_protocols,
            "project":
            i.project.id if i.project else None,
            "project__label":
            unicode(i.project) if i.project else None,
            "state":
            i.state.id if i.state else default_state.id,
            "state__label":
            unicode(i.state if i.state else default_state),
            "vc_domain":
            i.vc_domain.id if i.vc_domain else None,
            "vc_domain__label":
            unicode(i.vc_domain) if i.vc_domain else None,
            "row_class":
            get_style(i),
        } for i in Interface.objects.filter(managed_object=o.id,
                                            type="physical")]
        # LAG
        lag = [{
            "id":
            str(i.id),
            "name":
            i.name,
            "description":
            i.description,
            "profile":
            str(i.profile.id) if i.profile else None,
            "profile__label":
            unicode(i.profile) if i.profile else None,
            "members": [
                j.name
                for j in Interface.objects.filter(managed_object=o.id,
                                                  aggregated_interface=i.id)
            ],
            "row_class":
            get_style(i),
        } for i in Interface.objects.filter(managed_object=o.id,
                                            type="aggregated")]
        # L2 interfaces
        l2 = [{
            "name": i.name,
            "description": i.description,
            "untagged_vlan": i.untagged_vlan,
            "tagged_vlans": i.tagged_vlans,
        } for i in SubInterface.objects.filter(managed_object=o.id,
                                               enabled_afi="BRIDGE")]
        # L3 interfaces
        q = MQ(enabled_afi="IPv4") | MQ(enabled_afi="IPv6")
        l3 = [{
            "name": i.name,
            "description": i.description,
            "ipv4_addresses": i.ipv4_addresses,
            "ipv6_addresses": i.ipv6_addresses,
            "enabled_protocols": i.enabled_protocols,
            "vlan": i.vlan_ids,
            "vrf": i.forwarding_instance.name if i.forwarding_instance else "",
            "mac": i.mac,
        } for i in SubInterface.objects.filter(managed_object=o.id).filter(q)]
        return {
            "l1": sorted_iname(l1),
            "lag": sorted_iname(lag),
            "l2": sorted_iname(l2),
            "l3": sorted_iname(l3),
        }

    @view(url=r"^(?P<id>\d+)/interface/$",
          method=["POST"],
          access="change_interface",
          api=True)
    def api_set_interface(self, request, id):
        def get_or_none(c, v):
            if not v:
                return None
            return c.objects.get(id=v)

        o = self.get_object_or_404(ManagedObject, id=int(id))
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        d = ujson.loads(request.body)
        if "id" in d:
            i = self.get_object_or_404(Interface, id=d["id"])
            if i.managed_object.id != o.id:
                return self.response_not_found()
            # Set profile
            if "profile" in d:
                p = get_or_none(InterfaceProfile, d["profile"])
                i.profile = p
                if p:
                    i.profile_locked = True
            # Project
            if "project" in d:
                i.project = get_or_none(Project, d["project"])
            # State
            if "state" in d:
                i.state = get_or_none(ResourceState, d["state"])
            # VC Domain
            if "vc_domain" in d:
                i.vc_domain = get_or_none(VCDomain, d["vc_domain"])
            #
            i.save()
        return {"success": True}

    @view(method=["DELETE"], url=r"^(?P<id>\d+)/?$", access="delete", api=True)
    def api_delete(self, request, id):
        """
        Override default method
        :param request:
        :param id:
        :return:
        """
        try:
            o = self.queryset(request).get(id=int(id))
        except self.model.DoesNotExist:
            return self.render_json({
                "status": False,
                "message": "Not found"
            },
                                    status=self.NOT_FOUND)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        # Run sa.wipe_managed_object job instead
        o.name = "wiping-%d" % o.id
        o.is_managed = False
        o.description = "Wiping! Do not touch!"
        o.save()
        call_later("noc.sa.wipe.managedobject.wipe", o=o.id)
        return HttpResponse(status=self.DELETED)

    @view(
        url=r"^actions/run_discovery/$",
        method=["POST"],
        access="launch",
        api=True,
        validate={
            "ids":
            ListOfParameter(element=ModelParameter(ManagedObject),
                            convert=True)
        },
    )
    def api_action_run_discovery(self, request, ids):
        d = 0
        for o in ids:
            if not o.has_access(request.user):
                continue
            o.run_discovery(delta=d)
            d += 1
        return "Discovery processes has been scheduled"

    def get_nested_inventory(self, o):
        rev = o.get_data("asset", "revision")
        if rev == "None":
            rev = ""
        r = {
            "id": str(o.id),
            "serial": o.get_data("asset", "serial"),
            "revision": rev or "",
            "description": o.model.description,
            "model": o.model.name,
        }
        children = []
        for n in o.model.connections:
            if n.direction == "i":
                c, r_object, _ = o.get_p2p_connection(n.name)
                if c is None:
                    children += [{
                        "id": None,
                        "name": n.name,
                        "leaf": True,
                        "serial": None,
                        "description": "--- EMPTY ---",
                        "model": None,
                    }]
                else:
                    cc = self.get_nested_inventory(r_object)
                    cc["name"] = n.name
                    children += [cc]
            elif n.direction == "s":
                children += [{
                    "id": None,
                    "name": n.name,
                    "leaf": True,
                    "serial": None,
                    "description": n.description,
                    "model": ", ".join(n.protocols),
                }]
        if children:
            to_expand = "Transceiver" not in o.model.name
            r["children"] = children
            r["expanded"] = to_expand
        else:
            r["leaf"] = True
        return r

    @view(url=r"^(?P<id>\d+)/inventory/$",
          method=["GET"],
          access="read",
          api=True)
    def api_inventory(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = []
        for p in o.get_inventory():
            c = self.get_nested_inventory(p)
            c["name"] = p.name or o.name
            r += [c]
        return {"expanded": True, "children": r}

    @view(url=r"^(?P<id>\d+)/confdb/$",
          method=["GET"],
          access="config",
          api=True)
    def api_confdb(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        cleanup = True
        if "cleanup" in request.GET:
            c = request.GET["cleanup"].strip().lower()
            cleanup = c not in ("no", "false", "0")
        cdb = o.get_confdb(cleanup=cleanup)
        return self.render_plain_text(cdb.dump("json"),
                                      content_type="text/json")

    @view(
        url=r"^(?P<id>\d+)/confdb/$",
        method=["POST"],
        validate={
            "query": StringParameter(),
            "cleanup": BooleanParameter(default=True),
            "dump": BooleanParameter(default=False),
        },
        access="config",
        api=True,
    )
    def api_confdb_query(self,
                         request,
                         id,
                         query="",
                         cleanup=True,
                         dump=False):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        cdb = o.get_confdb(cleanup=cleanup)
        try:
            r = list(cdb.query(query))
            result = {"status": True, "result": r}
            if dump:
                result["confdb"] = ujson.loads(cdb.dump("json"))
        except SyntaxError as e:
            result = {"status": False, "error": str(e)}
        return result

    @view(url=r"^(?P<id>\d+)/job_log/(?P<job>\S+)/$",
          method=["GET"],
          access="read",
          api=True)
    def api_job_log(self, request, id, job):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        # fs = gridfs.GridFS(get_db(), "noc.joblog")
        key = "discovery-%s-%s" % (job, o.id)
        d = get_db()["noc.joblog"].find_one({"_id": key})
        if d and d["log"]:
            return self.render_plain_text(zlib.decompress(str(d["log"])))
        else:
            return self.render_plain_text("No data")

    @view(url=r"^(?P<id>\d+)/interactions/$",
          method=["GET"],
          access="interactions",
          api=True)
    def api_interactions(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        return [{
            "ts": self.to_json(i.timestamp),
            "op": i.op,
            "user": i.user,
            "text": i.text
        } for i in InteractionLog.objects.filter(
            object=o.id).order_by("-timestamp")]

    @view(url=r"^(?P<id>\d+)/scripts/$",
          method=["GET"],
          access="script",
          api=True)
    def api_scripts(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = []
        for s in o.scripts:
            sn = o.profile.name + "." + s
            script = script_loader.get_script(sn)
            if not script:
                self.logger.error("Failed to load script: %s", sn)
                continue
            interface = script.interface()
            ss = {
                "name":
                s,
                "has_input":
                any(interface.gen_parameters()),
                "require_input":
                interface.has_required_params,
                "form":
                interface.get_form(),
                "preview":
                interface.preview
                or "NOC.sa.managedobject.scripts.JSONPreview",
            }
            r += [ss]
        return r

    @view(url=r"^(?P<id>\d+)/scripts/(?P<name>[^/]+)/$",
          method=["POST"],
          access="script",
          api=True)
    def api_run_script(self, request, id, name):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return {"error": "Access denied"}
        if name not in o.scripts:
            return {"error": "Script not found: %s" % name}
        params = self.deserialize(request.body)
        try:
            result = o.scripts[name](**params)
        except Exception as e:
            return {"error": str(e)}
        return {"result": result}

    @view(url=r"^(?P<id>\d+)/console/$",
          method=["POST"],
          access="console",
          api=True)
    def api_console_command(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return {"error": "Access denied"}
        if "commands" not in o.scripts:
            return {"error": "Script not found: commands"}
        params = self.deserialize(request.body)
        try:
            result = o.scripts.commands(**params)
        except Exception as e:
            return {"error": str(e)}
        return {"result": result}

    @view(url=r"(?P<id>\d+)/caps/$", method=["GET"], access="read", api=True)
    def api_get_caps(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = []
        oc = ObjectCapabilities.objects.filter(object=o).first()
        if oc:
            for c in oc.caps:
                r += [{
                    "capability": c.capability.name,
                    "description": c.capability.description,
                    "type": c.capability.type,
                    "value": c.value,
                    "source": c.source,
                }]
        return sorted(r, key=lambda x: x["capability"])

    @view(url=r"(?P<id>\d+)/facts/$", method=["GET"], access="read", api=True)
    def api_get_facts(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        return sorted(
            ({
                "cls": f.cls,
                "label": f.label,
                "attrs": [{
                    "name": a,
                    "value": f.attrs[a]
                } for a in f.attrs],
                "introduced": f.introduced.isoformat(),
                "changed": f.changed.isoformat(),
            } for f in ObjectFact.objects.filter(object=o.id)),
            key=lambda x: (x["cls"], x["label"]),
        )

    @view(url=r"(?P<id>\d+)/revalidate/$",
          method=["POST"],
          access="read",
          api=True)
    def api_revalidate(self, request, id):
        def revalidate(o):
            engine = Engine(o)
            engine.check()
            return self.response({"status": True}, self.OK)

        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        return self.submit_slow_op(request, revalidate, o)

    @view(url=r"(?P<id>\d+)/actions/(?P<action>\S+)/$",
          method=["POST"],
          access="action",
          api=True)
    def api_action(self, request, id, action):
        def execute(o, a, args):
            return a.execute(o, **args)

        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        a = self.get_object_or_404(Action, name=action)
        # @todo: Check access
        body = request.body
        if body:
            args = ujson.loads(body)
        else:
            args = {}
        return self.submit_slow_op(request, execute, o, a, args)

    @view(url=r"^link/fix/(?P<link_id>[0-9a-f]{24})/$",
          method=["POST"],
          access="change_link")
    def api_fix_links(self, request, link_id):
        def get_mac(arp, ip):
            for r in arp:
                if r["ip"] == ip:
                    return r["mac"]
            return None

        def get_interface(macs, mac):
            for m in macs:
                if m["mac"] == mac:
                    return m["interfaces"][0]
            return None

        def error_status(message, *args):
            self.logger.error(message, *args)
            return {"status": False, "message": message % args}

        def success_status(message, *args):
            self.logger.error(message, *args)
            return {"status": True, "message": message % args}

        link = self.get_object_or_404(Link, id=link_id)
        if len(link.interfaces) != 2:
            return error_status("Cannot fix link: Not P2P")
        mo1 = link.interfaces[0].managed_object
        mo2 = link.interfaces[1].managed_object
        if mo1.id == mo2.id:
            return error_status("Cannot fix circular links")
        # Ping each other
        self.logger.info("[%s] Pinging %s", mo1.name, mo2.address)
        r1 = mo1.scripts.ping(address=mo2.address)
        if not r1["success"]:
            return error_status("Failed to ping %s", mo2.name)
        self.logger.info("[%s] Pinging %s", mo2.name, mo1.address)
        r2 = mo2.scripts.ping(address=mo1.address)
        if not r2["success"]:
            return error_status("Failed to ping %s", mo1.name)
        # Get ARPs
        mac2 = get_mac(mo1.scripts.get_arp(), mo2.address)
        if not mac2:
            return error_status("[%s] ARP cache is not filled properly",
                                mo1.name)
        self.logger.info("[%s] MAC=%s", mo2.name, mac2)
        mac1 = get_mac(mo2.scripts.get_arp(), mo1.address)
        if not mac1:
            return error_status("[%s] ARP cache is not filled properly",
                                mo2.name)
        self.logger.info("[%s] MAC=%s", mo1.name, mac1)
        # Get MACs
        r1 = mo1.scripts.get_mac_address_table(mac=mac2)
        self.logger.info("[%s] MACS=%s", mo1.name, r1)
        r2 = mo2.scripts.get_mac_address_table(mac=mac1)
        self.logger.info("[%s] MACS=%s", mo2.name, r2)
        # mo1: Find mo2
        i1 = get_interface(r1, mac2)
        if not i1:
            return error_status("[%s] Cannot find %s in the MAC address table",
                                mo1.name, mo2.name)
        # mo2: Find mo1
        i2 = get_interface(r2, mac1)
        if not i1:
            return error_status("[%s] Cannot find %s in the MAC address table",
                                mo2.name, mo1.name)
        self.logger.info("%s:%s -- %s:%s", mo1.name, i1, mo2.name, i2)
        if link.interfaces[0].name == i1 and link.interfaces[1].name == i2:
            return success_status("Linked properly")
        # Get interfaces
        iface1 = mo1.get_interface(i1)
        if not iface1:
            return error_status("[%s] Interface not found: %s", mo1.name, i1)
        iface2 = mo2.get_interface(i2)
        if not iface2:
            return error_status("[%s] Interface not found: %s", mo2.name, i2)
        # Check we can relink
        if_ids = [i.id for i in link.interfaces]
        if iface1.id not in if_ids and iface1.is_linked:
            return error_status("[%s] %s is already linked", mo1.name, i1)
        if iface2.id not in if_ids and iface2.is_linked:
            return error_status("[%s] %s is already linked", mo2.name, i2)
        # Relink
        self.logger.info("Relinking")
        link.delete()
        iface1.link_ptp(iface2, method="macfix")
        return success_status("Relinked")

    @view(url=r"^(?P<id>\d+)/cpe/$", method=["GET"], access="read", api=True)
    def api_cpe(self, request, id):
        """
        GET CPEs
        :param request:
        :param id:
        :return:
        """
        def sorted_iname(s):
            return sorted(s, key=lambda x: split_alnum(x["name"]))

        # Get object
        o = self.get_object_or_404(ManagedObject, id=int(id))
        if not o.has_access(request.user):
            return self.response_forbidden("Permission denied")
        # CPE
        # @todo: proper ordering
        # default_state = ResourceState.get_default()
        # style_cache = {}  # profile_id -> css_style
        l1 = [
            {
                "global_id": str(c.global_id),
                "name": c.name or "",
                "interface": c.interface,
                "local_id": c.local_id,
                "serial": c.serial or "",
                "status": c.status,
                "description": c.description or "",
                "address": c.ip or "",
                "model": c.model or "",
                "version": c.version or "",
                "mac": c.mac or "",
                "location": c.location or "",
                "distance": str(c.distance)
                # "row_class": get_style(i)
            } for c in CPEStatus.objects.filter(managed_object=o.id)
        ]

        return {"cpe": sorted_iname(l1)}
Ejemplo n.º 12
0
class PeerApplication(ExtModelApplication):
    """
    Peers application
    """
    title = "Peers"
    menu = "Peers"
    model = Peer
    query_fields = [
        "remote_asn__icontains", "description__icontains",
        "local_ip__icontains", "local_backup_ip__icontains",
        "remote_ip__icontains", "remote_backup_ip__icontains"
    ]

    def clean(self, data):
        data = super(PeerApplication, self).clean(data)
        ## Check address fields
        if not is_prefix(data["local_ip"]):
            raise ValueError(
                "Invalid 'Local IP Address', must be in x.x.x.x/x form or IPv6 prefix"
            )
        if not is_prefix(data["remote_ip"]):
            raise ValueError(
                "Invalid 'Remote IP Address', must be in x.x.x.x/x form or IPv6 prefix"
            )
        if "local_backup_ip" in data and data["local_backup_ip"]:
            if not is_prefix(data["local_backup_ip"]):
                raise ValueError(
                    "Invalid 'Local Backup IP Address', must be in x.x.x.x/x form or IPv6 prefix"
                )
        if "remote_backup_ip" in data and data["remote_backup_ip"]:
            if not is_prefix(data["remote_backup_ip"]):
                raise ValueError(
                    "Invalid 'Remote Backup IP Address', must be in x.x.x.x/x form or IPv6 prefix"
                )

        ## Check no or both backup addresses given
        has_local_backup = "local_backup_ip" in data and data["local_backup_ip"]
        has_remote_backup = "remote_backup_ip" in data and data[
            "remote_backup_ip"]
        if has_local_backup and not has_remote_backup:
            raise ValueError("One of backup addresses given. Set peer address")
        if not has_local_backup and has_remote_backup:
            raise ValueError("One of backup addresses given. Set peer address")
        ## Check all link addresses belongs to one AFI
        if len(
                set([
                    IP.prefix(data[x]).afi for x in [
                        "local_ip", "remote_ip", "local_backup_ip",
                        "remote_backup_ip"
                    ] if x in data and data[x]
                ])) > 1:
            raise ValueError(
                "All neighboring addresses must have same address family")
        return data

    ##
    ## Change peer status
    ##
    def set_peer_status(self, request, queryset, status, message):
        count = 0
        for p in queryset:
            p.status = status
            p.save()
            count += 1
        if count == 1:
            return "1 peer marked as %s" % message
        else:
            return "%d peers marked as %s" % (count, message)

    @view(url="^actions/planned/$",
          method=["POST"],
          access="update",
          api=True,
          validate={"ids": ListOfParameter(element=ModelParameter(Peer))})
    def api_action_planned(self, request, ids):
        return self.set_peer_status(request, ids, "P", "planned")

    api_action_planned.short_description = "Mark as planned"

    @view(url="^actions/active/$",
          method=["POST"],
          access="update",
          api=True,
          validate={"ids": ListOfParameter(element=ModelParameter(Peer))})
    def api_action_active(self, request, ids):
        return self.set_peer_status(request, ids, "A", "active")

    api_action_active.short_description = "Mark as active"

    @view(url="^actions/shutdown/$",
          method=["POST"],
          access="update",
          api=True,
          validate={"ids": ListOfParameter(element=ModelParameter(Peer))})
    def api_action_shutdown(self, request, ids):
        return self.set_peer_status(request, ids, "S", "shutdown")

    api_action_shutdown.short_description = "Mark as shutdown"
Ejemplo n.º 13
0
class VCApplication(ExtModelApplication):
    """
    VC application
    """

    title = _("VC")
    menu = _("Virtual Circuits")
    model = VC

    query_fields = ["name", "description"]
    query_condition = "icontains"
    int_query_fields = ["l1", "l2"]

    implied_permissions = {"read": ["vc:vcdomain:lookup", "main:style:lookup"]}

    def get_vc_domain_objects(self, vc_domain):
        return vc_domain.managedobject_set.all()

    def lookup_vcfilter(self, q, name, value):
        """
        Resolve __vcflter lookups
        :param q:
        :param name:
        :param value:
        :return:
        """
        value = ModelParameter(VCFilter).clean(value)
        x = value.to_sql(name)
        try:
            q[None] += [x]
        except KeyError:
            q[None] = [x]

    @cachedmethod(key="vc-interface-count-%s")
    def get_vc_interfaces_count(self, vc_id):
        vc = VC.get_by_id(vc_id)
        if not vc:
            return 0
        objects = vc.vc_domain.managedobject_set.values_list("id", flat=True)
        l1 = vc.l1
        n = SubInterface.objects.filter(
            Q(managed_object__in=objects)
            & (
                Q(untagged_vlan=l1, enabled_afi=["BRIDGE"])
                | Q(tagged_vlans=l1, enabled_afi=["BRIDGE"])
                | Q(vlan_ids=l1)
            )
        ).count()
        return n

    @cachedmethod(key="vc-prefixes-%s")
    def get_vc_prefixes(self, vc_id):
        vc = VC.get_by_id(vc_id)
        if not vc:
            return []
        objects = vc.vc_domain.managedobject_set.values_list("id", flat=True)
        ipv4 = set()
        ipv6 = set()
        # @todo: Exact match on vlan_ids
        for si in SubInterface.objects.filter(
            Q(managed_object__in=objects)
            & Q(vlan_ids=vc.l1)
            & (Q(enabled_afi=["IPv4"]) | Q(enabled_afi=["IPv6"]))
        ).only("enabled_afi", "ipv4_addresses", "ipv6_addresses"):
            if "IPv4" in si.enabled_afi:
                ipv4.update([IP.prefix(ip).first for ip in si.ipv4_addresses])
            if "IPv6" in si.enabled_afi:
                ipv6.update([IP.prefix(ip).first for ip in si.ipv6_addresses])
        p = [str(x.first) for x in sorted(ipv4)]
        p += [str(x.first) for x in sorted(ipv6)]
        return p

    def field_interfaces_count(self, obj):
        return self.get_vc_interfaces_count(obj.id)

    def field_prefixes(self, obj):
        p = self.get_vc_prefixes(obj.id)
        if p:
            return ", ".join(p)
        else:
            return "-"

    def field_row_class(self, o):
        return o.style.css_class_name if o.style else ""

    @view(
        url="^find_free/$",
        method=["GET"],
        access="read",
        api=True,
        validate={"vc_domain": ModelParameter(VCDomain), "vc_filter": ModelParameter(VCFilter)},
    )
    def api_find_free(self, request, vc_domain, vc_filter, **kwargs):
        return vc_domain.get_free_label(vc_filter)

    @view(
        url="^bulk/import/",
        method=["POST"],
        access="import",
        api=True,
        validate={
            "vc_domain": ModelParameter(VCDomain),
            "items": ListOfParameter(
                element=DictParameter(
                    attrs={
                        "l1": IntParameter(),
                        "l2": IntParameter(),
                        "name": StringParameter(),
                        "description": StringParameter(default=""),
                    }
                )
            ),
        },
    )
    def api_bulk_import(self, request, vc_domain, items):
        n = 0
        for i in items:
            if not VC.objects.filter(vc_domain=vc_domain, l1=i["l1"], l2=i["l2"]).exists():
                # Add only not-existing
                VC(
                    vc_domain=vc_domain,
                    l1=i["l1"],
                    l2=i["l2"],
                    name=i["name"],
                    description=i["description"],
                ).save()
                n += 1
        return {"status": True, "imported": n}

    @view(url=r"^(?P<vc_id>\d+)/interfaces/$", method=["GET"], access="read", api=True)
    def api_interfaces(self, request, vc_id):
        """
        Returns a dict of {untagged: ..., tagged: ...., l3: ...}
        :param request:
        :param vc_id:
        :return:
        """
        vc = self.get_object_or_404(VC, id=int(vc_id))
        l1 = vc.l1
        # Managed objects in VC domain
        objects = set(vc.vc_domain.managedobject_set.values_list("id", flat=True))
        # Find untagged interfaces
        si_objects = defaultdict(list)
        for si in SubInterface.objects.filter(
            managed_object__in=objects, untagged_vlan=l1, enabled_afi="BRIDGE"
        ):
            si_objects[si.managed_object] += [{"name": si.name}]
        untagged = [
            {
                "managed_object_id": o.id,
                "managed_object_name": o.name,
                "interfaces": sorted(si_objects[o], key=lambda x: x["name"]),
            }
            for o in si_objects
        ]
        # Find tagged interfaces
        si_objects = defaultdict(list)
        for si in SubInterface.objects.filter(
            managed_object__in=objects, tagged_vlans=l1, enabled_afi="BRIDGE"
        ):
            si_objects[si.managed_object] += [{"name": si.name}]
        tagged = [
            {
                "managed_object_id": o.id,
                "managed_object_name": o.name,
                "interfaces": sorted(si_objects[o], key=lambda x: x["name"]),
            }
            for o in si_objects
        ]
        # Find l3 interfaces
        si_objects = defaultdict(list)
        for si in SubInterface.objects.filter(managed_object__in=objects, vlan_ids=l1):
            si_objects[si.managed_object] += [
                {
                    "name": si.name,
                    "ipv4_addresses": si.ipv4_addresses,
                    "ipv6_addresses": si.ipv6_addresses,
                }
            ]
        l3 = [
            {
                "managed_object_id": o.id,
                "managed_object_name": o.name,
                "interfaces": sorted(si_objects[o], key=lambda x: x["name"]),
            }
            for o in si_objects
        ]
        # Update caches
        ic = sum(len(x["interfaces"]) for x in untagged)
        ic += sum(len(x["interfaces"]) for x in tagged)
        ic += sum(len(x["interfaces"]) for x in l3)
        #
        return {
            "untagged": sorted(untagged, key=lambda x: x["managed_object_name"]),
            "tagged": sorted(tagged, key=lambda x: x["managed_object_name"]),
            "l3": sorted(l3, key=lambda x: x["managed_object_name"]),
        }
Ejemplo n.º 14
0
class PrefixListBuilderApplication(ExtApplication):
    """
    Interactive prefix list builder
    """
    title = _("Prefix List Builder")
    menu = _("Prefix List Builder")

    @view(method=["GET"],
          url=r"^$",
          access="read",
          api=True,
          validate={
              "peering_point": ModelParameter(PeeringPoint),
              "name": UnicodeParameter(required=False),
              "as_set": UnicodeParameter()
          })
    def api_list(self, request, peering_point, name, as_set):
        if not WhoisCache.has_asset_members():
            return {
                "name":
                name,
                "prefix_list":
                "",
                "success":
                False,
                "message":
                _("AS-SET members cache is empty. Please update Whois Cache")
            }
        if not WhoisCache.has_origin_routes():
            return {
                "name":
                name,
                "prefix_list":
                "",
                "success":
                False,
                "message":
                _("Origin routes cache is empty. Please update Whois Cache")
            }
        if not WhoisCache.has_asset(as_set):
            return {
                "name": name,
                "prefix_list": "",
                "success": False,
                "message": _("Unknown AS-SET")
            }
        prefixes = WhoisCache.resolve_as_set_prefixes_maxlen(as_set)
        if not prefixes:
            return {
                "name": name,
                "prefix_list": "",
                "success": False,
                "message": _("Cannot resolve AS-SET prefixes")
            }
        try:
            pl = peering_point.profile.get_profile().generate_prefix_list(
                name, prefixes)
        except NotImplementedError:
            return {
                "name":
                name,
                "prefix_list":
                "",
                "success":
                False,
                "message":
                _("Prefix-list generator is not implemented for this profile")
            }
        return {
            "name": name,
            "prefix_list": pl,
            "success": True,
            "message": _("Prefix List built")
        }
Ejemplo n.º 15
0
class PrefixApplication(ExtModelApplication):
    """
    Prefix application
    """

    title = _("Prefix")
    model = Prefix

    def field_row_class(self, o):
        return o.profile.style.css_class_name if o.profile and o.profile.style else ""

    def can_create(self, user, obj):
        return PrefixAccess.user_can_change(user, obj.vrf, obj.afi, obj.prefix)

    def can_update(self, user, obj):
        return PrefixAccess.user_can_change(user, obj.vrf, obj.afi, obj.prefix)

    def can_delete(self, user, obj):
        return PrefixAccess.user_can_change(user, obj.vrf, obj.afi, obj.prefix)

    def queryset(self, request, query=None):
        qs = super(PrefixApplication, self).queryset(request, query=query)
        return qs.filter(PrefixAccess.read_Q(request.user))

    @view(
        url=r"^(?P<prefix_id>\d+)/rebase/$",
        method=["POST"],
        access="rebase",
        api=True,
        validate={
            "to_vrf": ModelParameter(VRF),
            "to_prefix": PrefixParameter()
        },
    )
    def api_rebase(self, request, prefix_id, to_vrf, to_prefix):
        prefix = self.get_object_or_404(Prefix, id=int(prefix_id))
        try:
            new_prefix = prefix.rebase(to_vrf, to_prefix)
            return self.instance_to_dict(new_prefix)
        except ValueError as e:
            return self.response_bad_request(str(e))

    @view(url=r"^(?P<prefix_id>\d+)/suggest_free/$",
          method=["GET"],
          access="read",
          api=True)
    def api_suggest_free(self, request, prefix_id):
        """
        Suggest free blocks of different sizes
        :param request:
        :param prefix_id:
        :return:
        """
        prefix = self.get_object_or_404(Prefix, id=int(prefix_id))
        suggestions = []
        p_mask = int(prefix.prefix.split("/")[1])
        free = sorted(
            IP.prefix(prefix.prefix).iter_free(
                [pp.prefix for pp in prefix.children_set.all()]),
            key=attrgetter("mask"),
            reverse=True,
        )
        # Find smallest free block possible
        for mask in range(30 if prefix.is_ipv4 else 64,
                          max(p_mask + 1, free[-1].mask) - 1, -1):
            # Find smallest free block possible
            for p in free:
                if p.mask <= mask:
                    suggestions += [{
                        "prefix":
                        "%s/%d" % (p.address, mask),
                        "size":
                        2**(32 - mask) if prefix.is_ipv4 else None,
                    }]
                    break
        return suggestions

    @view(method=["DELETE"],
          url=r"^(?P<id>\d+)/recursive/$",
          access="delete",
          api=True)
    def api_delete_recursive(self, request, id):
        try:
            o = self.queryset(request).get(**{self.pk: int(id)})
        except self.model.DoesNotExist:
            return self.render_json({
                "status": False,
                "message": "Not found"
            },
                                    status=self.NOT_FOUND)
        # Check permissions
        if not self.can_delete(request.user, o):
            return self.render_json(
                {
                    "status": False,
                    "message": "Permission denied"
                },
                status=self.FORBIDDEN)
        try:
            o.delete_recursive()
        except ValueError as e:
            return self.render_json(
                {
                    "success": False,
                    "message": "ERROR: %s" % e
                },
                status=self.CONFLICT)
        return HttpResponse(status=self.DELETED)

    @view(r"^(?P<id>\d+)/get_path/$", access="read", api=True)
    def api_get_path(self, request, id):
        o = self.get_object_or_404(Prefix, id=int(id))
        try:
            path = [Prefix.objects.get(id=ns) for ns in o.get_path()]
            return {
                "data": [{
                    "id": str(p.id),
                    "name": smart_text(p.name),
                    "afi": p.afi
                } for p in path]
            }
        except ValueError as e:
            return self.response_bad_request(str(e))
Ejemplo n.º 16
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
Ejemplo n.º 17
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"]

    def __init__(self, *args, **kwargs):
        ExtApplication.__init__(self, *args, **kwargs)
        from plugins.base import AlarmPlugin
        # Load plugins
        self.plugins = {}
        for f in os.listdir("fm/apps/alarm/plugins/"):
            if (not f.endswith(".py") or
                    f == "base.py" or
                    f.startswith("_")):
                continue
            mn = "noc.fm.apps.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()
        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]
        # Normalize parameters
        for p in q:
            qp = p.split("__")[0]
            if qp in self.clean_fields:
                q[p] = self.clean_fields[qp].clean(q[p])
        if "administrative_domain" in q:
            a = AdministrativeDomain.objects.get(id = q["administrative_domain"])
            q["managed_object__in"] = a.managedobject_set.values_list("id", flat=True)
            q.pop("administrative_domain")
        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 "collapse" in q:
            c = q["collapse"]
            del q["collapse"]
            if c != "0":
                q["root__exists"] = False
        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,
            "row_class": s.style.css_class_name
        }
        if fields:
            d = dict((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]
        return model.objects.all()

    @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
        lang = "en"
        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
        d["managed_object_version"] = mo.get_attr("version")
        # Log
        if alarm.log:
            d["log"] = [
                {
                    "timestamp": self.to_json(l.timestamp),
                    "from_status": l.from_status,
                    "to_status": l.to_status,
                    "message": l.message
                } for l 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
        if alarm.alarm_class.plugins:
            plugins = []
            for p in alarm.alarm_class.plugins:
                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("%s: %s" % (request.user.username, msg))
        return 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")
    def api_clear(self, request, id):
        alarm = get_alarm(id)
        if alarm.status == "A":
            alarm.clear_alarm("Cleared by %s" % request.user)
        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
Ejemplo n.º 18
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={})

    DEFAULT_ARCH_ALARM = datetime.timedelta(
        seconds=config.web.api_arch_alarm_limit)

    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]
        # Normalize parameters
        for p in q:
            qp = p.split("__")[0]
            if qp in self.clean_fields:
                q[p] = self.clean_fields[qp].clean(q[p])
        # Exclude maintenance
        if "maintenance" not in q:
            q["maintenance"] = "hide"
        if q["maintenance"] == "hide":
            q["managed_object__nin"] = Maintenance.currently_affected()
        elif q["maintenance"] == "only":
            q["managed_object__in"] = Maintenance.currently_affected()
        del q["maintenance"]
        if "administrative_domain" in q:
            q["adm_path"] = int(q["administrative_domain"])
            q.pop("administrative_domain")
        if "segment" in q:
            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 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())
        mtc = o.managed_object.id in Maintenance.currently_affected()
        if o.status == "C":
            # For archived alarms
            mtc = Maintenance.objects.filter(
                start__lte=o.clear_timestamp,
                stop__lte=o.timestamp,
                affected_objects__in=[
                    MaintenanceObject(object=o.managed_object)
                ]).count() > 0

        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,
            "isInMaintenance":
            mtc,
            "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)
        }
        if fields:
            d = dict((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.tags
        # Log
        if alarm.log:
            d["log"] = [{
                "timestamp": self.to_json(l.timestamp),
                "from_status": l.from_status,
                "to_status": l.to_status,
                "message": l.message
            } for l 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("%s: %s" % (request.user.username, msg))
        return 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")
    def api_clear(self, request, id):
        alarm = get_alarm(id)
        if alarm.status == "A":
            alarm.clear_alarm("Cleared by %s" % request.user)
        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="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 sorted(d.items(), key=lambda x: -x[1]):
                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
                    v += [
                        "<i class=\"%s\" title=\"%s\"></i>%s" %
                        (pv.glyph, pv.name, badge)
                    ]
            return "<span class='x-summary'>%s</span>" % " ".join(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 "&nbsp;".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(res.strip().decode("utf-8").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]
        else:
            return ["", ""]
Ejemplo n.º 19
0
class RunCommandsApplication(ExtApplication):
    title = _("Run Commands")
    menu = [_("Run Commands")]

    implied_permissions = {"launch": ["sa:objectlist:read"]}

    @view(url=r"^form/snippet/(?P<snippet_id>\d+)/$",
          method=["GET"],
          access="launch",
          api=True)
    def api_form_snippet(self, request, snippet_id):
        snippet = self.get_object_or_404(CommandSnippet, id=int(snippet_id))
        r = []
        vars = snippet.vars
        for k in vars:
            cfg = {
                "name": k,
                "fieldLabel": k,
                "allowBlank": not vars[k].get("required", False)
            }
            t = vars[k].get("type")
            if t == "int":
                cfg["xtype"] = "numberfield"
            else:
                cfg["xtype"] = "textfield"
            r += [cfg]
        return r

    @view(url=r"^form/action/(?P<action_id>[0-9a-f]{24})/$",
          method=["GET"],
          access="launch",
          api=True)
    def api_form_action(self, request, action_id):
        action = self.get_object_or_404(Action, id=action_id)
        r = []
        for p in action.params:
            cfg = {
                "name": p.name,
                "fieldLabel": p.description or p.name,
                "allowBlank": not p.is_required,
            }
            if p.type == "int":
                cfg["xtype"] = "numberfield"
            else:
                cfg["xtype"] = "textfield"
            r += [cfg]
        return r

    @view(
        url=r"^render/snippet/(?P<snippet_id>\d+)/$",
        method=["POST"],
        validate={
            "objects": ListOfParameter(element=ModelParameter(ManagedObject)),
            "config": DictParameter(),
        },
        access="launch",
        api=True,
    )
    def api_render_snippet(self, request, snippet_id, objects, config):
        snippet = self.get_object_or_404(CommandSnippet, id=int(snippet_id))
        r = {}
        for mo in objects:
            config["object"] = mo
            r[mo.id] = snippet.expand(config)
        return r

    @view(
        url=r"^render/action/(?P<action_id>[0-9a-f]{24})/$",
        method=["POST"],
        validate={
            "objects": ListOfParameter(element=ModelParameter(ManagedObject)),
            "config": DictParameter(),
        },
        access="launch",
        api=True,
    )
    def api_render_action(self, request, action_id, objects, config):
        action = self.get_object_or_404(Action, id=action_id)
        r = {}
        for mo in objects:
            r[mo.id] = action.expand(mo, **config)
        return r
Ejemplo n.º 20
0
Archivo: views.py Proyecto: nbashev/noc
class InterfaceAppplication(ExtApplication):
    """
    inv.interface application
    """

    title = _("Interfaces")
    menu = _("Interfaces")

    mrt_config = {
        "get_mac": {
            "map_script": "get_mac_address_table",
            "timeout": config.script.timeout,
            "access": "get_mac",
        }
    }

    implied_permissions = {
        "get_mac": [
            "inv:inv:read",
            "inv:interface:view",
            "sa:managedobject:lookup",
            "sa:managedobject:read",
        ]
    }

    @view(url=r"^(?P<managed_object>\d+)/$",
          method=["GET"],
          access="view",
          api=True)
    def api_get_interfaces(self, request, managed_object):
        """
        GET interfaces
        :param managed_object:
        :return:
        """
        def sorted_iname(s):
            return list(sorted(s, key=lambda x: alnum_key(x["name"])))

        def get_style(i):
            profile = i.profile
            if profile:
                try:
                    return style_cache[profile.id]
                except KeyError:
                    pass
                if profile.style:
                    s = profile.style.css_class_name
                else:
                    s = ""
                style_cache[profile.id] = s
                return s
            else:
                return ""

        def get_link(i):
            link = i.link
            if not link:
                return None
            if link.is_ptp:
                # ptp
                o = link.other_ptp(i)
                label = "%s:%s" % (o.managed_object.name, o.name)
            elif link.is_lag:
                # unresolved LAG
                o = [
                    ii for ii in link.other(i)
                    if ii.managed_object.id != i.managed_object.id
                ]
                label = "LAG %s: %s" % (o[0].managed_object.name, ", ".join(
                    ii.name for ii in o))
            else:
                # Broadcast
                label = ", ".join("%s:%s" % (ii.managed_object.name, ii.name)
                                  for ii in link.other(i))
            return {"id": str(link.id), "label": label}

        # Get object
        o = self.get_object_or_404(ManagedObject, id=int(managed_object))
        if not o.has_access(request.user):
            return self.response_forbidden("Permission denied")
        # Physical interfaces
        # @todo: proper ordering
        default_state = ResourceState.get_default()
        style_cache = {}  # profile_id -> css_style
        l1 = [{
            "id":
            str(i.id),
            "name":
            i.name,
            "description":
            i.description,
            "mac":
            i.mac,
            "ifindex":
            i.ifindex,
            "lag":
            (i.aggregated_interface.name if i.aggregated_interface else ""),
            "link":
            get_link(i),
            "profile":
            str(i.profile.id) if i.profile else None,
            "profile__label":
            smart_text(i.profile) if i.profile else None,
            "enabled_protocols":
            i.enabled_protocols,
            "project":
            i.project.id if i.project else None,
            "project__label":
            smart_text(i.project) if i.project else None,
            "state":
            i.state.id if i.state else default_state.id,
            "state__label":
            smart_text(i.state if i.state else default_state),
            "vc_domain":
            i.vc_domain.id if i.vc_domain else None,
            "vc_domain__label":
            smart_text(i.vc_domain) if i.vc_domain else None,
            "row_class":
            get_style(i),
        } for i in Interface.objects.filter(managed_object=o.id,
                                            type="physical")]
        # LAG
        lag = [{
            "id":
            str(i.id),
            "name":
            i.name,
            "description":
            i.description,
            "members": [
                j.name
                for j in Interface.objects.filter(managed_object=o.id,
                                                  aggregated_interface=i.id)
            ],
            "profile":
            str(i.profile.id) if i.profile else None,
            "profile__label":
            smart_text(i.profile) if i.profile else None,
            "enabled_protocols":
            i.enabled_protocols,
            "project":
            i.project.id if i.project else None,
            "project__label":
            smart_text(i.project) if i.project else None,
            "state":
            i.state.id if i.state else default_state.id,
            "state__label":
            smart_text(i.state if i.state else default_state),
            "vc_domain":
            i.vc_domain.id if i.vc_domain else None,
            "vc_domain__label":
            smart_text(i.vc_domain) if i.vc_domain else None,
            "row_class":
            get_style(i),
        } for i in Interface.objects.filter(managed_object=o.id,
                                            type="aggregated")]
        # L2 interfaces
        l2 = [{
            "name": i.name,
            "description": i.description,
            "untagged_vlan": i.untagged_vlan,
            "tagged_vlans": i.tagged_vlans,
        } for i in SubInterface.objects.filter(managed_object=o.id,
                                               enabled_afi="BRIDGE")]
        # L3 interfaces
        q = Q(enabled_afi="IPv4") | Q(enabled_afi="IPv6")
        l3 = [{
            "name":
            i.name,
            "description":
            i.description,
            "ipv4_addresses":
            i.ipv4_addresses,
            "ipv6_addresses":
            i.ipv6_addresses,
            "enabled_protocols":
            i.enabled_protocols,
            "vlan":
            i.vlan_ids,
            "vrf":
            i.forwarding_instance.name if i.forwarding_instance else "",
        } for i in SubInterface.objects.filter(managed_object=o.id).filter(q)]
        return {
            "l1": sorted_iname(l1),
            "lag": sorted_iname(lag),
            "l2": sorted_iname(l2),
            "l3": sorted_iname(l3),
        }

    @view(
        url=r"^link/$",
        method=["POST"],
        validate={
            "type": StringParameter(choices=["ptp"]),
            "interfaces":
            ListOfParameter(element=DocumentParameter(Interface)),
        },
        access="link",
        api=True,
    )
    def api_link(self, request, type, interfaces):
        if type == "ptp":
            if len(interfaces) == 2:
                interfaces[0].link_ptp(interfaces[1])
                return {"status": True}
            else:
                raise ValueError("Invalid interfaces length")
        return {"status": False}

    @view(url=r"^unlink/(?P<iface_id>[0-9a-f]{24})/$",
          method=["POST"],
          access="link",
          api=True)
    def api_unlink(self, request, iface_id):
        i = Interface.objects.filter(id=iface_id).first()
        if not i:
            return self.response_not_found()
        try:
            i.unlink()
            return {"status": True, "msg": "Unlinked"}
        except ValueError as why:
            return {"status": False, "msg": str(why)}

    @view(url=r"^unlinked/(?P<object_id>\d+)/$",
          method=["GET"],
          access="link",
          api=True)
    def api_unlinked(self, request, object_id):
        def get_label(i):
            if i.description:
                return "%s (%s)" % (i.name, i.description)
            else:
                return i.name

        o = self.get_object_or_404(ManagedObject, id=int(object_id))
        r = [{
            "id": str(i.id),
            "label": get_label(i)
        } for i in Interface.objects.filter(managed_object=o.id,
                                            type="physical").order_by("name")
             if not i.link]
        return list(sorted(r, key=lambda x: alnum_key(x["label"])))

    @view(
        url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_profile/$",
        validate={"profile": DocumentParameter(InterfaceProfile)},
        method=["POST"],
        access="profile",
        api=True,
    )
    def api_change_profile(self, request, iface_id, profile):
        i = Interface.objects.filter(id=iface_id).first()
        if not i:
            return self.response_not_found()
        if i.profile != profile:
            i.profile = profile
            i.profile_locked = True
            i.save()
        return True

    @view(
        url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_state/$",
        validate={"state": ModelParameter(ResourceState)},
        method=["POST"],
        access="profile",
        api=True,
    )
    def api_change_state(self, request, iface_id, state):
        i = Interface.objects.filter(id=iface_id).first()
        if not i:
            return self.response_not_found()
        if i.state != state:
            i.state = state
            i.save()
        return True

    @view(
        url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_project/$",
        validate={"project": ModelParameter(Project, required=False)},
        method=["POST"],
        access="profile",
        api=True,
    )
    def api_change_project(self, request, iface_id, project):
        i = Interface.objects.filter(id=iface_id).first()
        if not i:
            return self.response_not_found()
        if i.project != project:
            i.project = project
            i.save()
        return True

    @view(
        url=r"^l1/(?P<iface_id>[0-9a-f]{24})/change_vc_domain/$",
        validate={"vc_domain": ModelParameter(VCDomain, required=False)},
        method=["POST"],
        access="profile",
        api=True,
    )
    def api_change_vc_domain(self, request, iface_id, vc_domain):
        i = Interface.objects.filter(id=iface_id).first()
        if not i:
            return self.response_not_found()
        if i.vc_domain != vc_domain:
            i.vc_domain = vc_domain
            i.save()
        return True
Ejemplo n.º 21
0
class UserProfileApplication(ExtApplication):
    """
    main.userprofile application
    """
    title = "User Profile"
    implied_permissions = {"launch": ["main:timepattern:lookup"]}

    @view(url="^$", method=["GET"], access=PermitLogged(), api=True)
    def api_get(self, request):
        user = request.user
        try:
            profile = user.get_profile()
            language = profile.preferred_language
            theme = profile.theme
            preview_theme = profile.preview_theme
            contacts = [{
                "time_pattern": c.time_pattern.id,
                "time_pattern__label": c.time_pattern.name,
                "notification_method": c.notification_method,
                "params": c.params
            } for c in profile.userprofilecontact_set.all()]
        except UserProfile.DoesNotExist:
            language = None
            theme = None
            preview_theme = None
            contacts = []
        return {
            "username":
            user.username,
            "name":
            (" ".join([x for x in (user.first_name, user.last_name)
                       if x])).strip(),
            "email":
            user.email,
            "preferred_language":
            language or "en",
            "theme":
            theme or "gray",
            "preview_theme":
            preview_theme or "midnight",
            "contacts":
            contacts
        }

    @view(url="^$",
          method=["POST"],
          access=PermitLogged(),
          api=True,
          validate={
              "preferred_language":
              StringParameter(choices=[x[0] for x in LANGUAGES]),
              "theme":
              StringParameter(),
              "preview_theme":
              StringParameter(),
              "contacts":
              ListOfParameter(element=DictParameter(
                  attrs={
                      "time_pattern":
                      ModelParameter(TimePattern),
                      "notification_method":
                      StringParameter(choices=[
                          x[0] for x in USER_NOTIFICATION_METHOD_CHOICES
                      ]),
                      "params":
                      StringParameter()
                  }))
          })
    def api_save(self, request, preferred_language, theme, preview_theme,
                 contacts):
        user = request.user
        try:
            profile = user.get_profile()
        except UserProfile.DoesNotExist:
            profile = UserProfile(user=user)
        profile.preferred_language = preferred_language
        profile.theme = theme
        profile.preview_theme = preview_theme
        profile.save()
        # Setup contacts
        for c in profile.userprofilecontact_set.all():
            c.delete()
        for c in contacts:
            UserProfileContact(user_profile=profile,
                               time_pattern=c["time_pattern"],
                               notification_method=c["notification_method"],
                               params=c["params"]).save()
        # Setup language
        request.session["django_lang"] = preferred_language
        return True
Ejemplo n.º 22
0
            "profile": DocumentParameter(InterfaceProfile)
        },
        method=["POST"], access="profile", api=True)
    def api_change_profile(self, request, iface_id, profile):
        i = Interface.objects.filter(id=iface_id).first()
        if not i:
            return self.response_not_found()
        if i.profile != profile:
            i.profile = profile
            i.profile_locked = True
            i.save()
        return True

    @view(url="^l1/(?P<iface_id>[0-9a-f]{24})/change_state/$",
        validate={
            "state": ModelParameter(ResourceState)
        },
        method=["POST"], access="profile", api=True)
    def api_change_state(self, request, iface_id, state):
        i = Interface.objects.filter(id=iface_id).first()
        if not i:
            return self.response_not_found()
        if i.state != state:
            i.state = state
            i.save()
        return True

    @view(url="^l1/(?P<iface_id>[0-9a-f]{24})/change_project/$",
        validate={
            "project": ModelParameter(Project, required=False)
        },
Ejemplo n.º 23
0
class ManagedObjectApplication(ExtModelApplication):
    """
    ManagedObject application
    """
    title = "Managed Objects"
    menu = "Managed Objects"
    model = ManagedObject
    query_condition = "icontains"
    query_fields = ["name", "description", "address"]
    # Inlines
    attrs = ModelInline(ManagedObjectAttribute)
    cfg = RepoInline("config")

    extra_permissions = ["alarm", "change_interface"]

    mrt_config = {
        "console": {
            "access": "console",
            "map_script": "commands",
            "timeout": 60
        }
    }

    def field_platform(self, o):
        return o.platform

    def field_row_class(self, o):
        return o.object_profile.style.css_class_name if o.object_profile.style else ""

    def field_interface_count(self, o):
        return Interface.objects.filter(managed_object=o.id, type="physical").count()

    def field_link_count(self, o):
        return Link.object_links_count(o)

    def queryset(self, request, query=None):
        qs = super(ManagedObjectApplication, self).queryset(request, query)
        if not request.user.is_superuser:
            qs = qs.filter(UserAccess.Q(request.user))
        qs = qs.exclude(name__startswith="wiping-")
        return qs

    @view(url="^(?P<id>\d+)/links/$", method=["GET"],
          access="read", api=True)
    def api_links(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        # Get links
        result = []
        for link in Link.object_links(o):
            l = []
            r = []
            for i in link.interfaces:
                if i.managed_object.id == o.id:
                    l += [i]
                else:
                    r += [i]
                for li, ri in zip(l, r):
                    result += [{
                        "id": str(link.id),
                        "local_interface": str(li.id),
                        "local_interface__label": li.name,
                        "remote_object": ri.managed_object.id,
                        "remote_object__label": ri.managed_object.name,
                        "remote_interface": str(ri.id),
                        "remote_interface__label": ri.name,
                        "discovery_method": link.discovery_method,
                        "commited": True,
                        "local_description": li.description,
                        "remote_description": ri.description
                    }]
        # Get pending links
        q = MQ(local_object=o.id) | MQ(remote_object=o.id)
        for link in PendingLinkCheck.objects.filter(q):
            if link.local_object.id == o.id:
                ro = link.remote_object
                lin = link.local_interface
                rin = link.remote_interface
            else:
                ro = link.local_object
                lin = link.remote_interface
                rin = link.local_interface
            li = Interface.objects.filter(managed_object=o.id, name=lin).first()
            if not li:
                continue
            ri = Interface.objects.filter(managed_object=ro.id, name=rin).first()
            if not ri:
                continue
            result += [{
                "id": str(link.id),
                "local_interface": str(li.id),
                "local_interface__label": li.name,
                "remote_object": ro.id,
                "remote_object__label": ro.name,
                "remote_interface": str(ri.id),
                "remote_interface__label": ri.name,
                "discovery_method": link.method,
                "commited": False,
                "local_description": li.description,
                "remote_description": ri.description
            }]
        return result

    @view(url="^link/approve/$", method=["POST"],
          access="change_link", api=True)
    def api_link_approve(self, request):
        d = json_decode(request.raw_post_data)
        plc = self.get_object_or_404(PendingLinkCheck, id=d.get("link"))
        li = Interface.objects.filter(
            managed_object=plc.local_object.id,
            name=plc.local_interface
            ).first()
        if not li:
            return {
                "success": False,
                "error": "Interface not found: %s:%s" % (
                    plc.local_object.name, plc.local_interface)
            }
        ri = Interface.objects.filter(
            managed_object=plc.remote_object.id,
            name=plc.remote_interface
            ).first()
        if not ri:
            return {
                "success": False,
                "error": "Interface not found: %s:%s" % (
                    plc.remote_object.name, plc.remote_interface)
            }
        li.link_ptp(ri, method=plc.method + "+manual")
        plc.delete()
        return {
            "success": True
        }

    @view(url="^link/reject/$", method=["POST"],
          access="change_link", api=True)
    def api_link_reject(self, request):
        d = json_decode(request.raw_post_data)
        plc = self.get_object_or_404(PendingLinkCheck, id=d.get("link"))
        plc.delete()
        return {
            "success": True
        }

    def check_mrt_access(self, request, name):
        # @todo: Check object's access
        return super(ManagedObjectApplication, self).check_mrt_access(request, name)

    @view(url="^(?P<id>\d+)/discovery/$", method=["GET"],
          access="read", api=True)
    def api_discovery(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        link_count = defaultdict(int)
        for link in Link.object_links(o):
            m = link.discovery_method or ""
            if "+" in m:
                m = m.split("+")[0]
            link_count[m] += 1
        r = [{
            "name": "ping",
            "enable_profile": o.object_profile.enable_ping,
            "status": o.get_status(),
            "last_run": None,
            "last_status": None,
            "next_run": None,
            "link_count": None
        }]
        for name in get_active_discovery_methods():
            job = get_job("inv.discovery", name, o.id) or {}
            if name.endswith("_discovery"):
                lcmethod = name[:-10]
            else:
                lcmethod = None
            d = {
                "name": name,
                "enable_profile": getattr(o.object_profile,
                                          "enable_%s" % name),
                "status": job.get("s"),
                "last_run": self.to_json(job.get("last")),
                "last_status": job.get("ls"),
                "next_run": self.to_json(job.get("ts")),
                "link_count": link_count.get(lcmethod, "")
            }
            r += [d]
        return r


    @view(url="^actions/set_managed/$", method=["POST"],
          access="create", api=True,
          validate={
              "ids": ListOfParameter(element=ModelParameter(ManagedObject), convert=True)
          })
    def api_action_set_managed(self, request, ids):
        for o in ids:
            if not o.has_access(request.user):
                continue
            o.is_managed = True
            o.save()
        return "Selected objects set to managed state"

    @view(url="^actions/set_unmanaged/$", method=["POST"],
          access="create", api=True,
          validate={
              "ids": ListOfParameter(element=ModelParameter(ManagedObject), convert=True)
          })
    def api_action_set_unmanaged(self, request, ids):
        for o in ids:
            if not o.has_access(request.user):
                continue
            o.is_managed = False
            o.save()
        return "Selected objects set to unmanaged state"

    @view(url="^(?P<id>\d+)/discovery/run/$", method=["POST"],
          access="change_discovery", api=True)
    def api_run_discovery(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = json_decode(request.raw_post_data).get("names", [])
        d = 0
        for name in get_active_discovery_methods():
            cfg = "enable_%s" % name
            if getattr(o.object_profile, cfg) and name in r:
                start_schedule("inv.discovery", name, o.id)
                refresh_schedule("inv.discovery",
                                 name, o.id, delta=d)
                d += 1
        return {
            "success": True
        }

    @view(url="^(?P<id>\d+)/discovery/stop/$", method=["POST"],
          access="change_discovery", api=True)
    def api_stop_discovery(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = json_decode(request.raw_post_data).get("names", [])
        d = 0
        for name in get_active_discovery_methods():
            cfg = "enable_%s" % name
            if getattr(o.object_profile, cfg) and name in r:
                stop_schedule("inv.discovery", name, o.id)
                d += 1
        return {
            "success": True
        }

    @view(url="^(?P<id>\d+)/interface/$", method=["GET"],
        access="read", api=True)
    def api_interface(self, request, id):
        """
        GET interfaces
        :param managed_object:
        :return:
        """
        def sorted_iname(s):
            return sorted(s, key=lambda x: split_alnum(x["name"]))

        def get_style(i):
            profile = i.profile
            if profile:
                try:
                    return style_cache[profile.id]
                except KeyError:
                    pass
                if profile.style:
                    s = profile.style.css_class_name
                else:
                    s = ""
                style_cache[profile.id] = s
                return s
            else:
                return ""

        def get_link(i):
            link = i.link
            if not link:
                return None
            if link.is_ptp:
                # ptp
                o = link.other_ptp(i)
                label = "%s:%s" % (o.managed_object.name, o.name)
            elif link.is_lag:
                # unresolved LAG
                o = [ii for ii in link.other(i)
                     if ii.managed_object.id != i.managed_object.id]
                label = "LAG %s: %s" % (o[0].managed_object.name,
                                        ", ".join(ii.name for ii in o))
            else:
                # Broadcast
                label = ", ".join(
                    "%s:%s" % (ii.managed_object.name, ii.name)
                               for ii in link.other(i))
            return {
                "id": str(link.id),
                "label": label
            }

        # Get object
        o = self.get_object_or_404(ManagedObject, id=int(id))
        if not o.has_access(request.user):
            return self.response_forbidden("Permission denied")
        # Physical interfaces
        # @todo: proper ordering
        default_state = ResourceState.get_default()
        style_cache = {}  ## profile_id -> css_style
        l1 = [
            {
                "id": str(i.id),
                "name": i.name,
                "description": i.description,
                "mac": i.mac,
                "ifindex": i.ifindex,
                "lag": (i.aggregated_interface.name
                        if i.aggregated_interface else ""),
                "link": get_link(i),
                "profile": str(i.profile.id) if i.profile else None,
                "profile__label": unicode(i.profile) if i.profile else None,
                "enabled_protocols": i.enabled_protocols,
                "project": i.project.id if i.project else None,
                "project__label": unicode(i.project) if i.project else None,
                "state": i.state.id if i.state else default_state.id,
                "state__label": unicode(i.state if i.state else default_state),
                "vc_domain": i.vc_domain.id if i.vc_domain else None,
                "vc_domain__label": unicode(i.vc_domain) if i.vc_domain else None,
                "row_class": get_style(i)
            } for i in Interface.objects.filter(
                managed_object=o.id, type="physical")
        ]
        # LAG
        lag = [
            {
                "id": str(i.id),
                "name": i.name,
                "description": i.description,
                "profile": str(i.profile.id) if i.profile else None,
                "profile__label": unicode(i.profile) if i.profile else None,
                "members": [j.name for j in Interface.objects.filter(
                    managed_object=o.id, aggregated_interface=i.id)],
                "row_class": get_style(i)
            } for i in
              Interface.objects.filter(managed_object=o.id,
                                       type="aggregated")
        ]
        # L2 interfaces
        l2 = [
            {
                "name": i.name,
                "description": i.description,
                "untagged_vlan": i.untagged_vlan,
                "tagged_vlans": i.tagged_vlans
            } for i in
              SubInterface.objects.filter(managed_object=o.id,
                  enabled_afi="BRIDGE")
        ]
        # L3 interfaces
        q = MQ(enabled_afi="IPv4") | MQ(enabled_afi="IPv6")
        l3 = [
            {
                "name": i.name,
                "description": i.description,
                "ipv4_addresses": i.ipv4_addresses,
                "ipv6_addresses": i.ipv6_addresses,
                "enabled_protocols": i.enabled_protocols,
                "vlan": i.vlan_ids,
                "vrf": i.forwarding_instance.name if i.forwarding_instance else "",
                "mac": i.mac
            } for i in
              SubInterface.objects.filter(managed_object=o.id).filter(q)
        ]
        return {
            "l1": sorted_iname(l1),
            "lag": sorted_iname(lag),
            "l2": sorted_iname(l2),
            "l3": sorted_iname(l3)
        }

    @view(url="^(?P<id>\d+)/interface/$", method=["POST"],
        access="change_interface", api=True)
    def api_set_interface(self, request, id):
        def get_or_none(c, v):
            if not v:
                return None
            return c.objects.get(id=v)
        o = self.get_object_or_404(ManagedObject, id=int(id))
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        d = json_decode(request.raw_post_data)
        if "id" in d:
            i = self.get_object_or_404(Interface, id=d["id"])
            if i.managed_object.id != o.id:
                return self.response_not_found()
            # Set profile
            if "profile" in d:
                p = get_or_none(InterfaceProfile, d["profile"])
                i.profile = p
                if p:
                    i.profile_locked = True
            # Project
            if "project" in d:
                i.project = get_or_none(Project, d["project"])
            # State
            if "state" in d:
                i.state = get_or_none(ResourceState, d["state"])
            # VC Domain
            if "vc_domain" in d:
                i.vc_domain = get_or_none(VCDomain, d["vc_domain"])
            #
            i.save()
        return {
            "success": True
        }

    @view(method=["DELETE"], url="^(?P<id>\d+)/?$", access="delete", api=True)
    def api_delete(self, request, id):
        """
        Override default method
        :param request:
        :param id:
        :return:
        """
        try:
            o = self.queryset(request).get(id=int(id))
        except self.model.DoesNotExist:
            return self.render_json({
                "status": False,
                "message": "Not found"
            }, status=self.NOT_FOUND)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        # Run sa.wipe_managed_object job instead
        o.name = "wiping-%d" % o.id
        o.is_managed = False
        o.description = "Wiping! Do not touch!"
        o.save()
        submit_job("main.jobs", "sa.wipe_managedobject", key=o.id)
        return HttpResponse(status=self.DELETED)

    @view(url="^actions/run_discovery/$", method=["POST"],
          access="launch", api=True,
          validate={
              "ids": ListOfParameter(element=ModelParameter(ManagedObject), convert=True)
          })
    def api_action_run_discovery(self, request, ids):
        for o in ids:
            if not o.has_access(request.user):
                continue
            d = 0
            for name in get_active_discovery_methods():
                cfg = "enable_%s" % name
                if getattr(o.object_profile, cfg):
                    refresh_schedule(
                        "inv.discovery",
                        name, o.id, delta=d)
                    d += 1
        return "Discovery processes has been scheduled"

    def get_nested_inventory(self, o):
        rev = o.get_data("asset", "revision")
        if rev == "None":
            rev = ""
        r = {
            "id": str(o.id),
            "serial": o.get_data("asset", "serial"),
            "revision": rev or "",
            "description": o.model.description,
            "model": o.model.name
        }
        children = []
        for n in o.model.connections:
            if n.direction == "i":
                c, r_object, _ = o.get_p2p_connection(n.name)
                if c is None:
                    children += [{
                        "id": None,
                        "name": n.name,
                        "leaf": True,
                        "serial": None,
                        "description": "--- EMPTY ---",
                        "model": None
                    }]
                else:
                    cc = self.get_nested_inventory(r_object)
                    cc["name"] = n.name
                    children += [cc]
            elif n.direction == "s":
                children += [{
                    "id": None,
                    "name": n.name,
                    "leaf": True,
                    "serial": None,
                    "description": n.description,
                    "model": ", ".join(n.protocols)
                }]
        if children:
            to_expand = "Transceiver" not in o.model.name
            r["children"] = children
            r["expanded"] = to_expand
        else:
            r["leaf"] = True
        return r

    @view(url="^(?P<id>\d+)/inventory/$", method=["GET"],
        access="read", api=True)
    def api_inventory(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = []
        for p in o.get_inventory():
            c = self.get_nested_inventory(p)
            c["name"] = p.name or o.name
            r += [c]
        return {
            "expanded": True,
            "children": r
        }

    @view(url="^(?P<id>\d+)/job_log/(?P<job>[a-zA-Z0-9_]+)/$", method=["GET"],
        access="read", api=True)
    def api_job_log(self, request, id, job):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        if not hasattr(self, "discovery_log_jobs"):
            # Read config
            self.discovery_log_jobs = None
            config = SafeConfigParser()
            config.read("etc/noc-discovery.conf")
            if config.has_section("main") and config.has_option("main", "log_jobs"):
                p = config.get("main", "log_jobs")
                if os.path.isdir(p):
                    self.discovery_log_jobs = p
        if self.discovery_log_jobs:
            p = os.path.join(self.discovery_log_jobs, job, id)
            if os.path.exists(p):
                with open(p) as f:
                    return self.render_plain_text(f.read())
        return self.render_plain_text("No data!")

    @view(url="^(?P<id>\d+)/interactions/$", method=["GET"],
          access="interactions", api=True)
    def api_interactions(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        return [{
            "ts": self.to_json(i.timestamp),
            "op": i.op,
            "user": i.user,
            "text": i.text
        } for i in InteractionLog.objects.filter(object=o.id).order_by("-timestamp")]

    @view(url="^(?P<id>\d+)/scripts/$", method=["GET"], access="script",
          api=True)
    def api_scripts(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = []
        for s in sorted(o.profile.scripts):
            script = o.profile.scripts[s]
            interface = script.implements[0]
            ss = {
                "name": s,
                "has_input": any(interface.gen_parameters()),
                "require_input": interface.has_required_params,
                "form": interface.get_form(),
                "preview": interface.preview or "NOC.sa.managedobject.scripts.JSONPreview"
            }
            r += [ss]
        return r

    @view(url="^(?P<id>\d+)/scripts/(?P<name>[^/]+)/$",
          method=["POST"], access="script", api=True)
    def api_run_script(self, request, id, name):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        if name not in o.profile.scripts:
            return self.response_not_found("Script not found: %s" % name)
        task = ReduceTask.create_task(
            o, "pyrule:mrt_result", {},
            name, {},
            None)
        return task.id

    @view(url="^(?P<id>\d+)/scripts/(?P<name>[^/]+)/(?P<task>\d+)/$",
          method=["GET"], access="script", api=True)
    def api_get_script_result(self, request, id, name, task):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        if name not in o.profile.scripts:
            return self.response_not_found("Script not found: %s" % name)
        t = self.get_object_or_404(ReduceTask, id=int(task))
        try:
            r = t.get_result(block=False)
        except ReduceTask.NotReady:
            # Not ready
            return {
                "ready": False,
                "max_timeout": (t.stop_time - datetime.datetime.now()).seconds,
                "result": None
            }
        # Return result
        return {
            "ready": True,
            "max_timeout": 0,
            "result": r[0]
        }

    @view(url="(?P<id>\d+)/caps/$", method=["GET"],
          access="read", api=True)
    def api_get_caps(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        r = []
        oc = ObjectCapabilities.objects.filter(object=o).first()
        if oc:
            for c in oc.caps:
                r += [{
                    "capability": c.capability.name,
                    "description": c.capability.description,
                    "type": c.capability.type,
                    "discovered_value": c.discovered_value,
                    "local_value": c.local_value,
                    "value": c.local_value if c.local_value is not None else c.discovered_value
                }]
        return sorted(r, key=lambda x: x["capability"])

    @view(url="(?P<id>\d+)/facts/$", method=["GET"],
          access="read", api=True)
    def api_get_facts(self, request, id):
        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        return sorted(
            (
                {
                    "cls": f.cls,
                    "label": f.label,
                    "attrs": [
                        {
                            "name": a,
                            "value": f.attrs[a]
                        } for a in f.attrs
                    ],
                    "introduced": f.introduced.isoformat(),
                    "changed": f.changed.isoformat()
                } for f in ObjectFact.objects.filter(object=o.id)),
            key=lambda x: (x["cls"], x["label"]))

    @view(url="(?P<id>\d+)/revalidate/$", method=["POST"],
          access="read", api=True)
    def api_revalidate(self, request, id):
        def revalidate(o):
            engine = Engine(o)
            engine.check()
            return self.response({"status": True}, self.OK)

        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        return self.submit_slow_op(request, revalidate, o)

    @view(url="(?P<id>\d+)/actions/(?P<action>\S+)/$", method=["POST"],
          access="action", api=True)
    def api_action(self, request, id, action):
        def execute(o, a, args):
            return a.execute(o, **args)

        o = self.get_object_or_404(ManagedObject, id=id)
        if not o.has_access(request.user):
            return self.response_forbidden("Access denied")
        a = self.get_object_or_404(Action, name=action)
        # @todo: Check access
        body = request.raw_post_data
        if body:
            args = json_decode(body)
        else:
            args = {}
        return self.submit_slow_op(request, execute, o, a, args)
Ejemplo n.º 24
0
class UserProfileApplication(ExtApplication):
    """
    main.userprofile application
    """

    title = _("User Profile")
    implied_permissions = {"launch": ["main:timepattern:lookup"]}

    @view(url="^$", method=["GET"], access=PermitLogged(), api=True)
    def api_get(self, request):
        user = request.user
        language = user.preferred_language
        contacts = [{
            "time_pattern": c.time_pattern.id,
            "time_pattern__label": c.time_pattern.name,
            "notification_method": c.notification_method,
            "params": c.params,
        } for c in UserContact.objects.filter(user=user)]
        return {
            "username":
            user.username,
            "name":
            (" ".join([x for x in (user.first_name, user.last_name)
                       if x])).strip(),
            "email":
            user.email,
            "preferred_language":
            language or "en",
            "contacts":
            contacts,
            "groups": [g.name for g in user.groups.all().order_by("name")],
        }

    @view(
        url="^$",
        method=["POST"],
        access=PermitLogged(),
        api=True,
        validate={
            "preferred_language":
            StringParameter(choices=[x[0] for x in LANGUAGES]),
            "contacts":
            ListOfParameter(element=DictParameter(
                attrs={
                    "time_pattern":
                    ModelParameter(TimePattern),
                    "notification_method":
                    StringParameter(choices=[
                        x[0] for x in USER_NOTIFICATION_METHOD_CHOICES
                    ]),
                    "params":
                    StringParameter(),
                })),
        },
    )
    def api_save(self, request, preferred_language, contacts):
        user = request.user
        user.preferred_language = preferred_language
        user.save()
        # Setup contacts
        UserContact.objects.filter(user=user).delete()
        for c in contacts:
            UserContact(
                user=user,
                time_pattern=c["time_pattern"],
                notification_method=c["notification_method"],
                params=c["params"],
            ).save()
        return True
Ejemplo n.º 25
0
 def __init__(self, *args, **kwargs):
     super(ExtDocApplication, self).__init__(*args, **kwargs)
     self.pk = "id"  # @todo: detect properly
     self.has_uuid = False
     # Prepare field converters
     self.clean_fields = self.clean_fields.copy()  # name -> Parameter
     for name, f in six.iteritems(self.model._fields):
         if isinstance(f, BooleanField):
             self.clean_fields[name] = BooleanParameter()
         elif isinstance(f, GeoPointField):
             self.clean_fields[name] = GeoPointParameter()
         elif isinstance(f, ForeignKeyField):
             self.clean_fields[f.name] = ModelParameter(f.document_type, required=f.required)
         elif isinstance(f, ListField):
             if isinstance(f.field, EmbeddedDocumentField):
                 self.clean_fields[f.name] = ListOfParameter(
                     element=EmbeddedDocumentParameter(f.field.document_type)
                 )
         elif isinstance(f, ReferenceField):
             dt = f.document_type_obj
             if dt == "self":
                 dt = self.model
             self.clean_fields[f.name] = DocumentParameter(dt, required=f.required)
         if f.primary_key:
             self.pk = name
         if name == "uuid":
             self.has_uuid = True
     #
     if not self.query_fields:
         self.query_fields = [
             "%s__%s" % (n, self.query_condition)
             for n, f in six.iteritems(self.model._fields)
             if f.unique and isinstance(f, StringField)
         ]
     self.unique_fields = [n for n, f in six.iteritems(self.model._fields) if f.unique]
     # Install JSON API call when necessary
     self.json_collection = self.model._meta.get("json_collection")
     if (
         self.has_uuid
         and hasattr(self.model, "to_json")
         and not hasattr(self, "api_to_json")
         and not hasattr(self, "api_json")
     ):
         self.add_view(
             "api_json",
             self._api_to_json,
             url=r"^(?P<id>[0-9a-f]{24})/json/$",
             method=["GET"],
             access="read",
             api=True,
         )
         self.add_view(
             "api_share_info",
             self._api_share_info,
             url=r"^(?P<id>[0-9a-f]{24})/share_info/$",
             method=["GET"],
             access="read",
             api=True,
         )
     if self.json_collection:
         self.bulk_fields += [self._bulk_field_is_builtin]
     # Find field_* and populate custom fields
     self.custom_fields = {}
     for fn in [n for n in dir(self) if n.startswith("field_")]:
         h = getattr(self, fn)
         if callable(h):
             self.custom_fields[fn[6:]] = h
Ejemplo n.º 26
0
Archivo: views.py Proyecto: 0pt1on/noc
class EventApplication(ExtApplication):
    """
    fm.event application
    """

    title = _("Events")
    menu = _("Events")
    icon = "icon_find"

    model_map = {"A": ActiveEvent, "F": FailedEvent, "S": ArchivedEvent}

    clean_fields = {
        "managed_object": ModelParameter(ManagedObject),
        "timestamp": DateTimeParameter(),
    }
    ignored_params = ["status", "_dc"]

    def __init__(self, *args, **kwargs):
        ExtApplication.__init__(self, *args, **kwargs)
        from .plugins.base import EventPlugin

        # Load plugins
        self.plugins = {}
        for f in os.listdir("services/web/apps/fm/event/plugins/"):
            if not f.endswith(".py") or f == "base.py" or f.startswith("_"):
                continue
            mn = "noc.services.web.apps.fm.event.plugins.%s" % f[:-3]
            m = __import__(mn, {}, {}, "*")
            for on in dir(m):
                o = getattr(m, on)
                if (
                    inspect.isclass(o)
                    and issubclass(o, EventPlugin)
                    and o.__module__.startswith(mn)
                ):
                    assert o.name
                    self.plugins[o.name] = o(self)

    def cleaned_query(self, q):
        q = q.copy()
        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]
        # Normalize parameters
        for p in q:
            qp = p.split("__")[0]
            if qp in self.clean_fields:
                q[p] = self.clean_fields[qp].clean(q[p])
        if "administrative_domain" in q:
            a = AdministrativeDomain.objects.get(id=q["administrative_domain"])
            q["managed_object__in"] = a.managedobject_set.values_list("id", flat=True)
            q.pop("administrative_domain")
        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")
        return q

    def instance_to_dict(self, o, fields=None):
        row_class = None
        if o.status in ("A", "S"):
            subject = o.subject
            repeats = o.repeats
            duration = o.duration
            n_alarms = len(o.alarms)
            if n_alarms:
                row_class = AlarmSeverity.get_severity_css_class_name(get_severity(o.alarms))
        else:
            subject = None
            repeats = None
            duration = None
            n_alarms = None
        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,
            "event_class": str(o.event_class.id) if o.status in ("A", "S") else None,
            "event_class__label": o.event_class.name if o.status in ("A", "S") else None,
            "timestamp": self.to_json(o.timestamp),
            "subject": subject,
            "repeats": repeats,
            "duration": duration,
            "alarms": n_alarms,
            "row_class": row_class,
        }
        if fields:
            d = dict((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]
        return model.objects

    @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_event(self, request, id):
        event = get_event(id)
        if not event:
            return self.response_not_found()
        d = self.instance_to_dict(event)
        dd = dict(
            (v, None)
            for v in (
                "body",
                "symptoms",
                "probable_causes",
                "recommended_actions",
                "log",
                "vars",
                "resolved_vars",
                "raw_vars",
            )
        )
        if event.status in ("A", "S"):
            dd["body"] = event.body
            dd["symptoms"] = event.event_class.symptoms
            dd["probable_causes"] = event.event_class.probable_causes
            dd["recommended_actions"] = event.event_class.recommended_actions
            # Fill vars
            left = set(event.vars)
            vars = []
            for ev in event.event_class.vars:
                if ev.name in event.vars:
                    vars += [(ev.name, event.vars[ev.name], ev.description)]
                    left.remove(ev.name)
            vars += [(v, event.vars[v], None) for v in sorted(left)]
            dd["vars"] = vars
            # Fill resolved vars
            vars = []
            is_trap = event.raw_vars.get("source") == "SNMP Trap"
            for v in sorted(event.resolved_vars):
                desc = None
                if is_trap and "::" in v:
                    desc = MIB.get_description(v)
                vars += [(v, event.resolved_vars[v], desc)]
            dd["resolved_vars"] = vars
        dd["raw_vars"] = sorted(event.raw_vars.items())
        # Managed object properties
        mo = event.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["tags"] = mo.tags
        # Log
        if event.log:
            dd["log"] = [
                {
                    "timestamp": self.to_json(l.timestamp),
                    "from_status": l.from_status,
                    "to_status": l.to_status,
                    "message": l.message,
                }
                for l in event.log
            ]
        #
        d.update(dd)
        # Get alarms
        if event.status in ("A", "S"):
            alarms = []
            for a_id in event.alarms:
                a = get_alarm(a_id)
                if not a:
                    continue
                if a.opening_event == event.id:
                    role = "O"
                elif a.closing_event == event.id:
                    role = "C"
                else:
                    role = ""
                alarms += [
                    {
                        "id": str(a.id),
                        "status": a.status,
                        "alarm_class": str(a.alarm_class.id),
                        "alarm_class__label": a.alarm_class.name,
                        "subject": a.subject,
                        "role": role,
                        "timestamp": self.to_json(a.timestamp),
                    }
                ]
            d["alarms"] = alarms
        # Apply plugins
        if event.status in ("A", "S") and event.event_class.plugins:
            plugins = []
            for p in event.event_class.plugins:
                if p.name in self.plugins:
                    plugin = self.plugins[p.name]
                    dd = plugin.get_data(event, p.config)
                    if "plugins" in dd:
                        plugins += dd["plugins"]
                        del dd["plugins"]
                    d.update(dd)
            if plugins:
                d["plugins"] = plugins
        elif event.status == "F":
            # Enable traceback plugin for failed events
            d["traceback"] = event.traceback
            d["plugins"] = [("NOC.fm.event.plugins.Traceback", {})]
        return d

    @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):
        event = get_event(id)
        if not event:
            self.response_not_found()
        event.log_message("%s: %s" % (request.user.username, msg))
        return True

    rx_parse_log = re.compile("^Classified as '(.+?)'.+$")

    @view(url=r"^(?P<id>[a-z0-9]{24})/json/$", method=["GET"], api=True, access="launch")
    def api_json(self, request, id):
        event = get_event(id)
        if not event:
            self.response_not_found()
        # Get event class
        e_class = None
        if event.status in ("A", "S"):
            for l in event.log:
                match = self.rx_parse_log.match(l.message)
                if match:
                    e_class = match.group(1)
        r = ["["]
        r += ["    {"]
        r += ['        "profile": "%s",' % json_escape(event.managed_object.profile.name)]
        if e_class:
            r += ['        "event_class__name": "%s",' % e_class]
        r += ['        "raw_vars": {']
        rr = []
        for k in event.raw_vars:
            if k in ("collector", "severity", "facility"):
                continue
            rr += ['            "%s": "%s"' % (json_escape(k), json_escape(str(event.raw_vars[k])))]
        r += [",\n".join(rr)]
        r += ["        }"]
        r += ["    }"]
        r += ["]"]
        return "\n".join(r)

    @view(url=r"^(?P<id>[a-z0-9]{24})/reclassify/$", method=["POST"], api=True, access="launch")
    def api_reclassify(self, request, id):
        event = get_event(id)
        if not event:
            self.response_not_found()
        if event.status == "N":
            return False
        event.mark_as_new(
            "Event reclassification has been requested " "by user %s" % request.user.username
        )
        return True
Ejemplo n.º 27
0
class GetNowApplication(ExtApplication):
    """
    sa.getnow application
    """
    title = "Get Now"
    menu = "Get Now"
    icon = "icon_monitor"

    ignored_params = [
        "status", "_dc", "managed_object", "profile_name",
        "administrative_domain"
    ]

    clean_fields = {"managed_object": ModelParameter(ManagedObject)}

    @view("^$", method=["GET"], access="read", api=True)
    def api_list(self, request):
        return self.list_data(request, self.instance_to_dict)

    def queryset(self, request, query=None):
        """
        Filter records for lookup
        """
        get_request_data = request.GET
        qs = DiscoveryJob.objects.filter(
            jcls='config_discovery').order_by('status')
        if 'managed_object' in get_request_data:
            qs = qs.filter(object=int(get_request_data['managed_object']))
        if 'profile_name' in get_request_data:
            ids = ManagedObject.objects.filter(
                profile_name=get_request_data['profile_name']).values_list(
                    'id', flat=True)
            qs = qs.filter(object__in=ids)
        if 'administrative_domain' in get_request_data:
            ids = ManagedObject.objects.filter(
                administrative_domain=get_request_data['administrative_domain']
            )
            qs = qs.filter(object__in=ids)
        return qs

    def cleaned_query(self, q):
        to_clean_up = (self.limit_param, self.page_param, self.start_param,
                       self.format_param, self.sort_param, self.query_param,
                       self.only_param)
        q = q.copy()
        for p in self.ignored_params:
            if p in q:
                del q[p]
        for p in to_clean_up:
            if p in q:
                del q[p]
        for p in q:
            qp = p.split("__")[0]
            if qp in self.clean_fields:
                q[p] = self.clean_fields[qp].form_clean(q[p])
        return q

    def instance_to_dict(self, o, fields=None):
        last_success = humanize_distance(o.ts) if o.ts else '--'
        mo = ManagedObject.objects.get(id=o.object)
        last_update = mo.config.get_revisions(reverse=True)
        if last_update:
            last_update = humanize_distance(last_update[0].ts)
        return {
            'id': str(mo.id),
            'name': mo.name,
            'profile_name': mo.profile_name,
            'last_success': last_success,
            'status': o.status,
            'last_status': o.last_status,
            'last_update': last_update if last_update else None
        }