133 lines
4.9 KiB
Markdown
133 lines
4.9 KiB
Markdown
# 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`](https://git.netork.io/NAPALM/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](#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
|
|
|
|
```bash
|
|
pip install -e vendor/napalm-device-types/ -e vendor/napalm-linux/ -e vendor/napalm-qnap-qts/
|
|
```
|
|
|
|
## Usage
|
|
|
|
```python
|
|
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
|
|
|
|
```python
|
|
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
|
|
|
|
```bash
|
|
./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
|
|
|
|
```bash
|
|
pip install -e ".[dev]"
|
|
python -m pytest -q
|
|
ruff check .
|
|
```
|
|
|
|
## License
|
|
|
|
Apache-2.0
|