feat: a public command channel; no warnings of its own (0.4.0)
CI / test (3.10) (push) Successful in 25s
CI / test (3.11) (push) Successful in 24s
CI / test (3.12) (push) Successful in 25s
CI / test (3.10) (pull_request) Successful in 25s
CI / test (3.11) (pull_request) Successful in 24s
CI / test (3.12) (pull_request) Successful in 25s

run_command and open_stream (napalm-device-types CommandChannelMixin,
which AccessPointDriver carries) run on an SSH exec channel next to
netmiko's shell: stdin, stderr apart, a real exit code. netOrk sent UCI
scripts and the wifi channel through the private _send_command, typing
a file in base64 chunks or printf lines; with stdin it writes it with
cat, and base64 is needed for nothing (netOrk #1113). OpenWrt has no
sudo, so a privileged command from a login other than root is refused
before it runs.

get_device_warnings goes with it: no_base64 was its last code.
This commit is contained in:
Christian Manivong committed 2026-10-18 14:08:09 +02:00
1 parent 100a6d36c5
commit 595496549b
5 files changed
+120 -57

No files matched your search

+79
View File
@@ -0,0 +1,79 @@
"""A public command channel (napalm-device-types ``CommandChannelMixin``, netOrk #1113).
netOrk sent UCI scripts and the wifi channel through the private
``_send_command``: an interactive shell with no exit code, where a file had to
be typed in base64 chunks or ``printf`` lines. ``run_command`` runs on an SSH
exec channel of its own, with stdin, stderr and the exit code -- a script is
written with ``cat`` from stdin, and ``base64`` is needed for nothing.
"""
from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
from napalm.base.exceptions import ConnectionClosedException
from napalm_device_types import CommandResult
from napalm_openwrt.openwrt import OpenWrtDriver
def _driver(username: str = "root") -> OpenWrtDriver:
with patch("napalm_openwrt.openwrt.ConnectHandler"):
drv = OpenWrtDriver(hostname="192.0.2.15", username=username, password="")
drv.device = MagicMock()
return drv
def test_a_command_runs_on_the_ssh_transport_with_its_stdin():
drv = _driver()
transport = drv.device.remote_conn_pre.get_transport.return_value
done = CommandResult("", "", 0)
with patch("napalm_openwrt.openwrt.run_on_transport", return_value=done) as run:
result = drv.run_command("cat > /tmp/x.sh", stdin=b"uci commit\n", timeout=30)
assert result is done
run.assert_called_once_with(transport, "cat > /tmp/x.sh", stdin=b"uci commit\n", timeout=30)
def test_root_runs_privileged_commands_as_they_are():
drv = _driver()
with patch("napalm_openwrt.openwrt.run_on_transport") as run:
drv.run_command("wifi", privileged=True)
assert run.call_args.args[1] == "wifi"
def test_a_login_other_than_root_cannot_gain_root():
"""OpenWrt has no sudo: refused before anything runs, not half done."""
drv = _driver(username="admin")
with patch("napalm_openwrt.openwrt.run_on_transport") as run, pytest.raises(PermissionError):
drv.run_command("wifi", privileged=True)
run.assert_not_called()
def test_a_stream_on_the_same_transport():
drv = _driver()
transport = drv.device.remote_conn_pre.get_transport.return_value
with patch("napalm_openwrt.openwrt.open_stream_on_transport") as stream:
drv.open_stream("logread -f")
stream.assert_called_once_with(transport, "logread -f")
def test_not_connected():
drv = _driver()
drv.device = None
with pytest.raises(ConnectionClosedException):
drv.run_command("true")
def test_no_warnings_of_its_own():
"""base64 is no longer needed for anything, so a missing one is no warning;
lldpd, auc and the updates are facts the caller reads (netOrk #1111)."""
assert not any(
"get_device_warnings" in vars(c)
for c in OpenWrtDriver.__mro__
if c.__module__.startswith("napalm_openwrt")
)
-43
View File
@@ -1,43 +0,0 @@
"""What the driver still names itself (netOrk #1111).
lldpd, auc and the pending updates are facts the caller reads (``get_packages``,
``get_available_updates``) and decides on. A missing ``base64`` stays: BusyBox
may provide it as an applet, so no package says whether it is there.
"""
from __future__ import annotations
from napalm_openwrt import OpenWrtDriver
def _driver(answers: dict[str, str]) -> OpenWrtDriver:
d = OpenWrtDriver("ap", "root", "pw")
issued: list[str] = []
def send(command: str) -> str:
issued.append(command)
return next((out for frag, out in answers.items() if frag in command), "")
d._send_command = send
d.issued = issued
return d
def test_nothing_installed_names_only_base64():
"""No lldpd, no auc and an opkg system: the caller names those from the packages."""
d = _driver({"opkg list-upgradable": "luci - 1.0 - 1.1\n"})
assert [w["code"] for w in d.get_device_warnings()] == ["no_base64"]
def test_base64_present_names_nothing():
d = _driver({"command -v base64": "/usr/bin/base64\n"})
assert d.get_device_warnings() == []
def test_one_command_per_poll():
d = _driver({})
d.get_device_warnings()
assert d.issued == ["command -v base64 2>/dev/null"]