From 2394296f5b00ebbe098f8b30f736ec92fe4ae693 Mon Sep 17 00:00:00 2001 From: IluaAir Date: Sun, 22 Feb 2026 00:21:55 +0300 Subject: [PATCH] Enhance Keenetic model and update templates for improved data handling - Implemented the `interfaces` and `vlans` methods in the `Keenetic` model to process and decode interface and VLAN data. - Added a `_decode_utf` method to handle UTF-8 encoded descriptions. - Updated the Keenetic TTP template to define structured groups for system, interfaces, and VLANs. - Refactored file paths in the `Mikrotik` model for consistency and clarity. --- oxi/interfaces/base.py | 2 +- oxi/interfaces/models/keenetic.py | 44 ++++++++++++++++--- oxi/interfaces/models/mikrotik.py | 4 +- oxi/interfaces/models/templates/_template.ttp | 17 +++++-- oxi/interfaces/models/templates/keenetic.ttp | 29 ++++++++++++ 5 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 oxi/interfaces/models/templates/keenetic.ttp diff --git a/oxi/interfaces/base.py b/oxi/interfaces/base.py index 29efea8..c1d7073 100644 --- a/oxi/interfaces/base.py +++ b/oxi/interfaces/base.py @@ -106,7 +106,7 @@ class BaseDevice(ABC): raise ValueError( f"{self.__class__.__name__}: TTP template '{self.template}' " f"did not produce required sections: {sorted(missing)}. " - f"Got: {sorted(raw.keys())}" + f"Got: {(raw.keys())}" ) return raw diff --git a/oxi/interfaces/models/keenetic.py b/oxi/interfaces/models/keenetic.py index 42df4f4..b994e95 100644 --- a/oxi/interfaces/models/keenetic.py +++ b/oxi/interfaces/models/keenetic.py @@ -1,20 +1,54 @@ +from ipaddress import ip_interface +from pprint import pprint from oxi.interfaces import register_parser from oxi.interfaces.base import BaseDevice +from oxi.interfaces.contract import Interfaces, System, Vlans @register_parser(["NDMS", "keenetic", "KeeneticOS"]) class Keenetic(BaseDevice): template = "keenetic.ttp" - def system(self): ... + def system(self): + return System(**self._raw["system"]) - def interfaces(self): ... + def _decode_utf(self, text: str): + if "\\x" in text: + desc = text.strip('"') + decoded = ( + desc.encode("utf-8") + .decode("unicode_escape") + .encode("latin1") + .decode("utf-8") + ) + return decoded + return text - def vlans(self): ... + def interfaces(self): + interfaces: list[dict] = self._raw["interfaces"] + for item in interfaces: + if item.get("ip_address") and item.get("netmask"): + ipaddress = ip_interface( + f"{item.get('ip_address')}/{item.get('netmask')}" + ) + item["mask"] = ipaddress.network.prefixlen + item.pop("netmask", "Key not found") + if item.get("description"): + decoded = self._decode_utf(item.get("description", "")) + item["description"] = decoded + return [Interfaces(**item) for item in interfaces] + + def vlans(self): + vlans = self._raw["vlans"] + for item in vlans: + if item.get("description"): + decoded = self._decode_utf(item.get("description", "")) + item["description"] = decoded + return [Vlans(**item) for item in vlans] if __name__ == "__main__": - with open("../../test2.txt") as file: + with open("./test2.txt") as file: data = file.read() mikr = Keenetic(data) - print(mikr.parse().json()) + print(mikr.parse().model_dump_json()) diff --git a/oxi/interfaces/models/mikrotik.py b/oxi/interfaces/models/mikrotik.py index 4a49095..1fc3691 100644 --- a/oxi/interfaces/models/mikrotik.py +++ b/oxi/interfaces/models/mikrotik.py @@ -1,3 +1,4 @@ +import os from oxi.interfaces import register_parser from oxi.interfaces.base import BaseDevice from oxi.interfaces.contract import Interfaces, System, Vlans @@ -19,7 +20,8 @@ class Mikrotik(BaseDevice): if __name__ == "__main__": - with open("../../test.txt") as file: + print(os.path.abspath(os.curdir)) + with open("./test.txt") as file: data = file.read() mikr = Mikrotik(data) print(mikr.parse().json()) diff --git a/oxi/interfaces/models/templates/_template.ttp b/oxi/interfaces/models/templates/_template.ttp index 02d8a0c..67cb94d 100644 --- a/oxi/interfaces/models/templates/_template.ttp +++ b/oxi/interfaces/models/templates/_template.ttp @@ -1,7 +1,16 @@ - - + + - - \ No newline at end of file + + ... + + + + ... + + + + ... + diff --git a/oxi/interfaces/models/templates/keenetic.ttp b/oxi/interfaces/models/templates/keenetic.ttp new file mode 100644 index 0000000..6f9dfc7 --- /dev/null +++ b/oxi/interfaces/models/templates/keenetic.ttp @@ -0,0 +1,29 @@ + + + +default_system = { + "model": "", + "serial_number": "" +} +default_interfaces = {} + + + +! release: {{ version }} +! model: {{ model | ORPHRASE }} +! hw_version: {{ serial_number }} + + + +interface {{ name | _start_ | exclude("Vlan") }} + rename {{ rename }} + description {{ description | ORPHRASE }} + ip address {{ ip_address }} {{ netmask }} + {{ shutdown | re("up") | replace("up","False") | strip('"') }} + {{ shutdown | re("down") | replace("down","True") | strip('"') }} + + + +interface {{ ignore }}/Vlan{{ vlan_id }} + description {{ description | ORPHRASE | strip('"') }} + \ No newline at end of file