From 58386856900597e0050d84d98b32e786c17d0269 Mon Sep 17 00:00:00 2001 From: Christian Manivong Date: Wed, 7 Oct 2026 17:59:55 +0200 Subject: [PATCH] feat: hand the container engine connection Container Station's docker napalm-device-types 2.6.0 opens a host's container engine through `open_container_engine()`, and asks the driver for the binary through `_container_engine_binary()`. Under QTS docker is not on PATH; the hook now returns the path `open()` already discovers, so the Engine API stream (` system dial-stdio`) and the CLI reach Container Station while callers only pass arguments (NetOrk/netork#765). Version 0.2.0, requires napalm-device-types >= 2.6.0 and napalm-linux >= 0.2.0. Refs NAPALM/napalm-device-types#17 --- CHANGELOG.md | 13 +++++++++++++ napalm_qnap_qts/qnap_qts.py | 6 ++++++ pyproject.toml | 6 +++--- tests/test_qnap_qts.py | 21 +++++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0752258..1ec86a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.2.0] – 2026-10-07 + +### Added +- `_container_engine_binary` returns Container Station's docker path, so the + container engine connection from napalm-device-types 2.6.0 + (`open_container_engine("docker")`) reaches it although it is not on PATH. + Callers pass arguments only and never see the path (NetOrk/netork#765). + +### Changed +- Requires napalm-device-types >= 2.6.0 and napalm-linux >= 0.2.0. + +## [0.1.0] + ### Added - Initial driver scaffold: `QnapQtsDriver(StorageDriver, LinuxDriver)` with discovery fingerprints (SNMP enterprise OID 1.3.6.1.4.1.24681, HTTP, port diff --git a/napalm_qnap_qts/qnap_qts.py b/napalm_qnap_qts/qnap_qts.py index d3ac268..3291c44 100644 --- a/napalm_qnap_qts/qnap_qts.py +++ b/napalm_qnap_qts/qnap_qts.py @@ -154,6 +154,12 @@ class QnapQtsDriver(StorageDriver, HypervisorDriver, LinuxDriver): """Override LinuxDriver's hook: docker is not on PATH under QTS.""" return getattr(self, "_docker_path", None) or "docker" + def _container_engine_binary(self, engine: str) -> str: + """Container Station keeps docker off PATH; callers never see the path.""" + if engine == "docker": + return self._docker_bin() + return super()._container_engine_binary(engine) + # ── QPKG, not apt ───────────────────────────────────────────────────────── # # QTS is Linux, so LinuxDriver's package methods are in the MRO and would diff --git a/pyproject.toml b/pyproject.toml index 03247bd..9a16744 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "napalm-qnap-qts" -version = "0.1.0" +version = "0.2.0" description = "NAPALM driver for QNAP NAS systems running QTS via SSH" readme = "README.md" requires-python = ">=3.9" @@ -43,8 +43,8 @@ classifiers = [ # processes, Docker) from LinuxDriver rather than reimplementing it. dependencies = [ "napalm>=4.0", - "napalm-device-types>=0.5.0", - "napalm-linux>=0.1.0", + "napalm-device-types>=2.6.0", + "napalm-linux>=0.2.0", "netmiko>=4.0.0", "paramiko>=5.0.0", # CVE-2026-44405 ] diff --git a/tests/test_qnap_qts.py b/tests/test_qnap_qts.py index 9750edb..59bffea 100644 --- a/tests/test_qnap_qts.py +++ b/tests/test_qnap_qts.py @@ -184,6 +184,27 @@ class TestDockerBinDiscovery: assert driver._docker_bin() == "/opt/docker" +class TestContainerEngineBinary: + """The container engine connection (napalm-device-types 2.6.0) reaches + Container Station's docker, not one on PATH: the driver decides where the + binary lives, and netOrk never sees it (NetOrk/netork#765).""" + + def test_the_engine_binary_is_the_discovered_path(self, driver): + driver._docker_path = "/share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker" + assert driver._container_engine_binary("docker") == driver._docker_path + + def test_the_api_stream_runs_dial_stdio_from_that_path(self, driver): + driver._docker_path = "/share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker" + opened = [] + with patch.object(driver, "open_stream", side_effect=lambda cmd, **kw: opened.append(cmd)): + driver.open_container_engine("docker").open_api() + assert opened == [f"{driver._docker_path} system dial-stdio"] + + def test_without_a_discovered_path_it_falls_back_to_plain_docker(self, driver): + driver._docker_path = None + assert driver._container_engine_binary("docker") == "docker" + + def test_services_cannot_be_controlled(): """QTS has no systemd: the systemctl actions inherited from LinuxDriver would fail on every unit, so the driver says it cannot control services at all -- -- 2.54.0