Commit 21bffe60 authored by Andrey Vertiprahov's avatar Andrey Vertiprahov Committed by Dmitry Volodin
Browse files

#817 Add 'noc::is_linked::=' label.

parent 92081cae
......@@ -8,7 +8,7 @@
# Python modules
import datetime
import logging
from typing import Optional, Iterable, List
from itertools import filterfalse
# Third-party modules
from mongoengine.document import Document
......@@ -22,6 +22,7 @@ from mongoengine.fields import (
ObjectIdField,
)
from pymongo import ReadPreference
from typing import Optional, Iterable, List
# NOC Modules
from noc.config import config
......@@ -208,14 +209,40 @@ class Interface(Document):
:returns: True if interface is linked, False otherwise
"""
if self.type == "aggregated":
q = {"interfaces": {"$in": [self.id] + [i.id for i in self.lag_members]}}
# Speedup query for labels because self.lag_members very slow
return bool(
next(
Interface._get_collection()
.with_options(read_preference=ReadPreference.SECONDARY_PREFERRED)
.aggregate(
[
{
"$match": {
"$or": [{"_id": self.id}, {"aggregated_interface": self.id}]
}
},
{
"$lookup": {
"from": "noc.links",
"localField": "_id",
"foreignField": "interfaces",
"as": "links",
}
},
{"$match": {"links": {"$ne": []}}},
{"$limit": 1},
]
),
None,
)
)
else:
q = {"interfaces": self.id}
return bool(
Link._get_collection()
.with_options(read_preference=ReadPreference.SECONDARY_PREFERRED)
.find_one(q)
)
return bool(
Link._get_collection()
.with_options(read_preference=ReadPreference.SECONDARY_PREFERRED)
.find_one({"interfaces": self.id})
)
def unlink(self):
"""
......@@ -437,12 +464,15 @@ class Interface(Document):
yield Label.get_effective_regex_labels("interface_name", instance.name)
yield Label.get_effective_regex_labels("interface_description", instance.description or "")
if instance.managed_object:
yield from ManagedObject.iter_effective_labels(instance.managed_object)
yield from filterfalse(
lambda x: x != "noc::is_linked::=",
ManagedObject.iter_effective_labels(instance.managed_object),
)
if instance.service:
yield from Service.iter_effective_labels(instance.service)
# if instance.is_linked:
# Idle Discovery When create Aggregate interface
# yield ["noc::interface::linked::="]
if instance.is_linked:
# Idle Discovery When create Aggregate interface (fixed not use lag_members)
yield ["noc::is_linked::="]
for si in instance.parent.subinterface_set.filter(enabled_afi__in=["BRIDGE", "IPv4"]):
if si.tagged_vlans:
lazy_tagged_vlans_labels = list(
......
......@@ -11,6 +11,7 @@ import datetime
from typing import Optional
# Third-party modules
from pymongo import UpdateMany
from mongoengine.document import Document
from mongoengine.fields import StringField, DateTimeField, ListField, IntField, ObjectIdField
......@@ -196,9 +197,11 @@ class Link(Document):
def on_save(self):
if not hasattr(self, "_changed_fields") or "interfaces" in self._changed_fields:
self.update_topology()
self.set_label()
def on_delete(self):
self.update_topology()
self.reset_label()
@property
def managed_objects(self):
......@@ -245,3 +248,51 @@ class Link(Document):
else:
return "M"
return "u"
def reset_label(self):
from noc.main.models.label import Label
coll = Link._get_collection()
# Check ManagedObject Link Count
r = [
c["_id"]
for c in coll.aggregate(
[
{"$match": {"linked_objects": {"$in": self.linked_objects}}},
{"$unwind": "$linked_objects"},
{"$group": {"_id": "$linked_objects", "count": {"$sum": 1}}},
{"$match": {"count": {"$lt": 2}, "_id": {"$in": self.linked_objects}}},
]
)
]
Label.reset_model_labels("sa.ManagedObject", ["noc::is_linked::="], r)
# Assumption that Interface has only one Link :)
Label.reset_model_labels(
"inv.Interface", ["noc::is_linked::="], [i.id for i in self.interfaces]
)
def set_label(self):
from django.db import connection
from noc.inv.models.interface import Interface
from noc.sa.models.managedobject import ManagedObject
print("Set label Is Linked")
coll = Interface._get_collection()
coll.bulk_write(
[
UpdateMany(
{"_id": {"$in": [i.id for i in self.interfaces]}},
{"$addToSet": {"effective_labels": "noc::is_linked::="}},
)
]
)
sql = f"""
UPDATE {ManagedObject._meta.db_table}
SET effective_labels=ARRAY (
SELECT DISTINCT e FROM unnest(effective_labels || %s::varchar[]) AS a(e)
)
WHERE id = ANY (%s::numeric[])
"""
cursor = connection.cursor()
cursor.execute(sql, [["noc::is_linked::="], self.linked_objects])
......@@ -41,7 +41,7 @@ class Migration(BaseMigration):
"bg_color2": 16777215,
"fg_color2": 0,
"is_protected": False,
"is_autogenerated": True,
"is_autogenerated": False,
}
)
]
......
# ----------------------------------------------------------------------
# Create utility labels labels
# ----------------------------------------------------------------------
# Copyright (C) 2007-2021 The NOC Project
# See LICENSE for details
# ----------------------------------------------------------------------
# Third-party modules
from pymongo import InsertOne
# NOC modules
from noc.core.migration.base import BaseMigration
class Migration(BaseMigration):
def migrate(self):
# Create wildcard labels
l_coll = self.mongo_db["labels"]
current_labels = {ll["name"]: ll["_id"] for ll in l_coll.find()}
bulk = []
if "noc::is_linked::=" not in current_labels:
bulk += [
InsertOne(
{
"name": "noc::is_linked::=",
"description": "Builtin Labels mark if ManagedObject or Interface has link",
"bg_color1": 16777215,
"fg_color1": 0,
"bg_color2": 16777215,
"fg_color2": 0,
"is_protected": False,
"is_autogenerated": False,
"expose_alarm": True,
}
)
]
if "noc::is_fatal::=" not in current_labels:
bulk += [
InsertOne(
{
"name": "noc::is_fatal::=",
"description": "Builtin Labels mark for Alarm that fatal affected",
"bg_color1": 16777215,
"fg_color1": 0,
"bg_color2": 16777215,
"fg_color2": 0,
"is_protected": False,
"is_autogenerated": False,
"expose_alarm": True,
}
)
]
if bulk:
l_coll.bulk_write(bulk, ordered=True)
......@@ -425,10 +425,16 @@ class Label(Document):
:param name:
:param description:
:param is_protected:
:param is_autogenerated:
:param enable_managedobject:
:param enable_slaprobe:
:param enable_interface:
:param bg_color1:
:param fg_color1:
:param bg_color2:
:param fg_color2:
:param expose_metric:
:param expose_datastream:
:return:
"""
# if Label.objects.filter(name=name).first(): # Do not use get_by_name. Cached None !
......@@ -721,11 +727,12 @@ class Label(Document):
return inner
@classmethod
def reset_model_labels(cls, model_id: str, labels: List[str]):
def reset_model_labels(cls, model_id: str, labels: List[str], ids: List[str] = None):
"""
Unset labels from effective_labels field on models
:param model_id:
:param labels:
:param model_id: Model ID
:param labels: Labels for remove from effective_labels
:param ids: Model IDs for reset labels
:return:
"""
from django.db import connection
......@@ -733,23 +740,29 @@ class Label(Document):
model = get_model(model_id)
if is_document(model):
coll = model._get_collection()
match = {"effective_labels": {"$in": labels}}
if ids:
match["_id"] = {"$in": ids}
coll.bulk_write(
[
UpdateMany(
{"effective_labels": {"$in": labels}},
match,
{"$pull": {"effective_labels": {"$in": labels}}},
)
]
)
else:
params = [labels, labels]
if ids:
params += [ids]
sql = f"""
UPDATE {model._meta.db_table}
SET effective_labels=array(
SELECT unnest(effective_labels) EXCEPT SELECT unnest(%s::varchar[])
) WHERE effective_labels && %s::varchar[]
) WHERE effective_labels && %s::varchar[] {"AND id = ANY (%s::numeric[])" if ids else ""}
"""
cursor = connection.cursor()
cursor.execute(sql, [labels, labels])
cursor.execute(sql, params)
@staticmethod
def get_instance_profile(
......
......@@ -1318,7 +1318,7 @@ class ManagedObject(NOCModel):
def iter_recursive_objects(self):
"""
Generator yilding all recursive objects
Generator yielding all recursive objects
for effective PM settings
"""
from noc.inv.models.interface import Interface
......@@ -1929,6 +1929,8 @@ class ManagedObject(NOCModel):
@classmethod
def iter_effective_labels(cls, instance: "ManagedObject") -> Iterable[List[str]]:
yield list(instance.labels or [])
if instance.is_managed:
yield ["noc::is_managed::="]
yield list(AdministrativeDomain.iter_lazy_labels(instance.administrative_domain))
yield list(Pool.iter_lazy_labels(instance.pool))
yield list(ManagedObjectProfile.iter_lazy_labels(instance.object_profile))
......@@ -1958,6 +1960,12 @@ class ManagedObject(NOCModel):
yield list(VCDomain.iter_lazy_labels(instance.vc_domain))
if instance.tt_system:
yield list(TTSystem.iter_lazy_labels(instance.tt_system))
if Interface.objects.filter(
managed_object=instance.id, effective_labels="noc::is_linked::="
).first():
# If use Link.objects.filter(linked_objects=mo.id).first() - 1.27 ms,
# Interface = 39.4 µs
yield ["noc::is_linked::="]
@classmethod
def can_set_label(cls, label):
......@@ -2084,3 +2092,4 @@ from noc.core.pm.utils import get_objects_metrics
from noc.vc.models.vcdomain import VCDomain # noqa
from noc.main.models.prefixtable import PrefixTable
from noc.ip.models.vrf import VRF
from noc.inv.models.interface import Interface
......@@ -208,6 +208,9 @@ Ext.define("NOC.main.label.Application", {
if(item.data.expose_datastream) {
r.push(__("Datastream"));
}
if(item.data.expose_alarm) {
r.push(__("Alarm"));
}
return r.join(", ");
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment