diff --git a/collections/pm.measurementunits/DuplexStatus.json b/collections/pm.measurementunits/DuplexStatus.json index e5da4c85a3f0215953c684224e8754c7c3727465..6e26577287b7286e48cde99eb759ab2b34f607e7 100644 --- a/collections/pm.measurementunits/DuplexStatus.json +++ b/collections/pm.measurementunits/DuplexStatus.json @@ -6,6 +6,10 @@ "description": "Interface Duplex state", "label": " ", "dashboard_label": " ", + "convert_from": [{ + "expr": "x", + "unit__code": "1" + }], "enum": [ { "key": "Unknown", diff --git a/collections/pm.measurementunits/InterfaceStatus.json b/collections/pm.measurementunits/InterfaceStatus.json index 715fe9513b6d424c0418a81e24cacc7d2f965116..5a21c734c98d9d7efd4a1ac036ba8f482493a3d1 100644 --- a/collections/pm.measurementunits/InterfaceStatus.json +++ b/collections/pm.measurementunits/InterfaceStatus.json @@ -6,6 +6,10 @@ "description": "Operational state of the interface", "label": " ", "dashboard_label": null, + "convert_from": [{ + "expr": "x", + "unit__code": "1" + }], "enum": [ { "key": "up", diff --git a/collections/pm.metricactions/Average_CPU_Usage.json b/collections/pm.metricactions/Average_CPU_Usage.json index 1988887747ed70456b1747905b1ab815887921a4..7b9618f78661f7847a55be38fb960cfb47d95c7d 100644 --- a/collections/pm.metricactions/Average_CPU_Usage.json +++ b/collections/pm.metricactions/Average_CPU_Usage.json @@ -5,17 +5,17 @@ "description": "Средняя загрузка CPU больше N", "params": [ { - "name": "activation.min_window", + "name": "activation-window.min_window", "description": null, - "default": "5", + "default": "3", "max_value": 5.0, "min_value": 3.0, "type": "int" }, { - "name": "activation.max_window", + "name": "activation-window.max_window", "description": null, - "default": "3", + "default": "5", "max_value": 5.0, "min_value": 3.0, "type": "int" @@ -47,5 +47,8 @@ "window_config": {}, "window_function": "mean", "window_type": "tick" + }, + "alarm_config": { + "reference": null } } diff --git a/collections/pm.metricactions/Average_Memory_Usage.json b/collections/pm.metricactions/Average_Memory_Usage.json index c4cc1465c6e51a9222f39618260733af5f049dea..b395ca618bdcd351b3690fc92bfdfbf1ad28f692 100644 --- a/collections/pm.metricactions/Average_Memory_Usage.json +++ b/collections/pm.metricactions/Average_Memory_Usage.json @@ -21,7 +21,7 @@ "type": "int" }, { - "name": "activation.min_window", + "name": "activation-window.min_window", "description": null, "default": "3", "max_value": 10.0, @@ -29,7 +29,7 @@ "type": "int" }, { - "name": "activation.max_window", + "name": "activation-window.max_window", "description": null, "default": "5", "max_value": 10.0, diff --git a/collections/pm.metricactions/Interface_Bandwidth_more_than_N.json b/collections/pm.metricactions/Interface_Bandwidth_more_than_N.json index fc9737005e583e24f0b2c481db444b24a7870801..e6c3dfaf8be6653a7b689f5c0a95ec5e62ac633e 100644 --- a/collections/pm.metricactions/Interface_Bandwidth_more_than_N.json +++ b/collections/pm.metricactions/Interface_Bandwidth_more_than_N.json @@ -21,7 +21,7 @@ "type": "float" }, { - "name": "activation.min_window", + "name": "activation-window.min_window", "description": null, "default": "900", "max_value": 300.0, @@ -29,7 +29,7 @@ "type": "int" }, { - "name": "activation.max_window", + "name": "activation-window.max_window", "description": null, "default": "1200", "max_value": 300.0, diff --git a/collections/pm.metricactions/Interface_Errors_In.json b/collections/pm.metricactions/Interface_Errors_In.json index 247e21ae185dd7058375b4f1b49a0d0c426e9609..75cab0cb9e11cb97e9f10516e6ef6ffc95dee090 100644 --- a/collections/pm.metricactions/Interface_Errors_In.json +++ b/collections/pm.metricactions/Interface_Errors_In.json @@ -21,7 +21,7 @@ "type": "float" }, { - "name": "activation.min_window", + "name": "activation-window.min_window", "description": null, "default": "900", "max_value": 3600.0, @@ -29,7 +29,7 @@ "type": "int" }, { - "name": "activation.max_window", + "name": "activation-window.max_window", "description": null, "default": "1200", "max_value": 3600.0, @@ -51,5 +51,8 @@ }, "window_function": "percentile", "window_type": "seconds" + }, + "alarm_config": { + "reference": null } } diff --git a/core/cdag/node/probe.py b/core/cdag/node/probe.py index b98af9fd3a4b763727309efa70514e401c8ecd6a..c4ad13894eb82e6d5345e6c89781e32dcdda7d89 100644 --- a/core/cdag/node/probe.py +++ b/core/cdag/node/probe.py @@ -118,6 +118,10 @@ class ProbeNode(BaseCDAGNode): # Timer stepback, reset state and exit self.set_state(None, None) return None + elif (ts - self.state.lt) < NS: + # Too less timestamp different, Division by zero exception + logger.info("[%s] Skipping already processed value", self.node_id) + return None if fn.has_time_delta: kwargs["time_delta"] = (ts - self.state.lt) // NS # Always positive if fn.has_delta: diff --git a/core/cdag/node/subgraph.py b/core/cdag/node/subgraph.py index 386e72b899e0fa11fa6e347673ee041eff777952..07b29e92f4f2479821f6546fdd32ecd7d57cd3b0 100644 --- a/core/cdag/node/subgraph.py +++ b/core/cdag/node/subgraph.py @@ -17,7 +17,7 @@ import yaml # NOC modules from ..graph import CDAG from ..factory.config import ConfigCDAGFactory, GraphConfig -from .base import BaseCDAGNode, ValueType, Category +from .base import BaseCDAGNode, ValueType, Category, IN_INVALID, IN_REQUIRED class InputMapping(BaseModel): @@ -121,7 +121,6 @@ class SubgraphNode(BaseCDAGNode): if not node: continue self.input_mappings[m.public_name] = InputItem(node=node, input=m.name) - self.static_inputs.add(m.public_name) # Inject measure node when necessary self.measure_node = None if cfg.output: @@ -140,11 +139,10 @@ class SubgraphNode(BaseCDAGNode): def iter_inputs(self) -> Iterable[str]: yield from self.input_mappings - def has_input(self, name: str) -> bool: - return name in self.input_mappings - - def is_required_input(self, name: str) -> bool: - return name in self.input_mappings + def get_input_type(self, name: str) -> int: + if name in self.input_mappings: + return IN_REQUIRED + return IN_INVALID def get_value(self, *args, **kwargs) -> Optional[ValueType]: # Start sub-transaction @@ -153,8 +151,10 @@ class SubgraphNode(BaseCDAGNode): im = self.input_mappings[p] im.node.activate(tx, im.input, v) changed_state = tx.get_changed_state() - if self.state.state is None: - self.state.state = {} - self.state.state.update(changed_state) + if changed_state: + if self.state.state: + self.state.state.update(changed_state) + else: + self.state.state = changed_state.copy() out = tx.get_inputs(self.measure_node) return out.get("x") # None node has `x` input diff --git a/pm/migrations/0012_migrate_threshold_profile_metic_rules.py b/pm/migrations/0012_migrate_threshold_profile_metic_rules.py index 102488c5a70d0933ef2f859fd85938c7a52534f3..169ca99ea3a995d250de413191c4ccb5176ec464 100644 --- a/pm/migrations/0012_migrate_threshold_profile_metic_rules.py +++ b/pm/migrations/0012_migrate_threshold_profile_metic_rules.py @@ -208,8 +208,8 @@ class Migration(BaseMigration): if "invert_condition" in ac: params["alarm.invert_condition"] = ac["invert_condition"] if wc: - params["activation.max_window"] = wc["max_window"] - params["activation.min_window"] = wc["min_window"] + params["activation-window.max_window"] = wc["max_window"] + params["activation-window.min_window"] = wc["min_window"] mr_bulk += [ InsertOne( { diff --git a/pm/models/metricaction.py b/pm/models/metricaction.py index 6a96bb9814b717eeacf2c615a57ff4816fd02937..ae11c203c7cb8bc8c0bfc249652989da0daadda8 100644 --- a/pm/models/metricaction.py +++ b/pm/models/metricaction.py @@ -105,12 +105,18 @@ class AlarmConfig(EmbeddedDocument): @property def json_data(self) -> Dict[str, Any]: - return { - "alarm_class": self.alarm_class.name, - "reference": self.reference, - "activation_level": self.activation_level, - "deactivation_level": self.deactivation_level, - } + r = {} + if self.alarm_class: + r["alarm_class"] = self.alarm_class.name + if self.reference: + r["reference"] = self.reference + if self.activation_level != 1.0: + r["activation_level"] = self.activation_level + if self.deactivation_level != 1.0: + r["deactivation_level"] = self.deactivation_level + if self.invert_condition: + r["invert_condition"] = self.invert_condition + return r class ActivationConfig(EmbeddedDocument): diff --git a/services/metrics/service.py b/services/metrics/service.py index 8b972c482e859964334fb71187ab34d6d24ff0cc..7dc677437bddf4d983e49f2bf8316826773a7916 100755 --- a/services/metrics/service.py +++ b/services/metrics/service.py @@ -287,8 +287,8 @@ class MetricsService(FastAPIService): asyncio.get_running_loop().create_task(self.subscribe_metrics()) async def subscribe_metrics(self) -> None: - self.logger.info("Waiting for mappings") - await self.mappings_ready_event.wait() + self.logger.info("Waiting for rules") + await self.rules_ready_event.wait() self.logger.info("Mappings are ready") await self.subscribe_stream("metrics", self.slot_number, self.on_metrics, async_cursor=True) @@ -780,11 +780,9 @@ class MetricsService(FastAPIService): if not mu: continue # Missed field probe = card.probes.get(n) - if probe.name == ComposeProbeNode.name: # Skip composed probe - continue if self.lazy_init and not probe: probe = self.add_probe(n, k) - if not probe: + if not probe or probe.name == ComposeProbeNode.name: # Skip composed probe continue probe.activate(tx, "ts", ts) probe.activate(tx, "x", data[n]) diff --git a/tests/cdag/node/test_subgraph.py b/tests/cdag/node/test_subgraph.py index 01e24dc6a68efc00c59b53f5f81c5164bc443adb..491a41573b8a377c0c7a97cbb786c3c406ee38ef 100644 --- a/tests/cdag/node/test_subgraph.py +++ b/tests/cdag/node/test_subgraph.py @@ -1,7 +1,7 @@ # ---------------------------------------------------------------------- # subgraph node test # ---------------------------------------------------------------------- -# Copyright (C) 2007-2021 The NOC Project +# Copyright (C) 2007-2022 The NOC Project # See LICENSE for details # ---------------------------------------------------------------------- @@ -69,7 +69,7 @@ def test_config(): "x,y,expected", [(0, 0, 0), (1, 0, 2), (0, 1, 1), (2, 1, 5)], ) -def test_subgrapg_node(x, y, expected): +def test_subgraph_node(x, y, expected): cdag = NodeCDAG("subgraph", config=CONFIG) assert cdag.is_activated() is False cdag.activate("x", x)