From 46c4c13f3d02cd2d3d1c53ad06a570f5855ecc86 Mon Sep 17 00:00:00 2001 From: Christian Manivong Date: Wed, 24 Jun 2026 11:38:36 +0200 Subject: [PATCH] feat: TYPE_LABEL = "Storage" replaces storage_device = True flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TYPE_LABEL attribute on the base class hierarchy is now the canonical way for drivers to declare their device category. The storage_device sentinel flag is removed — classification is determined by reading TYPE_LABEL via getattr() in the backend. Co-Authored-By: Claude Sonnet 4.6 --- napalm_openmediavault/__init__.py | 6 +-- .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 880 bytes .../openmediavault.cpython-312.pyc | Bin 0 -> 25375 bytes napalm_openmediavault/openmediavault.py | 51 +++++++++--------- tests/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 178 bytes ...mv_type_label.cpython-312-pytest-9.0.3.pyc | Bin 0 -> 4343 bytes tests/test_omv_type_label.py | 18 +++++++ 7 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 napalm_openmediavault/__pycache__/__init__.cpython-312.pyc create mode 100644 napalm_openmediavault/__pycache__/openmediavault.cpython-312.pyc create mode 100644 tests/__pycache__/__init__.cpython-312.pyc create mode 100644 tests/__pycache__/test_omv_type_label.cpython-312-pytest-9.0.3.pyc create mode 100644 tests/test_omv_type_label.py 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 0000000000000000000000000000000000000000..3077e54165dad63b8798b5ced5841f8a229d45aa GIT binary patch literal 880 zcmZuwy>1gh5WcgG5-m!X0#OZCidb^)a0&!gf@BmdA;ortA%&aO=627w5sKxJ?q}wk?`HO!xo_Dq~VG%1KTZsYM?)8A9X1 z+2C{pRP&r^h?Rzk9xw!-`b0%HhvI~O3>%prN$dpQrbJapxMj_@Y zt1EXAkrbw*7vXp~4To>ez$8R7U~(atCYCD+IVWHfR&)Z9k};nHC6-(e!(8KUjccgi zM+lt7S_!CR!gpl?E;6OcJJ9?(0lSU=movU?Jl$l6YTdiz;UOw+QOKs2;My<;B|8H1HD>x)gG5+FR7d383m?*)*DAC+lPNX1` z=St2)%JOi`>_lINZV{-`;l{nKqibUdG3Jt6jDu`>vwb8KU8L-}E`A~3UFLzi{cifc a|EIC*xBhlLf9U_X|L8kvf85gB4*UmSX&dqY literal 0 HcmV?d00001 diff --git a/napalm_openmediavault/__pycache__/openmediavault.cpython-312.pyc b/napalm_openmediavault/__pycache__/openmediavault.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a6a537dfa0fb98fddf15ca913e74f664bf4e7a6 GIT binary patch literal 25375 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 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 0000000000000000000000000000000000000000..da365d8fdbaafe4ca689953ec3344dc3b1ca3202 GIT binary patch literal 178 zcmX@j%ge<81ph9|WP#|%AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd6{w$)pPQs!)PiIto zqxsoNZaN2j{faW(<)ne;oeWT8HDzYk2F|-Qq=mVF6wZJC@uYS3%!iX_3qiGTuI5%h zavjh9%wG1x3F57|r1&?EJ!PuVo=&f4@vV5W(9z((`Mru04TW4;6iaAJ6r}-EZK!pn zt}gWfm#U}ePhnapEM`P6X&um+gXN*kT2H2-DX zDU21c_l`-6$+^il3S(S;%A^FNe?yBj&_XhZ$~KOgYLYuA+Ro zwi?3Ov}_XXv}SGJw}@LKvq7b16F2IH*VfFk=Z9XEMj1Z<4H_M==t8jUJ51G@_k$VR zx2krN&$^;04u5LIM))w&3(v?9g&A)qJ~Zhw#QsM+T0-CwoF>PRh&> zXSjo5nHi-R`2s$VzbGvP6}L3IKs*|HcC}(xy_KLkUvk`)(v%yXBTJRJCii zUl|DC_Eqrqt>En|;YLtKt)Q}Eg{w8!^6eSdFVf1Rmw`7LzVwrF=i zWfMkLIzz)Ba6|yZ5WkcP96?p7D~s_}Ml10&;GzR4sPzjo_Vr8I>6szu+j@3cQe}`BlYY=M$C{IpLhd4ZK0kP|TzD>OyJBaeDeabRoADnGh zb(TJ|PLH#_o{djW?xjypPIwaSmeZ4gWU^z5V7`Zv!8q$xmoM=`B1$ucAT$v?5~LRi z=5DeL35L;xf{r7isc(qCs-p8j27mhlSqcw4ho8&^0hDdTb6m>jO^$;WE}HI!vgWe#yI#C& z?AtJUTSjkF@4t2dNYm)OcA;hTZ|L~D6AL)krY*hy>(iXOopjfkG8f-McWwQ42ehRu zG;w`tqd3tjPBiri$VE-)8xtEk{_Y3~XWO);Pq1u+I=7|%I@52f@ea6!5tu*F62=4ASZ`mb2?|MBXE#0TQ!t0E(xJbY!|bD^Kl;vS+$!Nu@9wUtYZ-??v10Z!MLwp z`Rb(qw}QI8Q)108EU2Hd02EG3JK6#3lWh9}JqfL24Afq_gx16gL@SlhP(%ajWv8N^ zxCFDH#`9*~wc)LN!J`GbTyqI^9oH$$tjeEXV}+w}0e*DtbbdUpn5zM=nxVGlWjJ(_ zGQ1B#@`OqIS!F$BQZwI(vI{n~!;r{uhah(X$q>O32x{*lG)#k`7*yMFJZ>sOdB6 zHy79UA8!tf-QGUV1t3ncDwUhL@*@q6V&Qw`pO0|C1FqFqZuONP zYRZoNkC@;eE*>fWxGG6Ex%8RV2l_i%3u!zQ`n<0x#c{67=YB7i?)ZR9IgKp_%B_KT z{;~~&C`d?I%W{HQ%ZhU1JBY<8I%x4Pry`FZe9aVzdy#k{dq`g4yYpSaLsto<5C|8s_%H)HL Ts*XO$Y3ii9*_~3)sLaKG9d}!0 literal 0 HcmV?d00001 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'"