Exemplo n.º 1
0
Arquivo: views.py Projeto: 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],
        }
Exemplo n.º 2
0
Arquivo: views.py Projeto: 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}
Exemplo n.º 3
0
 def init_plugin(self):
     super(DataPlugin, self).init_plugin()
     self.add_view("api_plugin_%s_save_data" % self.name,
                   self.api_save_data,
                   url="^(?P<id>[0-9a-f]{24})/plugin/data/$",
                   method=["PUT"],
                   validate={
                       "interface": StringParameter(),
                       "key": StringParameter(),
                       "value": UnicodeParameter()
                   })
Exemplo n.º 4
0
    def init_plugin(self):
        super().init_plugin()
        self.add_view(
            "api_plugin_%s_get_layer" % self.name,
            self.api_get_layer,
            url=r"^plugin/%s/layers/(?P<layer>\S+)/$" % self.name,
            method=["GET"],
        )
        self.add_view(
            "api_plugin_%s_object_data" % self.name,
            self.api_object_data,
            url="^(?P<id>[0-9a-f]{24})/plugin/%s/object_data/$" % self.name,
            method=["GET"],
        )
        self.add_view(
            "api_plugin_%s_set_geopoint" % self.name,
            self.api_set_geopoint,
            url="^(?P<id>[0-9a-f]{24})/plugin/%s/set_geopoint/$" % self.name,
            method=["POST"],
            validate={
                "srid": StringParameter(),
                "x": FloatParameter(),
                "y": FloatParameter()
            },
        )
        self.add_view(
            "api_plugin_%s_set_layer_visibility" % self.name,
            self.api_set_layer_visibility,
            url="^plugin/%s/layer_visibility/$" % self.name,
            method=["POST"],
            validate={
                "layer": StringParameter(),
                "status": BooleanParameter()
            },
        )

        self.add_view(
            "api_plugin_%s_create" % self.name,
            self.api_create,
            url="^plugin/%s/$" % self.name,
            method=["POST"],
            validate={
                "model": DocumentParameter(ObjectModel),
                "name": UnicodeParameter(),
                "srid": StringParameter(),
                "x": FloatParameter(),
                "y": FloatParameter(),
            },
        )
Exemplo n.º 5
0
Arquivo: views.py Projeto: nbashev/noc
class APITokenApplication(ExtApplication):
    """
    APIToken Application
    """
    @view("^(?P<type>[^/]+)/$",
          method=["GET"],
          access=PermitLogged(),
          api=True)
    def api_get_token(self, request, type):
        token = APIToken.objects.filter(type=type,
                                        user=request.user.id).first()
        if token:
            return {"type": token.type, "token": token.token}
        else:
            self.response_not_found()

    @view(
        "^(?P<type>[^/]+)/$",
        method=["POST"],
        access=PermitLogged(),
        validate={"token": StringParameter()},
        api=True,
    )
    def api_set_token(self, request, type, token=None):
        APIToken._get_collection().update(
            {
                "type": type,
                "user": request.user.id
            }, {"$set": {
                "token": token
            }},
            upsert=True)
Exemplo n.º 6
0
class JSONImportApplication(ExtApplication):
    """
    main.jsonimport application
    """
    title = "JSON Import"
    menu = "Setup | JSON Import"

    @view(url="^$",
          method=["POST"],
          access="launch",
          validate={"json": StringParameter(required=True)},
          api=True)
    def api_import(self, request, json):
        try:
            jdata = json_decode(json)
        except Exception, why:
            return {"status": False, "error": "Invalid JSON: %s" % why}
        try:
            if isinstance(jdata, list):
                for d in jdata:
                    self.import_object(d)
            else:
                self.import_object(jdata)
        except ValueError, why:
            return {"status": False, "error": str(why)}
Exemplo n.º 7
0
class JSONImportApplication(ExtApplication):
    """
    main.jsonimport application
    """

    title = _("JSON Import")
    menu = [_("Setup"), _("JSON Import")]

    @view(
        url="^$",
        method=["POST"],
        access="launch",
        validate={"json": StringParameter(required=True)},
        api=True,
    )
    def api_import(self, request, json):
        try:
            jdata = ujson.loads(json)
        except Exception as e:
            return {"status": False, "error": "Invalid JSON: %s" % e}
        try:
            if isinstance(jdata, list):
                for d in jdata:
                    Collection.install(d)
                    c = Collection(d["$collection"])
                    c.update_item(d)
            else:
                Collection.install(jdata)
                c = Collection(jdata["$collection"])
                c.update_item(jdata)
        except ValueError as e:
            return {"status": False, "error": str(e)}
        return {"status": True}
Exemplo n.º 8
0
def test_dict_parameter():
    assert DictParameter(attrs={
        "i": IntParameter(),
        "s": StringParameter()
    }).clean({
        "i": 10,
        "s": "ten"
    }) == {
        "i": 10,
        "s": "ten"
    }
    with pytest.raises(InterfaceTypeError):
        DictParameter(attrs={
            "i": IntParameter(),
            "s": StringParameter()
        }).clean({
            "i": "10",
            "x": "ten"
        })
Exemplo n.º 9
0
def test_string_parameter():
    assert StringParameter().clean("Test") == "Test"
    assert StringParameter().clean(10) == "10"
    assert StringParameter().clean(None) == "None"
    assert StringParameter(default="test").clean("no test") == "no test"
    assert StringParameter(default="test").clean(None) == "test"
    assert StringParameter(choices=["1", "2"]).clean("1") == "1"
    with pytest.raises(InterfaceTypeError):
        assert StringParameter(choices=["1", "2"]).clean("3")
Exemplo n.º 10
0
def test_listof_parameter():
    assert ListOfParameter(element=IntParameter()).clean([1, 2,
                                                          3]) == [1, 2, 3]
    assert ListOfParameter(element=IntParameter()).clean([1, 2,
                                                          "3"]) == [1, 2, 3]
    with pytest.raises(InterfaceTypeError):
        ListOfParameter(element=IntParameter()).clean([1, 2, "x"])
    assert ListOfParameter(element=StringParameter()).clean(
        [1, 2, 3, "x"]) == ["1", "2", "3", "x"]
    assert ListOfParameter(element=StringParameter(),
                           default=[]).clean(None) == []
    assert ListOfParameter(element=StringParameter(),
                           default=[1, 2, 3]).clean(None) == ["1", "2", "3"]
    assert ListOfParameter(
        element=[StringParameter(), IntParameter()]).clean([
            ("a", 1), ("b", "2")
        ]) == [["a", 1], ["b", 2]]
    with pytest.raises(InterfaceTypeError):
        assert ListOfParameter(
            element=[StringParameter(), IntParameter()]).clean([("a", 1),
                                                                ("b", "x")])
Exemplo n.º 11
0
def test_dictlist_parameter():
    assert DictListParameter().clean([{
        "1": 2
    }, {
        "2": 3,
        "4": 1
    }]) == [{
        "1": 2
    }, {
        "2": 3,
        "4": 1
    }]
    assert DictListParameter(attrs={
        "i": IntParameter(),
        "s": StringParameter()
    }).clean([{
        "i": 10,
        "s": "ten"
    }, {
        "i": "5",
        "s": "five"
    }]) == [{
        "i": 10,
        "s": "ten"
    }, {
        "i": 5,
        "s": "five"
    }]
    assert DictListParameter(attrs={
        "i": IntParameter(),
        "s": StringParameter()
    },
                             convert=True).clean({
                                 "i": "10",
                                 "s": "ten"
                             }) == [{
                                 "i": 10,
                                 "s": "ten"
                             }]
Exemplo n.º 12
0
class AccountApplication(ExtApplication):
    """
    support.account application
    """
    title = _("Account")
    menu = [_("Setup"), _("Account")]

    @view(url="^$", method=["GET"], access="launch", api=True)
    def api_get(self, request):
        c = CPClient()
        data = {}
        if c.has_account():
            data["account"] = c.account_info()
            for i in data["account"].get("industries", []):
                data["account"]["ind_%s" % i] = True
        if c.has_system():
            data["system"] = c.system_info()
        return data

    @view(url="^account/attach/$",
          method=["POST"],
          access="launch",
          api=True,
          validate={
              "name": StringParameter(),
              "password": StringParameter(required=False)
          })
    def api_attach_account(self, request, name, password):
        c = CPClient()
        if c.has_account():
            self.response_forbidden()
        try:
            c.attach_account(name, password)
        except CPClient.Error, why:
            return {"status": False, "message": str(why)}
        return {"status": True, "message": "Ok"}
Exemplo n.º 13
0
def test_string_parameter(raw, config, expected):
    assert StringParameter(**config).clean(raw) == expected
Exemplo n.º 14
0
def test_subclassof_parameter_error(raw, config):
    with pytest.raises(InterfaceTypeError):
        assert SubclassOfParameter(**config).clean(raw)


@pytest.mark.parametrize(
    "raw,config,expected",
    [
        ([1, 2, 3], {
            "element": IntParameter()
        }, [1, 2, 3]),
        ([1, 2, "3"], {
            "element": IntParameter()
        }, [1, 2, 3]),
        ([1, 2, 3, "x"], {
            "element": StringParameter()
        }, ["1", "2", "3", "x"]),
        (None, {
            "element": StringParameter(),
            "default": []
        }, []),
        (None, {
            "element": StringParameter(),
            "default": [1, 2, 3]
        }, ["1", "2", "3"]),
        (
            [("a", 1), ("b", "2")],
            {
                "element": [StringParameter(),
                            IntParameter()]
            },
Exemplo n.º 15
0
from noc.core.topology.constraint.base import BaseConstraint
from noc.core.topology.constraint.vlan import VLANConstraint
from noc.core.topology.constraint.upwards import UpwardsConstraint
from noc.core.topology.constraint.any import AnyConstraint
from noc.core.topology.goal.base import BaseGoal
from noc.core.topology.goal.managedobject import ManagedObjectGoal
from noc.core.topology.goal.level import ManagedObjectLevelGoal
from noc.core.text import split_alnum
from ..base import NBIAPI

# Constants
MAX_DEPTH_DEFAULT = 20
N_SHORTEST_DEFAULT = 10

# id/remote system pointer
PointerId = DictParameter(attrs={"id": StringParameter()})
PointerRemote = DictParameter(attrs={
    "remote_system": StringParameter(),
    "remote_id": StringParameter()
})
Pointer = PointerId | PointerRemote

# from: section
ObjectPointer = DictParameter(
    attrs={
        "object":
        Pointer,
        "interface":
        DictParameter(attrs={"name": StringParameter()}, required=False),
    })
InterfacePointer = DictParameter(
Exemplo n.º 16
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)}
Exemplo n.º 17
0
Arquivo: views.py Projeto: 0pt1on/noc
class ReportInterfaceStatusApplication(ExtApplication):
    menu = _("Reports") + "|" + _("Interface Status")
    title = _("Interface Status")

    @view(
        "^download/$",
        method=["GET"],
        access="launch",
        api=True,
        validate={
            "administrative_domain": StringParameter(required=False),
            "interface_profile": StringParameter(required=False),
            "selector": StringParameter(required=False),
            "zero": StringParameter(required=False),
            "def_profile": StringParameter(required=False),
            "columns": StringParameter(required=False),
            "o_format": StringParameter(choices=["csv", "xlsx"]),
        },
    )
    def api_report(
        self,
        request,
        o_format,
        administrative_domain=None,
        selector=None,
        interface_profile=None,
        zero=None,
        def_profile=None,
        columns=None,
        enable_autowidth=False,
    ):
        def humanize_speed(speed):
            if not speed:
                return "-"
            for t, n in [(1000000, "G"), (1000, "M"), (1, "k")]:
                if speed >= t:
                    if speed // t * t == speed:
                        return "%d%s" % (speed // t, n)
                    else:
                        return "%.2f%s" % (float(speed) / t, n)
            return str(speed)

        def row(row):
            def qe(v):
                if v is None:
                    return ""
                if isinstance(v, unicode):
                    return v.encode("utf-8")
                elif isinstance(v, datetime.datetime):
                    return v.strftime("%Y-%m-%d %H:%M:%S")
                elif not isinstance(v, str):
                    return str(v)
                else:
                    return v

            return [qe(x) for x in row]

        def translate_row(row, cmap):
            return [row[i] for i in cmap]

        cols = [
            "object_name",
            "object_address",
            "object_model",
            "object_software",
            "object_port_name",
            "object_port_profile_name",
            "object_port_status",
            "object_link_status",
            "object_port_speed",
            "object_port_duplex",
            "object_port_untagged_vlan",
            "object_port_tagged_vlans",
        ]

        header_row = [
            "MANAGED_OBJECT",
            "OBJECT_ADDRESS",
            "OBJECT_MODEL",
            "OBJECT_SOFTWARE",
            "PORT_NAME",
            "PORT_PROFILE_NAME",
            "PORT_STATUS",
            "LINK_STATUS",
            "PORT_SPEED",
            "PORT_DUPLEX",
            "PORT_UNTAGGED_VLAN",
            "PORT_TAGGED_VLANS",
        ]

        if columns:
            cmap = []
            for c in columns.split(","):
                try:
                    cmap += [cols.index(c)]
                except ValueError:
                    continue
        else:
            cmap = list(range(len(cols)))

        r = [translate_row(header_row, cmap)]
        mo = {}
        if_p = {}
        DUPLEX = {True: "Full", False: "Half"}

        for ifp in InterfaceProfile.objects.filter():
            if_p[ifp.id] = {"name": ifp.name}
        mos = ManagedObject.objects.filter(is_managed=True)
        if (request.user.is_superuser and not administrative_domain
                and not selector and not interface_profile):
            mos = ManagedObject.objects.filter(is_managed=True)
        if not request.user.is_superuser:
            mos = mos.filter(
                administrative_domain__in=UserAccess.get_domains(request.user))
        if administrative_domain:
            ads = AdministrativeDomain.get_nested_ids(
                int(administrative_domain))
            mos = mos.filter(administrative_domain__in=ads)
        if selector:
            selector = ManagedObjectSelector.get_by_id(int(selector))
            mos = mos.filter(selector.Q)

        for o in mos:
            mo[o.id] = {
                "type": "managedobject",
                "id": str(o.id),
                "name": o.name,
                "status": o.is_managed,
                "address": o.address,
                "vendor": o.vendor,
                "version": o.version,
                "platform": o.platform,
            }

        mos_id = list(mos.values_list("id", flat=True))

        rld = ReportInterfaceStatus(mos_id, zero, def_profile,
                                    interface_profile)

        for i in rld.out:
            untag, tagged = "", ""
            if i["subs"]:
                untag = i["subs"][0].get("untagged_vlan", "")
                tagged = list_to_ranges(i["subs"][0].get("tagged_vlans", []))
            r += [
                translate_row(
                    row([
                        mo[i["managed_object"]]["name"],
                        mo[i["managed_object"]]["address"],
                        "%s %s" % (
                            str(mo[i["managed_object"]]["vendor"]),
                            str(mo[i["managed_object"]]["platform"]),
                        ),
                        str(mo[i["managed_object"]]["version"]),
                        i["name"],
                        if_p[i["profile"]]["name"],
                        "UP" if i["admin_status"] is True else "Down",
                        "UP" if "oper_status" in i and i["oper_status"] is True
                        else "Down",
                        humanize_speed(i["in_speed"])
                        if "in_speed" in i else "-",
                        DUPLEX.get(i["full_duplex"])
                        if "full_duplex" in i and "in_speed" in i else "-",
                        untag,
                        tagged,
                    ]),
                    cmap,
                )
            ]

        filename = "interface_status_report_%s" % datetime.datetime.now(
        ).strftime("%Y%m%d")
        if o_format == "csv":
            response = HttpResponse(content_type="text/csv")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.csv"' % filename
            writer = csv.writer(response, dialect="excel", delimiter=";")
            writer.writerows(r)
            return response
        elif o_format == "xlsx":
            response = StringIO()
            wb = xlsxwriter.Workbook(response)
            cf1 = wb.add_format({"bottom": 1, "left": 1, "right": 1, "top": 1})
            ws = wb.add_worksheet("Objects")
            max_column_data_length = {}
            for rn, x in enumerate(r):
                for cn, c in enumerate(x):
                    if rn and (r[0][cn] not in max_column_data_length or
                               len(str(c)) > max_column_data_length[r[0][cn]]):
                        max_column_data_length[r[0][cn]] = len(str(c))
                    ws.write(rn, cn, c, cf1)
            ws.autofilter(0, 0, rn, cn)
            ws.freeze_panes(1, 0)
            for cn, c in enumerate(r[0]):
                # Set column width
                width = get_column_width(c)
                if enable_autowidth and width < max_column_data_length[c]:
                    width = max_column_data_length[c]
                ws.set_column(cn, cn, width=width)
            wb.close()
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/vnd.ms-excel")
            # response = HttpResponse(
            #     content_type="application/x-ms-excel")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.xlsx"' % filename
            response.close()
            return response
Exemplo n.º 18
0
from noc.sa.interfaces.base import (
    DictParameter,
    DictListParameter,
    StringParameter,
    StringListParameter,
    IntParameter,
    ListOfParameter,
    ListParameter,
)
from noc.pm.models.metrictype import MetricType
from noc.services.nbi.base import NBIAPI

Request = DictParameter(
    attrs={
        "host": StringParameter(required=True),
        "port": StringParameter(required=True),
        "sn": StringParameter(required=True),
    })


class GetllidzteAPI(NBIAPI):
    name = "getllidzte"

    @authenticated
    @tornado.gen.coroutine
    def post(self):
        connect()
        code, result = yield self.executor.submit(self.handler)
        self.set_status(code)
        if isinstance(result, six.string_types):
Exemplo n.º 19
0
from noc.pm.models.metrictype import MetricType
from noc.core.clickhouse.connect import ClickhouseClient
from noc.core.clickhouse.error import ClickhouseError
from noc.sa.models.profile import Profile
from ..base import NBIAPI

Request = DictParameter(
    attrs={
        "from":
        DateTimeShiftParameter(required=True),
        "to":
        DateTimeShiftParameter(required=True),
        "metrics":
        DictListParameter(
            attrs={
                "object": StringParameter(required=True),
                "interfaces": StringListParameter(required=False),
                "metric_types": StringListParameter(required=True),
            },
            required=True,
        ),
    })

S_INTERFACE = "interface"


class ObjectMetricsAPI(NBIAPI):
    name = "objectmetrics"

    @authenticated
    @tornado.gen.coroutine
Exemplo n.º 20
0
from noc.sa.interfaces.base import (
    DictParameter,
    DictListParameter,
    StringParameter,
    StringListParameter,
    IntParameter,
    ListOfParameter,
    ListParameter,
)
from noc.pm.models.metrictype import MetricType
from noc.services.nbi.base import NBIAPI

Request = DictParameter(
    attrs={
        "org": StringParameter(required=True),
    }
)


class GetoltAPI(NBIAPI):
    name = "getolt"

    @authenticated
    @tornado.gen.coroutine
    def post(self):
        connect()
        code, result = yield self.executor.submit(self.handler)
        self.set_status(code)
        if isinstance(result, six.string_types):
            self.write(result)
Exemplo n.º 21
0
def test_string_parameter_error(raw, config):
    with pytest.raises(InterfaceTypeError):
        assert StringParameter(**config).clean(raw)
Exemplo n.º 22
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 ["", ""]
Exemplo n.º 23
0
class ReportLinkDetailApplication(ExtApplication):
    menu = _("Reports") + "|" + _("Link Detail")
    title = _("Link Detail")

    SEGMENT_PATH_DEPTH = 7
    CONTAINER_PATH_DEPTH = 7

    @view(
        "^download/$",
        method=["GET"],
        access="launch",
        api=True,
        validate={
            "administrative_domain": StringParameter(required=False),
            "pool": StringParameter(required=False),
            "segment": StringParameter(required=False),
            "selector": StringParameter(required=False),
            "ids": StringParameter(required=False),
            "is_managed": BooleanParameter(required=False),
            "avail_status": BooleanParameter(required=False),
            "columns": StringParameter(required=False),
            "o_format": StringParameter(choices=["csv", "csv_zip", "xlsx"]),
        },
    )
    def api_report(
        self,
        request,
        o_format,
        is_managed=None,
        administrative_domain=None,
        selector=None,
        pool=None,
        segment=None,
        avail_status=False,
        columns=None,
        ids=None,
        enable_autowidth=False,
    ):
        def row(row):
            def qe(v):
                if v is None:
                    return ""
                if isinstance(v, str):
                    return smart_text(v)
                elif isinstance(v, datetime.datetime):
                    return v.strftime("%Y-%m-%d %H:%M:%S")
                elif not isinstance(v, str):
                    return str(v)
                else:
                    return v

            return [qe(x) for x in row]

        def translate_row(row, cmap):
            return [row[i] for i in cmap]

        type_columns = ["Up/10G", "Up/1G", "Up/100M", "Down/-", "-"]

        cols = [
            "object1_admin_domain",
            # "id",
            "object1_name",
            "object1_address",
            "object1_platform",
            "object1_segment",
            "object1_tags",
            "object1_iface",
            "object1_descr",
            "object1_speed",
            "object2_admin_domain",
            "object2_name",
            "object2_address",
            "object2_platform",
            "object2_segment",
            "object2_tags",
            "object2_iface",
            "object2_descr",
            "object2_speed",
            "link_proto",
            "last_seen",
        ]

        header_row = [
            "OBJECT1_ADMIN_DOMAIN",
            "OBJECT1_NAME",
            "OBJECT1_ADDRESS",
            "OBJECT1_PLATFORM",
            "OBJECT1_SEGMENT",
            "OBJECT1_TAGS",
            "OBJECT1_IFACE",
            "OBJECT1_DESCR",
            "OBJECT1_SPEED",
            "OBJECT2_ADMIN_DOMAIN",
            "OBJECT2_NAME",
            "OBJECT2_ADDRESS",
            "OBJECT2_PLATFORM",
            "OBJECT2_SEGMENT",
            "OBJECT2_TAGS",
            "OBJECT2_IFACE",
            "OBJECT2_DESCR",
            "OBJECT2_SPEED",
            "LINK_PROTO",
            "LAST_SEEN",
        ]

        if columns:
            cmap = []
            for c in columns.split(","):
                try:
                    cmap += [cols.index(c)]
                except ValueError:
                    continue
        else:
            cmap = list(range(len(cols)))
        r = [translate_row(header_row, cmap)]
        if "interface_type_count" in columns.split(","):
            r[-1].extend(type_columns)
        # self.logger.info(r)
        # self.logger.info("---------------------------------")
        # print("-----------%s------------%s" % (administrative_domain, columns))

        p = Pool.get_by_name(pool or "default")
        mos = ManagedObject.objects.filter()
        if request.user.is_superuser and not administrative_domain and not selector and not segment:
            mos = ManagedObject.objects.filter(pool=p)
        if ids:
            mos = ManagedObject.objects.filter(id__in=[ids])
        if is_managed is not None:
            mos = ManagedObject.objects.filter(is_managed=is_managed)
        if pool:
            mos = mos.filter(pool=p)
        if not request.user.is_superuser:
            mos = mos.filter(
                administrative_domain__in=UserAccess.get_domains(request.user))
        if administrative_domain:
            ads = AdministrativeDomain.get_nested_ids(
                int(administrative_domain))
            mos = mos.filter(administrative_domain__in=ads)
        if selector:
            selector = ManagedObjectSelector.get_by_id(int(selector))
            mos = mos.filter(selector.Q)
        if segment:
            segment = NetworkSegment.objects.filter(id=segment).first()
            if segment:
                mos = mos.filter(segment__in=segment.get_nested_ids())
        mos_id = list(mos.values_list("id", flat=True))

        rld = ReportLinksDetail(mos_id)
        mo_resolv = {
            mo[0]: mo[1:]
            for mo in ManagedObject.objects.filter().values_list(
                "id",
                "administrative_domain__name",
                "name",
                "address",
                "segment",
                "platform",
                "labels",
            )
        }

        for link in rld.out:
            if len(rld.out[link]) != 2:
                # Multilink or bad link
                continue
            s1, s2 = rld.out[link]
            seg1, seg2 = None, None
            if "object1_segment" in columns.split(
                    ",") or "object2_segment" in columns.split(","):
                seg1, seg2 = mo_resolv[s1["mo"][0]][3], mo_resolv[s2["mo"]
                                                                  [0]][3]
            plat1, plat2 = None, None
            if "object1_platform" in columns.split(
                    ",") or "object2_platform" in columns.split(","):
                plat1, plat2 = mo_resolv[s1["mo"][0]][4], mo_resolv[s2["mo"]
                                                                    [0]][4]
            r += [
                translate_row(
                    row([
                        mo_resolv[s1["mo"][0]][0],
                        mo_resolv[s1["mo"][0]][1],
                        mo_resolv[s1["mo"][0]][2],
                        "" if not plat1 else Platform.get_by_id(plat1),
                        "" if not seg1 else NetworkSegment.get_by_id(seg1),
                        ";".join(mo_resolv[s1["mo"][0]][5] or []),
                        s1["iface_n"][0],
                        s1.get("iface_descr")[0]
                        if s1.get("iface_descr") else "",
                        s1.get("iface_speed")[0]
                        if s1.get("iface_speed") else 0,
                        mo_resolv[s2["mo"][0]][0],
                        mo_resolv[s2["mo"][0]][1],
                        mo_resolv[s2["mo"][0]][2],
                        "" if not plat2 else Platform.get_by_id(plat2),
                        "" if not seg2 else NetworkSegment.get_by_id(seg2),
                        ";".join(mo_resolv[s2["mo"][0]][5] or []),
                        s2["iface_n"][0],
                        s2.get("iface_descr")[0]
                        if s2.get("iface_descr") else "",
                        s2.get("iface_speed")[0]
                        if s2.get("iface_speed") else 0,
                        s2.get("dis_method", ""),
                        s2.get("last_seen", ""),
                    ]),
                    cmap,
                )
            ]
        filename = "links_detail_report_%s" % datetime.datetime.now().strftime(
            "%Y%m%d")
        if o_format == "csv":
            response = HttpResponse(content_type="text/csv")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.csv"' % filename
            writer = csv.writer(response,
                                dialect="excel",
                                delimiter=",",
                                quoting=csv.QUOTE_MINIMAL)
            writer.writerows(r)
            return response
        elif o_format == "csv_zip":
            response = BytesIO()
            f = TextIOWrapper(TemporaryFile(mode="w+b"), encoding="utf-8")
            writer = csv.writer(f,
                                dialect="excel",
                                delimiter=";",
                                quotechar='"')
            writer.writerows(r)
            f.seek(0)
            with ZipFile(response, "w", compression=ZIP_DEFLATED) as zf:
                zf.writestr("%s.csv" % filename, f.read())
                zf.filename = "%s.csv.zip" % filename
            # response = HttpResponse(content_type="text/csv")
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/zip")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.csv.zip"' % filename
            return response
        elif o_format == "xlsx":
            response = BytesIO()
            wb = xlsxwriter.Workbook(response)
            cf1 = wb.add_format({"bottom": 1, "left": 1, "right": 1, "top": 1})
            ws = wb.add_worksheet("Objects")
            max_column_data_length = {}
            for rn, x in enumerate(r):
                for cn, c in enumerate(x):
                    if rn and (r[0][cn] not in max_column_data_length or
                               len(str(c)) > max_column_data_length[r[0][cn]]):
                        max_column_data_length[r[0][cn]] = len(str(c))
                    ws.write(rn, cn, c, cf1)
            ws.autofilter(0, 0, rn, cn)
            ws.freeze_panes(1, 0)
            for cn, c in enumerate(r[0]):
                # Set column width
                width = get_column_width(c)
                if enable_autowidth and width < max_column_data_length[c]:
                    width = max_column_data_length[c]
                ws.set_column(cn, cn, width=width)
            wb.close()
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/vnd.ms-excel")
            # response = HttpResponse(
            #     content_type="application/x-ms-excel")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.xlsx"' % filename
            response.close()
            return response
Exemplo n.º 24
0
class ReportObjectDetailApplication(ExtApplication):
    menu = _("Reports") + "|" + _("Object Detail")
    title = _("Object Detail")

    SEGMENT_PATH_DEPTH = 7
    CONTAINER_PATH_DEPTH = 7

    def get_report_object(self,
                          user=None,
                          is_managed=None,
                          adm=None,
                          selector=None,
                          pool=None,
                          segment=None,
                          ids=None):
        mos = ManagedObject.objects.filter()
        if user.is_superuser and not adm and not selector and not segment:
            mos = ManagedObject.objects.filter()
        if ids:
            mos = ManagedObject.objects.filter(id__in=[ids])
        if is_managed is not None:
            mos = ManagedObject.objects.filter(is_managed=is_managed)
        if pool:
            p = Pool.get_by_name(pool or "default")
            mos = mos.filter(pool=p)
        if not user.is_superuser:
            mos = mos.filter(
                administrative_domain__in=UserAccess.get_domains(user))
        if adm:
            ads = AdministrativeDomain.get_nested_ids(int(adm))
            mos = mos.filter(administrative_domain__in=ads)
        if selector:
            selector = ManagedObjectSelector.get_by_id(int(selector))
            mos = mos.filter(selector.Q)
        if segment:
            segment = NetworkSegment.objects.filter(id=segment).first()
            if segment:
                mos = mos.filter(segment__in=segment.get_nested_ids())
        return mos

    @view(
        "^download/$",
        method=["GET"],
        access="launch",
        api=True,
        validate={
            "administrative_domain": StringParameter(required=False),
            "pool": StringParameter(required=False),
            "segment": StringParameter(required=False),
            "selector": StringParameter(required=False),
            "ids": StringParameter(required=False),
            "detail_stat": StringParameter(required=False),
            "is_managed": BooleanParameter(required=False),
            "avail_status": BooleanParameter(required=False),
            "columns": StringParameter(required=False),
            "o_format": StringParameter(choices=["csv", "xlsx"]),
        },
    )
    def api_report(
        self,
        request,
        o_format,
        is_managed=None,
        administrative_domain=None,
        selector=None,
        pool=None,
        segment=None,
        avail_status=False,
        columns=None,
        ids=None,
        detail_stat=None,
        enable_autowidth=False,
    ):
        def row(row):
            def qe(v):
                if v is None:
                    return ""
                if isinstance(v, unicode):
                    return v.encode("utf-8")
                elif isinstance(v, datetime.datetime):
                    return v.strftime("%Y-%m-%d %H:%M:%S")
                elif not isinstance(v, str):
                    return str(v)
                else:
                    return v

            return [qe(x) for x in row]

        def translate_row(row, cmap):
            return [row[i] for i in cmap]

        type_columns = ["Up/10G", "Up/1G", "Up/100M", "Up/10M", "Down/-", "-"]
        cols = [
            "id", "object_name", "object_address", "object_hostname",
            "object_status", "profile_name", "object_profile", "object_vendor",
            "object_platform", "object_attr_hwversion", "object_version",
            "object_attr_bootprom", "object_serial", "object_attr_patch",
            "auth_profile", "avail", "admin_domain", "container", "segment",
            "phys_interface_count", "link_count", "last_config_ts"
            # "discovery_problem"
            # "object_tags"
            # "sorted_tags"
            # "object_caps"
            # "interface_type_count"
        ]

        header_row = [
            "ID",
            "OBJECT_NAME",
            "OBJECT_ADDRESS",
            "OBJECT_HOSTNAME",
            "OBJECT_STATUS",
            "PROFILE_NAME",
            "OBJECT_PROFILE",
            "OBJECT_VENDOR",
            "OBJECT_PLATFORM",
            "OBJECT_HWVERSION",
            "OBJECT_VERSION",
            "OBJECT_BOOTPROM",
            "OBJECT_SERIAL",
            "OBJECT_ATTR_PATCH",
            "AUTH_PROFILE",
            "AVAIL",
            "ADMIN_DOMAIN",
            "CONTAINER",
            "SEGMENT",
            "PHYS_INTERFACE_COUNT",
            "LINK_COUNT",
            "LAST_CONFIG_TS",
        ]
        # "DISCOVERY_PROBLEM"
        # "ADM_PATH
        # "DISCOVERY_PROBLEM"
        # "OBJECT_TAGS"
        # "SORTED_TAGS"
        # "OBJECT_CAPS"
        # "INTERFACE_TYPE_COUNT"

        if columns:
            cmap = []
            for c in columns.split(","):
                try:
                    cmap += [cols.index(c)]
                except ValueError:
                    continue
        else:
            cmap = list(range(len(cols)))
        r = [translate_row(header_row, cmap)]
        mos = self.get_report_object(request.user, is_managed,
                                     administrative_domain, selector, pool,
                                     segment, ids)
        columns_filter = set(columns.split(","))
        mos_id = tuple(mos.order_by("id").values_list("id", flat=True))
        mos_filter = None
        if detail_stat:
            ref = ReportModelFilter()
            ids = list(six.itervalues(ref.proccessed(detail_stat)))
            mos_filter = set(mos_id).intersection(ids[0])
            mos_id = sorted(mos_filter)
        avail = {}
        if "avail" in columns_filter:
            avail = ObjectStatus.get_statuses(mos_id)
        link_count = iter(ReportObjectLinkCount(mos_id))
        iface_count = iter(ReportObjectIfacesTypeStat(mos_id))
        if "container" in columns_filter:
            container_lookup = iter(ReportContainerData(mos_id))
        else:
            container_lookup = None
        if "object_serial" in columns_filter:
            container_serials = iter(ReportContainer(mos_id))
        else:
            container_serials = None
        if "interface_type_count" in columns_filter:
            iss = iter(ReportObjectIfacesStatusStat(mos_id))
        else:
            iss = None
        if "object_attr_patch" in columns_filter or "object_serial" in columns_filter:
            roa = iter(ReportObjectAttributes(mos_id))
        else:
            roa = None
        hn = iter(ReportObjectsHostname1(mos_id))
        rc = iter(ReportObjectConfig(mos_id))
        # ccc = iter(ReportObjectCaps(mos_id))
        if "adm_path" in columns_filter:
            ad_path = ReportAdPath()
            r[-1].extend([_("ADM_PATH1"), _("ADM_PATH1"), _("ADM_PATH1")])
        if "interface_type_count" in columns_filter:
            r[-1].extend(type_columns)
        if "object_caps" in columns_filter:
            object_caps = ReportObjectCaps(mos_id)
            caps_columns = list(six.itervalues(object_caps.ATTRS))
            ccc = iter(object_caps)
            r[-1].extend(caps_columns)
        if "object_tags" in columns_filter:
            r[-1].extend([_("OBJECT_TAGS")])
        if "sorted_tags" in columns_filter:
            tags = set()
            for s in (ManagedObject.objects.filter().exclude(
                    tags=None).values_list("tags", flat=True).distinct()):
                tags.update(set(s))
            tags_o = sorted([t for t in tags if "{" not in t])
            r[-1].extend(tags_o)
        if "discovery_problem" in columns.split(","):
            discovery_result = ReportDiscoveryResult(mos_id)
            discovery_result.safe_output = True
            discovery_result.unknown_value = ([""] *
                                              len(discovery_result.ATTRS), )
            dp_columns = discovery_result.ATTRS
            dp = iter(discovery_result)
            r[-1].extend(dp_columns)
        for (
                mo_id,
                name,
                address,
                is_managed,
                sa_profile,
                o_profile,
                auth_profile,
                ad,
                m_segment,
                vendor,
                platform,
                version,
                tags,
        ) in (mos.values_list(
                "id",
                "name",
                "address",
                "is_managed",
                "profile",
                "object_profile__name",
                "auth_profile__name",
                "administrative_domain__name",
                "segment",
                "vendor",
                "platform",
                "version",
                "tags",
        ).order_by("id").iterator()):
            if (mos_filter and mo_id not in mos_filter) or not mos_id:
                continue
            if container_serials:
                mo_serials = next(container_serials)
            else:
                mo_serials = [{}]
            if container_lookup:
                mo_continer = next(container_lookup)
            else:
                mo_continer = ("", )
            if roa:
                serial, hw_ver, boot_prom, patch = next(roa)[0]  # noqa
            else:
                serial, hw_ver, boot_prom, patch = "", "", "", ""  # noqa
            r.append(
                translate_row(
                    row([
                        mo_id,
                        name,
                        address,
                        next(hn)[0],
                        "managed" if is_managed else "unmanaged",
                        Profile.get_by_id(sa_profile),
                        o_profile,
                        Vendor.get_by_id(vendor) if vendor else "",
                        Platform.get_by_id(platform) if platform else "",
                        hw_ver,
                        Firmware.get_by_id(version) if version else "",
                        boot_prom,
                        # Serial
                        mo_serials[0].get("serial", "") or serial,
                        patch or "",
                        auth_profile,
                        _("Yes") if avail.get(mo_id, None) else _("No"),
                        ad,
                        mo_continer[0],
                        NetworkSegment.get_by_id(m_segment)
                        if m_segment else "",
                        next(iface_count)[0],
                        next(link_count)[0],
                        next(rc)[0],
                    ]),
                    cmap,
                ))
            if "adm_path" in columns_filter:
                r[-1].extend([ad] + list(ad_path[ad]))
            if "interface_type_count" in columns_filter:
                r[-1].extend(next(iss)[0])
            if "object_caps" in columns_filter:
                r[-1].extend(next(ccc)[0])
            if "object_tags" in columns_filter:
                r[-1].append(",".join(tags if tags else []))
            if "sorted_tags" in columns_filter:
                out_tags = [""] * len(tags_o)
                try:
                    if tags:
                        for m in tags:
                            out_tags[tags_o.index(m)] = m
                except ValueError:
                    logger.warning("Bad value for tag: %s", m)
                r[-1].extend(out_tags)
            if "discovery_problem" in columns_filter:
                r[-1].extend(next(dp)[0])
        filename = "mo_detail_report_%s" % datetime.datetime.now().strftime(
            "%Y%m%d")
        if o_format == "csv":
            response = HttpResponse(content_type="text/csv")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.csv"' % filename
            writer = csv.writer(response,
                                dialect="excel",
                                delimiter=";",
                                quotechar='"')
            writer.writerows(r)
            return response
        elif o_format == "xlsx":
            response = StringIO()
            wb = xlsxwriter.Workbook(response)
            cf1 = wb.add_format({"bottom": 1, "left": 1, "right": 1, "top": 1})
            ws = wb.add_worksheet("Objects")
            max_column_data_length = {}
            for rn, x in enumerate(r):
                for cn, c in enumerate(x):
                    if rn and (r[0][cn] not in max_column_data_length or
                               len(str(c)) > max_column_data_length[r[0][cn]]):
                        max_column_data_length[r[0][cn]] = len(str(c))
                    ws.write(rn, cn, c, cf1)
            # for
            ws.autofilter(0, 0, rn, cn)
            ws.freeze_panes(1, 0)
            for cn, c in enumerate(r[0]):
                # Set column width
                width = get_column_width(c)
                if enable_autowidth and width < max_column_data_length[c]:
                    width = max_column_data_length[c]
                ws.set_column(cn, cn, width=width)
            wb.close()
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/vnd.ms-excel")
            # response = HttpResponse(
            #     content_type="application/x-ms-excel")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.xlsx"' % filename
            response.close()
            return response
Exemplo n.º 25
0
class UserApplication(ExtModelApplication):
    model = User

    glyph = "user"
    menu = [_("Setup"), _("Users")]
    icon = "icon_user"
    title = _("Users")
    app_alias = "auth"
    query_condition = "icontains"
    query_fields = ["username"]
    default_ordering = ["username"]
    clean_fields = {
        "username": UsernameParameter(),
        "first_name": StringParameter(default=""),
        "last_name": StringParameter(default=""),
        "email": StringParameter(default=""),
    }
    ignored_fields = {"id", "bi_id", "password"}
    custom_m2m_fields = {"permissions": Permission}

    @classmethod
    def apps_permissions_list(cls):
        r = []
        apps = list(site.apps)
        perms = Permission.objects.values_list("name", flat=True)
        for module in [m for m in settings.INSTALLED_APPS if m.startswith("noc.")]:
            mod = module[4:]
            m = __import__("noc.services.web.apps.%s" % mod, {}, {}, "MODULE_NAME")
            for app in [app for app in apps if app.startswith(mod + ".")]:
                app_perms = sorted([p for p in perms if p.startswith(app.replace(".", ":") + ":")])
                a = site.apps[app]
                if app_perms:
                    for p in app_perms:
                        r += [
                            {
                                "module": m.MODULE_NAME,
                                "title": str(a.title),
                                "name": p,
                                "status": False,
                            }
                        ]
        return r

    @view(method=["GET"], url=r"^(?P<id>\d+)/?$", access="read", api=True)
    def api_read(self, request, id):
        """
        Returns dict with object's fields and values
        """
        try:
            o = self.queryset(request).get(**{self.pk: int(id)})
        except self.model.DoesNotExist:
            return HttpResponse("", status=self.NOT_FOUND)
        only = request.GET.get(self.only_param)
        if only:
            only = only.split(",")
        return self.response(self.instance_to_dict_get(o, fields=only), status=self.OK)

    def instance_to_dict_get(self, o, fields=None):
        r = super().instance_to_dict(o, fields)
        del r["password"]
        r["permissions"] = self.apps_permissions_list()
        current_perms = Permission.get_user_permissions(o)
        if current_perms:
            for p in r["permissions"]:
                if p["name"] in current_perms:
                    p["status"] = True
        return r

    def clean_list_data(self, data):
        """
        Finally process list_data result. Override to enrich with
        additional fields
        :param data:
        :return:
        """
        r = super().apply_bulk_fields(data=data)
        for x in r:
            if "password" in x:
                del x["password"]
        return r

    def update_m2m(self, o, name, values):
        if values is None:
            return  # Do not touch
        if name == "permissions":
            Permission.set_user_permissions(user=o, perms=values)
        else:
            super().update_m2m(o, name, values)

    @view(method=["GET"], url=r"^new_permissions/$", access="read", api=True)
    def api_read_permission(self, request):
        """
        Returns dict available permissions
        """
        return self.response(
            {"data": {"user_permissions": self.apps_permissions_list()}}, status=self.OK
        )

    @view(
        url=r"^(\d+)/password/$",
        method=["POST"],
        access="change",
        validate={"password": StringParameter(required=True)},
    )
    def view_change_password(self, request, object_id, password):
        """
        Change user's password
        :param request:
        :param object_id:
        :param password:
        :return:
        """
        if not request.user.is_superuser:
            return self.response_forbidden("Permission denied")
        user = self.get_object_or_404(self.model, pk=object_id)
        user.set_password(password)
        user.save()
        return self.response({"result": "Password changed", "status": True}, self.OK)

    def can_delete(self, user, obj=None):
        """Disable 'Delete' button"""
        return False
Exemplo n.º 26
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
Exemplo n.º 27
0
class InvApplication(ExtApplication):
    """
    inv.inv application
    """
    title = "Inventory"
    menu = "Inventory"

    # Undeletable nodes
    UNDELETABLE = set([
        # Global Lost&Found
        "b0fae773-b214-4edf-be35-3468b53b03f2"
    ])

    def __init__(self, *args, **kwargs):
        ExtApplication.__init__(self, *args, **kwargs)
        # Load plugins
        from plugins.base import InvPlugin
        self.plugins = {}
        for f in os.listdir("inv/apps/inv/plugins/"):
            if (not f.endswith(".py") or
                    f == "base.py" or
                    f.startswith("_")):
                continue
            mn = "noc.inv.apps.inv.plugins.%s" % f[:-3]
            m = __import__(mn, {}, {}, "*")
            for on in dir(m):
                o = getattr(m, on)
                if (inspect.isclass(o) and
                        issubclass(o, InvPlugin) and
                        o.__module__.startswith(mn)):
                    assert o.name
                    self.plugins[o.name] = o(self)

    def get_root(self):
        """
        Get root container
        """
        if not hasattr(self, "root_container"):
            rm = ObjectModel.objects.get(name="Root")
            rc = list(Object.objects.filter(model=rm))
            if len(rc) == 0:
                raise Exception("No root object")
            elif len(rc) == 1:
                self.root_container = rc[0]
                return self.root_container
            else:
                raise Exception("Multiple root objects")
        else:
            return self.root_container

    def get_plugin_data(self, name):
        return {
            "name": name,
            "xtype": self.plugins[name].js
        }

    @view("^node/$", method=["GET"],
          access="read", api=True)
    def api_node(self, request):
        container = None
        if request.GET and "node" in request.GET:
            container = request.GET["node"]
            if container == "root":
                container = self.get_root()
            elif not is_objectid(container):
                raise Exception("Invalid node")
            else:
                container = self.get_object_or_404(Object, id=container)
        r = []
        if not container:
            container = self.get_root()
        # Collect children objects
        children = [
            (o.name, o)
            for o in Object.objects.filter(container=container.id)
        ]
        # Collect inner connections
        children += [
            (name, o) for name, o, _ in container.get_inner_connections()
        ]
        # Build node interface
        for name, o in children:
            m_plugins = o.model.plugins or []
            disabled_plugins = set(p[1:] for p in m_plugins if p.startswith("-"))
            n = {
                "id": str(o.id),
                "name": name,
                "plugins": [],
                "can_add": bool(o.get_data("container", "container")),
                "can_delete": str(o.model.uuid) not in self.UNDELETABLE
            }
            if (o.get_data("container", "container") or
                    o.has_inner_connections()):
                n["expanded"] = Object.objects.filter(container=o.id).count() == 1
            else:
                n["leaf"] = True
            if o.get_data("rack", "units"):
                n["plugins"] += [self.get_plugin_data("rack")]
            if o.model.connections:
                n["plugins"] += [self.get_plugin_data("inventory")]
            if o.get_data("geopoint", "layer"):
                n["plugins"] += [self.get_plugin_data("map")]
            if o.get_data("management", "managed_object"):
                n["plugins"] += [self.get_plugin_data("managedobject")]
            # Append model's plugins
            for p in m_plugins:
                if not p.startswith("-"):
                    n["plugins"] += [self.get_plugin_data(p)]
            n["plugins"] += [
                self.get_plugin_data("data"),
                self.get_plugin_data("comment"),
                self.get_plugin_data("file"),
                self.get_plugin_data("log")
            ]
            # Process disabled plugins
            n["plugins"] = [p for p in n["plugins"] if p["name"] not in disabled_plugins]
            r += [n]
        return r

    @view("^add_group/$", method=["POST"], access="create_group",
          api=True,
          validate={
              "container": ObjectIdParameter(required=False),
              "type": ObjectIdParameter(),
              "name": UnicodeParameter(),
              "serial": UnicodeParameter(required=False)
          })
    def api_add_group(self, request, type, name, container=None,
                      serial=None):
        if container is None:
            c = self.get_root()
        else:
            c = self.get_object_or_404(Object, id=container)
        m = self.get_object_or_404(ObjectModel, id=type)
        o = Object(name=name, model=m, container=c.id)
        if serial and m.get_data("asset", "part_no0"):
            o.set_data("asset", "serial", serial)
        o.save()
        o.log("Created", user=request.user.username,
              system="WEB", op="CREATE")
        return str(o.id)

    @view("^remove_group/$", method=["DELETE"], access="remove_group",
          api=True,
          validate={
              "container": ObjectIdParameter(required=True)
          })
    def api_remove_group(self, request, container=None):
        c = self.get_object_or_404(Object, id=container)
        c.delete()
        return True

    @view("^insert/$", method=["POST"], access="reorder", api=True,
          validate={
              "container": ObjectIdParameter(required=False),
              "objects": ListOfParameter(element=ObjectIdParameter()),
              "position": StringParameter()
          })
    def api_insert(self, request, container, objects, position):
        c = self.get_object_or_404(Object, id=container)
        o = []
        for r in objects:
            o += [self.get_object_or_404(Object, id=r)]
        if position == "append":
            for x in o:
                x.put_into(c)
        elif position in ("before", "after"):
            cc = self.get_object_or_404(Object, id=c.container)
            for x in o:
                x.put_into(cc)
        return True

    @view("^(?P<id>[0-9a-f]{24})/path/$", method=["GET"],
          access="read", api=True)
    def api_get_path(self, request, id):
        o = self.get_object_or_404(Object, id=id)
        path = [{
            "id": str(o.id),
            "name": o.name
        }]
        root = self.get_root().id
        while o.container and o.container != root:
            o = Object.objects.get(id=o.container)
            path = [{
                "id": str(o.id),
                "name": o.name
            }] + path
        return path
Exemplo n.º 28
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"]),
        }
Exemplo n.º 29
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
Exemplo n.º 30
0
class ProbeApplication(ExtDocApplication):
    """
    PMProbe application
    """
    title = "Probe"
    menu = "Setup | Probes"
    model = Probe
    query_fields = ["name"]

    REFRESH_CHUNK = config.getint("pm", "expired_refresh_chunk")
    REFRESH_TIMEOUT = config.getint("pm", "expired_refresh_timeout")

    @view(url="^(?P<name>[^/]+)/(?P<instance>\d+)/config/$",
          method=["GET"],
          validate={"last": DateTimeParameter(required=False)},
          access="config",
          api=True)
    def api_config(self, request, name, instance, last=None):
        """
        Get full probe configuration
        """
        probe = self.get_object_or_404(Probe, name=name)
        if not probe.user or request.user.id != probe.user.id:
            return self.response_forbidden()
        instance = int(instance)
        if instance >= probe.n_instances:
            return self.response_not_found("Invalid instance")
        probe_id = str(probe.id)
        now = datetime.datetime.now()
        # Refresh expired congfigs
        t0 = time.time()
        nr = 0
        dt = 0
        stopped = False
        for pc in ProbeConfig.objects.filter(probe_id=probe_id,
                                             instance_id=instance,
                                             expire__lt=now):
            pc.refresh()
            nr += 1
            if nr % self.REFRESH_CHUNK:
                # Check execution time
                dt = time.time() - t0
                if dt > self.REFRESH_TIMEOUT:
                    self.logger.info(
                        "%d configs has been refreshed in %s seconds. Giving up",
                        nr, dt)
                    stopped = True
                    break
        if nr and not stopped:
            self.logger.info("%d configs has been refreshed in %s seconds.",
                             nr, dt)
        # Get configs
        q = {"probe_id": probe_id, "instance_id": instance}
        if last:
            fmt = "%Y-%m-%dT%H:%M:%S.%f" if "." in last else "%Y-%m-%dT%H:%M:%S"
            last = datetime.datetime.strptime(last, fmt)
            q["changed"] = {"$gte": last}
        config = [{
            "uuid":
            pc["uuid"],
            "handler":
            pc["handler"],
            "interval":
            pc["interval"],
            "metrics": [{
                "metric": m["metric"],
                "metric_type": m["metric_type"],
                "thresholds": m["thresholds"],
                "convert": m["convert"],
                "scale": m["scale"],
                "collectors": {
                    "policy":
                    m["collectors"]["policy"],
                    "write_concern":
                    m["collectors"]["write_concern"],
                    "collectors": [{
                        "proto": c["proto"],
                        "address": c["address"],
                        "port": c["port"]
                    } for c in m["collectors"]["collectors"]]
                }
            } for m in pc["metrics"]],
            "config":
            pc["config"],
            "managed_object":
            pc.get("managed_object", None),
            "changed":
            pc["changed"].isoformat(),
            "expire":
            pc["expire"].isoformat()
        } for pc in ProbeConfig._get_collection().find(q)]
        if config:
            expire = min(c["expire"] for c in config)
            # Wipe out deleted configs
            deleted = [
                c["uuid"] for c in config if c["changed"] == c["expire"]
            ]
            if deleted:
                ProbeConfig.objects.filter(uuid__in=deleted).delete()
        else:
            expire = None
        return {
            "now": now.isoformat(),
            "last": last.isoformat() if last else None,
            "expire": expire,
            "config": config
        }

    @view(url="^(?P<name>[^/]+)/(?P<instance>\d+)/feed/$",
          method=["POST"],
          validate={
              "thresholds":
              DictListParameter(
                  attrs={
                      "managed_object": IntParameter(),
                      "metric": StringParameter(),
                      "metric_type": StringParameter(),
                      "ts": IntParameter(),
                      "value": FloatParameter(),
                      "old_state": StringParameter(),
                      "new_state": StringParameter()
                  })
          },
          access="config",
          api=True)
    def api_fmfeed(self, request, name, instance, thresholds):
        if thresholds:
            cnt = itertools.count()
            batch = NewEvent._get_collection().initialize_unordered_bulk_op()
            for t in thresholds:
                seq = struct.pack("!II", int(time.time()),
                                  cnt.next() & 0xFFFFFFFFL)
                batch.insert({
                    "timestamp":
                    datetime.datetime.fromtimestamp(t["ts"]),
                    "managed_object":
                    t["managed_object"],
                    "raw_vars": {
                        "source": "system",
                        "metric": t["metric"],
                        "metric_type": t["metric_type"],
                        "value": str(t["value"]),
                        "old_state": t["old_state"],
                        "new_state": t["new_state"]
                    },
                    "seq":
                    Binary(seq)
                })
            batch.execute(0)