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:
@@ -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
|
||||
|
||||
@@ -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"}
|
||||
Reference in New Issue
Block a user