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