feat(firewall): add send_wake_on_lan() capability to FirewallDriver

Abstract method for sending a Wake-on-LAN magic packet through a
firewall's driver connection, following the same contract style as
get_nat_translations/get_security_zones. Raises NotImplementedError
by default; concrete drivers implement it per their own API.
This commit is contained in:
2026-07-12 11:17:26 +02:00
parent 841881018c
commit 478c7b434a
2 changed files with 59 additions and 0 deletions
+27
View File
@@ -160,6 +160,33 @@ class FirewallDriver(DeviceTypeDriver):
"""
raise NotImplementedError
def send_wake_on_lan(self, mac_address: str, interface: str = "") -> Dict[str, Any]:
"""
Sends a Wake-on-LAN "magic packet" to wake a host on the network.
:param mac_address: Target host's MAC address (colon-separated,
case-insensitive, e.g. ``"AA:BB:CC:DD:EE:FF"``).
:param interface: Driver-specific interface identifier to broadcast the
magic packet from. Required by drivers that scope WOL per interface
(e.g. OPNsense); an empty string means "use the driver's default/
only broadcast domain." Consult the concrete driver's docstring for
the exact expected format.
:raises NotImplementedError: If the driver does not support Wake-on-LAN.
:raises ValueError: If ``mac_address`` is malformed, or ``interface`` is
required by this driver but was not provided.
:returns: A dict with:
* success (bool) - ``True`` if the magic packet was sent without error
* output (string) - human-readable status message
Example::
driver.send_wake_on_lan("AA:BB:CC:DD:EE:FF", interface="lan")
# → {"success": True, "output": "Magic packet sent to AA:BB:CC:DD:EE:FF via lan"}
"""
raise NotImplementedError
def get_packages(self) -> List[PackageDict]:
"""
Returns all packages / plugins currently known to the firewall's
+32
View File
@@ -0,0 +1,32 @@
"""Tests for FirewallDriver.send_wake_on_lan default contract."""
import pytest
from napalm_device_types import FirewallDriver
class _BareFirewall(FirewallDriver):
"""FirewallDriver.__init__ is NetworkDriver's, which itself raises
NotImplementedError — override with a no-op so tests exercise
send_wake_on_lan itself, not construction."""
def __init__(self):
pass
def test_send_wake_on_lan_raises_not_implemented_by_default():
with pytest.raises(NotImplementedError):
_BareFirewall().send_wake_on_lan("AA:BB:CC:DD:EE:FF")
def test_send_wake_on_lan_accepts_optional_interface():
with pytest.raises(NotImplementedError):
_BareFirewall().send_wake_on_lan("AA:BB:CC:DD:EE:FF", interface="lan")
def test_subclass_can_implement_send_wake_on_lan():
class MyFirewall(_BareFirewall):
def send_wake_on_lan(self, mac_address: str, interface: str = ""):
return {"success": True, "output": f"woke {mac_address} via {interface}"}
result = MyFirewall().send_wake_on_lan("AA:BB:CC:DD:EE:FF", interface="lan")
assert result == {"success": True, "output": "woke AA:BB:CC:DD:EE:FF via lan"}