diff --git a/napalm_openmediavault/__init__.py b/napalm_openmediavault/__init__.py index 496533b..0df6deb 100644 --- a/napalm_openmediavault/__init__.py +++ b/napalm_openmediavault/__init__.py @@ -14,9 +14,9 @@ Usage:: driver = OpenMediaVaultDriver("192.168.1.10", "admin", "secret") driver.open() - print(driver.get_facts()) - print(driver.get_disks()) - print(driver.get_shares()) + facts = driver.get_facts() + disks = driver.get_disks() + shares = driver.get_shares() driver.close() """ diff --git a/napalm_openmediavault/__pycache__/__init__.cpython-312.pyc b/napalm_openmediavault/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..3077e54 Binary files /dev/null and b/napalm_openmediavault/__pycache__/__init__.cpython-312.pyc differ diff --git a/napalm_openmediavault/__pycache__/openmediavault.cpython-312.pyc b/napalm_openmediavault/__pycache__/openmediavault.cpython-312.pyc new file mode 100644 index 0000000..8a6a537 Binary files /dev/null and b/napalm_openmediavault/__pycache__/openmediavault.cpython-312.pyc differ diff --git a/napalm_openmediavault/openmediavault.py b/napalm_openmediavault/openmediavault.py index 9398553..5d4844d 100644 --- a/napalm_openmediavault/openmediavault.py +++ b/napalm_openmediavault/openmediavault.py @@ -16,9 +16,11 @@ All optional_args from LinuxDriver are accepted (pkg_manager, sudo_password, … Tested against OpenMediaVault 6.x and 7.x (Debian Bullseye / Bookworm base). """ +from __future__ import annotations + import json as _json import re -from typing import Any, Dict, List +from typing import Any from napalm_device_types.models import ( DiskPoolDict, @@ -45,12 +47,12 @@ class OpenMediaVaultDriver(LinuxDriver): the full systemd service list). """ + TYPE_LABEL = "Storage" driver_name = "openmediavault" - storage_device = True # signals netOrk to classify this driver as "storage" # ── Facts override ───────────────────────────────────────────────────────── - def get_facts(self) -> Dict[str, Any]: + def get_facts(self) -> dict[str, Any]: """Return device facts, overriding OMV version from dpkg.""" facts = super().get_facts() try: @@ -65,7 +67,7 @@ class OpenMediaVaultDriver(LinuxDriver): # ── Warnings ────────────────────────────────────────────────────────────── - def get_device_warnings(self) -> List[Dict[str, Any]]: + def get_device_warnings(self) -> list[dict[str, Any]]: """Return warnings, ignoring packages held back by apt-get upgrade. On OMV, kernel and OMV-specific packages are routinely held back @@ -74,7 +76,7 @@ class OpenMediaVaultDriver(LinuxDriver): We simulate the upgrade first and only warn if there are packages that a standard apt-get upgrade would actually install. """ - warnings: List[Dict[str, Any]] = [] + warnings: list[dict[str, Any]] = [] try: sim = self._sudo( "DEBIAN_FRONTEND=noninteractive apt-get upgrade --simulate 2>&1", @@ -105,7 +107,7 @@ class OpenMediaVaultDriver(LinuxDriver): # ── Physical disks ───────────────────────────────────────────────────────── - def get_disks(self) -> List[PhysicalDiskDict]: + def get_disks(self) -> list[PhysicalDiskDict]: """Return physical disk inventory. Uses ``lsblk -J`` for device enumeration and ``smartctl -iA`` @@ -141,7 +143,7 @@ class OpenMediaVaultDriver(LinuxDriver): }, ] """ - result: List[PhysicalDiskDict] = [] + result: list[PhysicalDiskDict] = [] try: raw = self._send( @@ -226,7 +228,7 @@ class OpenMediaVaultDriver(LinuxDriver): # ── md RAID pools ────────────────────────────────────────────────────────── - def get_disk_pools(self) -> Dict[str, DiskPoolDict]: + def get_disk_pools(self) -> dict[str, DiskPoolDict]: """Return md RAID array status from ``/proc/mdstat`` and ``mdadm --detail``. Keys are array names (e.g. ``"md1"``). Each value contains: @@ -261,7 +263,7 @@ class OpenMediaVaultDriver(LinuxDriver): }, } """ - result: Dict[str, DiskPoolDict] = {} + result: dict[str, DiskPoolDict] = {} try: mdstat = self._send("cat /proc/mdstat 2>/dev/null") @@ -310,7 +312,7 @@ class OpenMediaVaultDriver(LinuxDriver): # ── Logical volumes / filesystems ────────────────────────────────────────── - def get_volumes(self) -> Dict[str, LogicalVolumeDict]: + def get_volumes(self) -> dict[str, LogicalVolumeDict]: """Return mounted filesystem info from ``df``. Only real block devices (``/dev/…``) are included; tmpfs, devtmpfs, @@ -351,7 +353,7 @@ class OpenMediaVaultDriver(LinuxDriver): }, } """ - result: Dict[str, LogicalVolumeDict] = {} + result: dict[str, LogicalVolumeDict] = {} try: df_out = self._send("df -Pk 2>/dev/null") @@ -400,7 +402,7 @@ class OpenMediaVaultDriver(LinuxDriver): # ── NAS shares ──────────────────────────────────────────────────────────── - def get_shares(self) -> Dict[str, NASShareDict]: + def get_shares(self) -> dict[str, NASShareDict]: """Return all configured NAS shares from the OMV config database. Covers SMB/CIFS, NFS, and FTP shares. Keys are prefixed with the @@ -442,7 +444,7 @@ class OpenMediaVaultDriver(LinuxDriver): }, } """ - shares: Dict[str, NASShareDict] = {} + shares: dict[str, NASShareDict] = {} shares.update(self._smb_shares()) shares.update(self._nfs_shares()) shares.update(self._ftp_shares()) @@ -450,7 +452,7 @@ class OpenMediaVaultDriver(LinuxDriver): # ── Storage services ────────────────────────────────────────────────────── - def get_storage_services(self) -> Dict[str, StorageServiceDict]: + def get_storage_services(self) -> dict[str, StorageServiceDict]: """Return status of key NAS services (SMB, NFS, FTP, SSH, rsync). This method is separate from ``get_services()`` (inherited from @@ -482,7 +484,7 @@ class OpenMediaVaultDriver(LinuxDriver): ("ssh", "ssh", 22), ("rsync", "rsync", 873), ] - result: Dict[str, StorageServiceDict] = {} + result: dict[str, StorageServiceDict] = {} for key, unit, port in _SVC_MAP: try: running = ( @@ -502,16 +504,17 @@ class OpenMediaVaultDriver(LinuxDriver): # ── Not implemented ──────────────────────────────────────────────────────── - def get_volume_snapshots(self, volume: str = "") -> List[VolumeSnapshotDict]: + def get_volume_snapshots(self, volume: str = "") -> list[VolumeSnapshotDict]: + """Return volume snapshots (not supported on OpenMediaVault).""" raise NotImplementedError( "OpenMediaVault does not expose volume snapshots via this driver" ) - def get_replication_jobs(self) -> List[ReplicationJobDict]: + def get_replication_jobs(self) -> list[ReplicationJobDict]: """Return replication jobs (not supported on OpenMediaVault).""" raise NotImplementedError - def get_quotas(self) -> List[StorageQuotaDict]: + def get_quotas(self) -> list[StorageQuotaDict]: """Return storage quotas (not supported on OpenMediaVault).""" raise NotImplementedError @@ -558,8 +561,8 @@ class OpenMediaVaultDriver(LinuxDriver): pass return "" - def _smb_shares(self) -> Dict[str, NASShareDict]: - out: Dict[str, NASShareDict] = {} + def _smb_shares(self) -> dict[str, NASShareDict]: + out: dict[str, NASShareDict] = {} for s in self._omv_read("conf.service.smb.shares"): name = s.get("name", "") if not name: @@ -577,8 +580,8 @@ class OpenMediaVaultDriver(LinuxDriver): ) return out - def _nfs_shares(self) -> Dict[str, NASShareDict]: - out: Dict[str, NASShareDict] = {} + def _nfs_shares(self) -> dict[str, NASShareDict]: + out: dict[str, NASShareDict] = {} for s in self._omv_read("conf.service.nfs.shares"): path = self._resolve_shared_folder(s.get("sharedfolderref", "")) name = path.split("/")[-1] or s.get("sharedfolderref", "") @@ -597,8 +600,8 @@ class OpenMediaVaultDriver(LinuxDriver): ) return out - def _ftp_shares(self) -> Dict[str, NASShareDict]: - out: Dict[str, NASShareDict] = {} + def _ftp_shares(self) -> dict[str, NASShareDict]: + out: dict[str, NASShareDict] = {} for s in self._omv_read("conf.service.ftp.shares"): path = self._resolve_shared_folder(s.get("sharedfolderref", "")) name = path.split("/")[-1] or s.get("sharedfolderref", "") diff --git a/tests/__pycache__/__init__.cpython-312.pyc b/tests/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..da365d8 Binary files /dev/null and b/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/tests/__pycache__/test_omv_type_label.cpython-312-pytest-9.0.3.pyc b/tests/__pycache__/test_omv_type_label.cpython-312-pytest-9.0.3.pyc new file mode 100644 index 0000000..96d6fbf Binary files /dev/null and b/tests/__pycache__/test_omv_type_label.cpython-312-pytest-9.0.3.pyc differ diff --git a/tests/test_omv_type_label.py b/tests/test_omv_type_label.py new file mode 100644 index 0000000..0675c2a --- /dev/null +++ b/tests/test_omv_type_label.py @@ -0,0 +1,18 @@ +"""Tests for TYPE_LABEL on OpenMediaVaultDriver.""" + +from napalm_openmediavault.openmediavault import OpenMediaVaultDriver + + +def test_type_label_is_storage(): + assert OpenMediaVaultDriver.TYPE_LABEL == "Storage" + + +def test_type_label_overrides_linux(): + from napalm_linux.linux import LinuxDriver + assert LinuxDriver.TYPE_LABEL == "Linux" + assert OpenMediaVaultDriver.TYPE_LABEL != LinuxDriver.TYPE_LABEL + + +def test_storage_device_flag_removed(): + assert not hasattr(OpenMediaVaultDriver, "storage_device"), \ + "storage_device is superseded by TYPE_LABEL = 'Storage'"