napalm-qnap-qts
NAPALM driver for QNAP NAS systems running QTS, over SSH.
QTS is a Linux distribution, so this driver inherits the whole OS surface from
napalm-linux —
packages, services, users, processes, Docker — and adds QNAP's storage, QPKG
and virtualisation layers on top.
Targets QTS 4.x and QTS 5.x.
Status
The class scaffold, discovery fingerprints and version/tool detection are in place. The storage, QPKG and VM parsers are not written yet: they are blocked on capturing real command output from hardware (see Harvesting fixtures). Writing parsers against guessed output is how a driver ends up passing its own tests and failing on a real NAS.
| Method | Source | Status |
|---|---|---|
get_facts |
getcfg, getsysinfo, /proc/uptime |
pending harvest |
get_interfaces, get_interfaces_ip |
ip / ifconfig |
pending harvest |
get_disks |
qcli_storage -d, get_hd_smartinfo |
pending harvest |
get_disk_pools |
qcli_storage -p, /proc/mdstat |
pending harvest |
get_volumes |
qcli_storage -v, df |
pending harvest |
get_shares |
/etc/config/smb.conf, /etc/exports |
pending harvest |
get_storage_services |
getcfg, ss -lntup |
pending harvest |
get_disk_smart |
get_hd_smartinfo |
pending harvest |
get_packages |
QPKG (qpkg.conf / qpkg_cli) |
pending harvest |
get_vms |
virsh (Virtualization Station) |
pending harvest |
start_vm, stop_vm, reboot_vm |
virsh |
pending harvest |
set_service_enabled |
setcfg, /etc/init.d |
pending harvest |
get_device_warnings |
derived from the above | pending harvest |
get_docker_info |
inherited, via _docker_bin() |
✅ |
get_services, get_users, get_processes |
inherited from LinuxDriver |
✅ |
get_health_metrics |
inherited (UCD-MIB over SNMP) | ✅ |
ping, ping_sweep |
inherited from LinuxDriver |
✅ |
| Snapshots, quotas, replication, QPKG install/remove | — | out of scope for v1 |
Requirements
SSH must be enabled on the NAS: Control Panel → Telnet/SSH → Allow SSH connection. The driver connects on port 22 by default; the QTS web UI on 443/8080 is not used.
Install
pip install -e vendor/napalm-device-types/ -e vendor/napalm-linux/ -e vendor/napalm-qnap-qts/
Usage
from napalm_qnap_qts import QnapQtsDriver
driver = QnapQtsDriver("nas.example.lan", "admin", "secret")
driver.open()
print(driver.get_facts())
driver.close()
Recognised optional_args: everything napalm-linux accepts (port,
sudo_password, secret, …). Unknown keys are ignored.
Design notes
Inheritance order
class QnapQtsDriver(StorageDriver, LinuxDriver):
StorageDriver precedes LinuxDriver in the MRO, so its
NotImplementedError stubs shadow LinuxDriver's working implementations
wherever the names collide — get_services, get_packages,
install_package. Each collision is resolved with an explicit forwarding
method; TestMroForwarding guards that they stay resolved.
NAS services are exposed as get_storage_services(), not get_services():
netOrk's poller reads the former for the storage snapshot and the latter for
the OS service list. Same convention as napalm-openmediavault.
Device class
The driver sets DEVICE_CLASS = "storage" explicitly. Without it netOrk's
issubclass chain reaches OSDriver before StorageDriver and would file a
QNAP under "linux", hiding its Storage tab. VMs and containers stay visible
through capability introspection (supports_vms), not through this key — a
QNAP running Virtualization Station is a NAS and a hypervisor, and
device_class only holds one of those.
Docker
Container Station does not put docker on PATH; it lives under
/share/<pool>/.qpkg/container-station/. The Docker logic stays in
LinuxDriver and only the path is overridden here, via the _docker_bin()
hook.
Harvesting fixtures
./tools/harvest.sh admin@nas4.example.lan qts4
./tools/harvest.sh admin@nas5.example.lan qts5
./tools/sanitize.py tools/harvest-out/qts5 --extra-host mynas
harvest.sh runs the command set this driver parses over a single SSH session
and writes one file per command. sanitize.py replaces serial numbers, MACs,
IP addresses and hostnames with stable placeholders — cross-references between
files survive, so the fixtures still describe one coherent device.
Read the sanitised output before committing it. The sanitiser catches patterns, not judgement, and fixtures live in git forever. Raw harvest output is gitignored and must never be committed.
Where QTS 4 and QTS 5 differ, keep both fixtures and parametrise the test over the pair, so the version divergence is part of the test matrix rather than a later surprise.
Development
pip install -e ".[dev]"
python -m pytest -q
ruff check .
License
Apache-2.0