testprotocols 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- testprotocols/__init__.py +217 -0
- testprotocols/aftr_gateway.py +22 -0
- testprotocols/appliance_nat.py +52 -0
- testprotocols/appliance_uplinks.py +32 -0
- testprotocols/appliance_vlans.py +50 -0
- testprotocols/arp_client.py +26 -0
- testprotocols/bgp.py +55 -0
- testprotocols/conntrack.py +147 -0
- testprotocols/content_filtering.py +47 -0
- testprotocols/device_lifecycle.py +49 -0
- testprotocols/device_management.py +50 -0
- testprotocols/devices/__init__.py +46 -0
- testprotocols/devices/base.py +40 -0
- testprotocols/devices/client.py +133 -0
- testprotocols/devices/cpe.py +66 -0
- testprotocols/devices/infra.py +62 -0
- testprotocols/devices/sdwan.py +97 -0
- testprotocols/devices/switch.py +115 -0
- testprotocols/devices/traffic.py +53 -0
- testprotocols/devices/voice.py +69 -0
- testprotocols/devices/wan.py +60 -0
- testprotocols/dhcp_client.py +30 -0
- testprotocols/dhcp_server.py +23 -0
- testprotocols/discovery.py +20 -0
- testprotocols/dns_client.py +23 -0
- testprotocols/file_transfer.py +22 -0
- testprotocols/firewall.py +121 -0
- testprotocols/firewall_zones.py +133 -0
- testprotocols/first_hop_security.py +52 -0
- testprotocols/gateway_redundancy.py +29 -0
- testprotocols/http_client.py +36 -0
- testprotocols/http_server.py +22 -0
- testprotocols/hw_console.py +48 -0
- testprotocols/infra_controller.py +28 -0
- testprotocols/interface_dhcp.py +30 -0
- testprotocols/ip_interface.py +62 -0
- testprotocols/ip_routing.py +57 -0
- testprotocols/iperf_client.py +47 -0
- testprotocols/iperf_generator.py +42 -0
- testprotocols/iperf_server.py +41 -0
- testprotocols/l3_firewall.py +74 -0
- testprotocols/l7_firewall.py +32 -0
- testprotocols/link_aggregation.py +24 -0
- testprotocols/mac_table.py +20 -0
- testprotocols/models/__init__.py +304 -0
- testprotocols/models/dhcp.py +28 -0
- testprotocols/models/firewall.py +197 -0
- testprotocols/models/impairment.py +18 -0
- testprotocols/models/l2_common.py +53 -0
- testprotocols/models/multicast.py +22 -0
- testprotocols/models/networking.py +50 -0
- testprotocols/models/packets.py +21 -0
- testprotocols/models/qoe.py +31 -0
- testprotocols/models/radius.py +63 -0
- testprotocols/models/sdwan_appliance.py +637 -0
- testprotocols/models/switch.py +297 -0
- testprotocols/models/switch_routing.py +122 -0
- testprotocols/models/tr069.py +35 -0
- testprotocols/models/traffic.py +29 -0
- testprotocols/models/wan_edge.py +116 -0
- testprotocols/models/wifi.py +183 -0
- testprotocols/multicast_client.py +20 -0
- testprotocols/nat.py +87 -0
- testprotocols/netem_controller.py +42 -0
- testprotocols/network_endpoint.py +32 -0
- testprotocols/network_probe.py +27 -0
- testprotocols/nmap_scanner.py +27 -0
- testprotocols/ntp_client.py +26 -0
- testprotocols/ntp_config.py +25 -0
- testprotocols/ospf.py +24 -0
- testprotocols/packet_filter.py +144 -0
- testprotocols/pcap_capture.py +39 -0
- testprotocols/pdu_controller.py +26 -0
- testprotocols/port_poe.py +25 -0
- testprotocols/port_security.py +25 -0
- testprotocols/port_status.py +23 -0
- testprotocols/py.typed +0 -0
- testprotocols/qoe_browser.py +62 -0
- testprotocols/radius_client.py +78 -0
- testprotocols/radius_server.py +130 -0
- testprotocols/routed_interfaces.py +29 -0
- testprotocols/router.py +53 -0
- testprotocols/routing_read.py +22 -0
- testprotocols/sdwan_policy_manager.py +64 -0
- testprotocols/sip_phone.py +230 -0
- testprotocols/sip_server.py +205 -0
- testprotocols/site_to_site_vpn.py +61 -0
- testprotocols/snmp_client.py +17 -0
- testprotocols/spanning_tree.py +37 -0
- testprotocols/static_routes.py +47 -0
- testprotocols/storm_control.py +24 -0
- testprotocols/streaming_server.py +32 -0
- testprotocols/switch_acl.py +29 -0
- testprotocols/switch_ports.py +28 -0
- testprotocols/switch_qos.py +33 -0
- testprotocols/switch_vlans.py +34 -0
- testprotocols/syslog_config.py +31 -0
- testprotocols/tftp_server.py +22 -0
- testprotocols/threat_prevention.py +60 -0
- testprotocols/tr069_client.py +47 -0
- testprotocols/tr069_server.py +151 -0
- testprotocols/traffic_shaping.py +54 -0
- testprotocols/upnp_client.py +37 -0
- testprotocols/vlan_client.py +22 -0
- testprotocols/wan_link_admin.py +34 -0
- testprotocols/wifi_bss.py +197 -0
- testprotocols/wifi_client.py +72 -0
- testprotocols/wifi_mesh.py +259 -0
- testprotocols/wifi_onboarding.py +105 -0
- testprotocols/wifi_radio.py +153 -0
- testprotocols/wifi_rf.py +78 -0
- testprotocols/wifi_stations.py +59 -0
- testprotocols/wifi_transitions.py +112 -0
- testprotocols-0.1.0.dist-info/METADATA +29 -0
- testprotocols-0.1.0.dist-info/RECORD +119 -0
- testprotocols-0.1.0.dist-info/WHEEL +5 -0
- testprotocols-0.1.0.dist-info/licenses/LICENSE +201 -0
- testprotocols-0.1.0.dist-info/licenses/NOTICE +11 -0
- testprotocols-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Switchport configuration — the first-class object of a managed switch.
|
|
2
|
+
|
|
3
|
+
Per-port access/trunk mode, native (PVID) + allowed VLANs, enable state, voice
|
|
4
|
+
VLAN, and isolation. Read via a port listing; configured per whole-port object.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Protocol, runtime_checkable
|
|
10
|
+
|
|
11
|
+
from testprotocols.models.switch import SwitchPort
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class SwitchPorts(Protocol):
|
|
16
|
+
"""Abstract contract for per-port switchport configuration."""
|
|
17
|
+
|
|
18
|
+
def list_ports(self) -> list[SwitchPort]:
|
|
19
|
+
"""Return every switchport."""
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
def get_port(self, name: str) -> SwitchPort:
|
|
23
|
+
"""Return the port *name*. Raises KeyError if absent."""
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
def set_port(self, port: SwitchPort) -> None:
|
|
27
|
+
"""Create or replace the port identified by ``port.name``."""
|
|
28
|
+
...
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Switch QoS — classification rules, DSCP->CoS map, and trust mode."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Protocol, runtime_checkable
|
|
6
|
+
|
|
7
|
+
from testprotocols.models.switch import QosRule, QosTrustMode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@runtime_checkable
|
|
11
|
+
class SwitchQos(Protocol):
|
|
12
|
+
"""Abstract contract for switch QoS.
|
|
13
|
+
|
|
14
|
+
Explicit queue-scheduler / per-port rate-limit tuning is out of scope
|
|
15
|
+
(deferred); a product with limited scheduler control normalizes to
|
|
16
|
+
rules + trust/map.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def set_trust_mode(self, port: str, mode: QosTrustMode) -> None:
|
|
20
|
+
"""Set the QoS trust mode on *port*."""
|
|
21
|
+
...
|
|
22
|
+
|
|
23
|
+
def set_dscp_cos_map(self, mapping: dict[int, int]) -> None:
|
|
24
|
+
"""Replace the DSCP->CoS map."""
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
def set_rules(self, rules: list[QosRule]) -> None:
|
|
28
|
+
"""Replace the ordered QoS classification rule list."""
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
def get_rules(self) -> list[QosRule]:
|
|
32
|
+
"""Return the QoS classification rules."""
|
|
33
|
+
...
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""VLAN id/name registry for a managed switch.
|
|
2
|
+
|
|
3
|
+
A switch VLAN registry tracks id/name membership and port assignment; this is
|
|
4
|
+
distinct from an appliance VLAN surface, which pairs each VLAN with an SVI,
|
|
5
|
+
DHCP scope, and routing policy. Keeping them separate lets each capability
|
|
6
|
+
protocol stay minimal and composable.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Protocol, runtime_checkable
|
|
12
|
+
|
|
13
|
+
from testprotocols.models.switch import VlanDef
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class SwitchVlans(Protocol):
|
|
18
|
+
"""Abstract contract for the switch VLAN registry."""
|
|
19
|
+
|
|
20
|
+
def list_vlans(self) -> list[VlanDef]:
|
|
21
|
+
"""Return every configured VLAN."""
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
def create_vlan(self, vlan: VlanDef) -> None:
|
|
25
|
+
"""Create or rename the VLAN ``vlan.vlan_id``.
|
|
26
|
+
|
|
27
|
+
A driver whose product treats VLANs as implicit (no first-class CRUD)
|
|
28
|
+
raises unsupported-capability here.
|
|
29
|
+
"""
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
def delete_vlan(self, vlan_id: int) -> None:
|
|
33
|
+
"""Delete VLAN *vlan_id*. Raises unsupported-capability where VLANs are implicit."""
|
|
34
|
+
...
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Syslog-destination template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for configuring where a device sends its syslog
|
|
4
|
+
streams and which log roles each destination receives. Small and generic — any
|
|
5
|
+
networked device with remote logging can satisfy it — scoped here to the SD-WAN
|
|
6
|
+
appliance archetype where event/flow/security logging drives test evidence.
|
|
7
|
+
|
|
8
|
+
In scope: read/replace the syslog-server list.
|
|
9
|
+
|
|
10
|
+
Out of scope: reading the log contents themselves (that is the collector's job /
|
|
11
|
+
the realtime-syslog path), and security-event retrieval (see ``threat_prevention``).
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Protocol, runtime_checkable
|
|
17
|
+
|
|
18
|
+
from testprotocols.models.sdwan_appliance import SyslogServer
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@runtime_checkable
|
|
22
|
+
class SyslogConfig(Protocol):
|
|
23
|
+
"""Abstract contract for configuring syslog destinations."""
|
|
24
|
+
|
|
25
|
+
def set_syslog_servers(self, servers: list[SyslogServer]) -> None:
|
|
26
|
+
"""Replace the configured syslog-destination list with *servers*."""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
def get_syslog_servers(self) -> list[SyslogServer]:
|
|
30
|
+
"""Return the configured syslog destinations."""
|
|
31
|
+
...
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""TFTP / Server template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for TFTP server operations including
|
|
4
|
+
image download and lighttpd service management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Protocol, runtime_checkable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class TftpServer(Protocol):
|
|
14
|
+
"""Abstract contract for TFTP server operations."""
|
|
15
|
+
|
|
16
|
+
def download_image_from_uri(self, image_uri: str) -> str:
|
|
17
|
+
"""Download an image from *image_uri* and return the local path."""
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
def restart_lighttpd(self) -> None:
|
|
21
|
+
"""Restart the lighttpd service on the TFTP server."""
|
|
22
|
+
...
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Threat-prevention template — IDS/IPS, anti-malware, and security events.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for a managed SD-WAN appliance's threat-prevention
|
|
4
|
+
subsystem: configuring intrusion detection/prevention and anti-malware, and
|
|
5
|
+
reading back security events.
|
|
6
|
+
|
|
7
|
+
Security-event reads here are the *deferred*, settle-aware augmentation surface;
|
|
8
|
+
realtime assertions in a testbed should still use the syslog backbone. Events
|
|
9
|
+
carry only normalized fields (action + category, not vendor signature ids).
|
|
10
|
+
|
|
11
|
+
In scope: intrusion mode/sensitivity, malware mode, security-event retrieval.
|
|
12
|
+
|
|
13
|
+
Out of scope: firewall rules (see ``l3_firewall`` / ``l7_firewall``), content
|
|
14
|
+
filtering (see ``content_filtering``), and syslog destination config (see
|
|
15
|
+
``syslog_config``).
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Protocol, runtime_checkable
|
|
21
|
+
|
|
22
|
+
from testprotocols.models.sdwan_appliance import (
|
|
23
|
+
IntrusionConfig,
|
|
24
|
+
IntrusionMode,
|
|
25
|
+
IntrusionSensitivity,
|
|
26
|
+
MalwareConfig,
|
|
27
|
+
MalwareMode,
|
|
28
|
+
SecurityEvent,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@runtime_checkable
|
|
33
|
+
class ThreatPrevention(Protocol):
|
|
34
|
+
"""Abstract contract for an appliance's IDS/IPS + anti-malware subsystem."""
|
|
35
|
+
|
|
36
|
+
def set_intrusion(
|
|
37
|
+
self, mode: IntrusionMode, sensitivity: IntrusionSensitivity | None = None
|
|
38
|
+
) -> None:
|
|
39
|
+
"""Set the IDS/IPS *mode* and optional ruleset *sensitivity*."""
|
|
40
|
+
...
|
|
41
|
+
|
|
42
|
+
def get_intrusion(self) -> IntrusionConfig:
|
|
43
|
+
"""Return the current IDS/IPS configuration."""
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
def set_malware(self, mode: MalwareMode) -> None:
|
|
47
|
+
"""Enable or disable anti-malware protection."""
|
|
48
|
+
...
|
|
49
|
+
|
|
50
|
+
def get_malware(self) -> MalwareConfig:
|
|
51
|
+
"""Return the current anti-malware configuration."""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
def get_security_events(self, since_s: int = 3600) -> list[SecurityEvent]:
|
|
55
|
+
"""Return security events from the last *since_s* seconds.
|
|
56
|
+
|
|
57
|
+
Deferred / settle-aware augmentation surface — not the realtime
|
|
58
|
+
assertion path. Empty list when none.
|
|
59
|
+
"""
|
|
60
|
+
...
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""TR-069 CPE client template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for TR-069 client operations on a CPE
|
|
4
|
+
device — the CPE-side counterpart to the ACS-side ``Tr069Server``
|
|
5
|
+
Protocol. Covers connection status, log retrieval, the CPE's own
|
|
6
|
+
identity, and the ability to force an immediate Inform.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Protocol, runtime_checkable
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class Tr069Client(Protocol):
|
|
16
|
+
"""Abstract contract for TR-069 client operations on a CPE device."""
|
|
17
|
+
|
|
18
|
+
def is_tr069_connected(self) -> bool:
|
|
19
|
+
"""Return True if the CPE has an active TR-069 connection to the ACS."""
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
def get_tr069_log(self) -> list[str]:
|
|
23
|
+
"""Return the TR-069 client log as a list of log lines."""
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
def get_id(self) -> str:
|
|
27
|
+
"""Return the CPE's TR-069 device identifier as known to the ACS.
|
|
28
|
+
|
|
29
|
+
Per CWMP §A.3.3.1 this is the ``OUI-ProductClass-SerialNumber``
|
|
30
|
+
tuple the CPE uses in its Inform header. The ACS uses this as
|
|
31
|
+
its primary key when storing the per-CPE record. Implementations
|
|
32
|
+
should source the value from the CPE itself (e.g. the CWMP
|
|
33
|
+
daemon's UCI config) rather than from external inventory, so
|
|
34
|
+
the value is always self-consistent with what the ACS sees.
|
|
35
|
+
"""
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
def force_inform(self) -> None:
|
|
39
|
+
"""Trigger an immediate Inform to the ACS, bypassing the periodic schedule.
|
|
40
|
+
|
|
41
|
+
Used to make queued ACS-side tasks execute promptly instead of
|
|
42
|
+
waiting for the next periodic Inform window (typically 300s).
|
|
43
|
+
Implementations route through whatever CWMP daemon ipc the CPE
|
|
44
|
+
provides (``ubus call tr069 inform`` on prplOS/iCWMPD, the
|
|
45
|
+
equivalent on other daemons).
|
|
46
|
+
"""
|
|
47
|
+
...
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""TR-069 ACS server template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for TR-069 ACS (Auto Configuration Server)
|
|
4
|
+
operations, including all standard CWMP RPC methods and ACS-side state
|
|
5
|
+
(inventory, per-CPE connection status, Inform timing).
|
|
6
|
+
|
|
7
|
+
"CPE" follows TR-069 §2: any CWMP-managed device — gateway, set-top box,
|
|
8
|
+
VoIP ATA, femtocell, IoT endpoint — not specifically a residential
|
|
9
|
+
gateway.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Any, Protocol, runtime_checkable
|
|
15
|
+
|
|
16
|
+
from testprotocols.models.tr069 import CpeConnectionStatus
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class Tr069Server(Protocol):
|
|
21
|
+
"""Abstract contract for TR-069 ACS operations."""
|
|
22
|
+
|
|
23
|
+
def GPV(
|
|
24
|
+
self,
|
|
25
|
+
param: str | list[str],
|
|
26
|
+
timeout: int | None = None,
|
|
27
|
+
cpe_id: str | None = None,
|
|
28
|
+
) -> list[dict[str, Any]]:
|
|
29
|
+
"""GetParameterValues RPC."""
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
def SPV(
|
|
33
|
+
self,
|
|
34
|
+
param_value: dict[str, Any] | list[dict[str, Any]],
|
|
35
|
+
timeout: int | None = None,
|
|
36
|
+
cpe_id: str | None = None,
|
|
37
|
+
) -> int:
|
|
38
|
+
"""SetParameterValues RPC."""
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
def GPA(
|
|
42
|
+
self,
|
|
43
|
+
param: str,
|
|
44
|
+
cpe_id: str | None = None,
|
|
45
|
+
) -> list[dict[str, Any]]:
|
|
46
|
+
"""GetParameterAttributes RPC."""
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
def SPA(
|
|
50
|
+
self,
|
|
51
|
+
param: list[dict[str, Any]] | dict[str, Any],
|
|
52
|
+
notification_param: bool = True,
|
|
53
|
+
access_param: bool = False,
|
|
54
|
+
access_list: list[Any] | None = None,
|
|
55
|
+
cpe_id: str | None = None,
|
|
56
|
+
) -> list[dict[str, Any]]:
|
|
57
|
+
"""SetParameterAttributes RPC."""
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
def FactoryReset(self, cpe_id: str | None = None) -> list[dict[str, Any]]:
|
|
61
|
+
"""FactoryReset RPC."""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
def Reboot(
|
|
65
|
+
self,
|
|
66
|
+
CommandKey: str = "reboot",
|
|
67
|
+
cpe_id: str | None = None,
|
|
68
|
+
) -> list[dict[str, Any]]:
|
|
69
|
+
"""Reboot RPC."""
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
def AddObject(
|
|
73
|
+
self,
|
|
74
|
+
param: str,
|
|
75
|
+
param_key: str = "",
|
|
76
|
+
cpe_id: str | None = None,
|
|
77
|
+
) -> list[dict[str, Any]]:
|
|
78
|
+
"""AddObject RPC."""
|
|
79
|
+
...
|
|
80
|
+
|
|
81
|
+
def DelObject(
|
|
82
|
+
self,
|
|
83
|
+
param: str,
|
|
84
|
+
param_key: str = "",
|
|
85
|
+
cpe_id: str | None = None,
|
|
86
|
+
) -> list[dict[str, Any]]:
|
|
87
|
+
"""DeleteObject RPC."""
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
def GPN(
|
|
91
|
+
self,
|
|
92
|
+
param: str,
|
|
93
|
+
next_level: bool,
|
|
94
|
+
timeout: int | None = None,
|
|
95
|
+
cpe_id: str | None = None,
|
|
96
|
+
) -> list[dict[str, Any]]:
|
|
97
|
+
"""GetParameterNames RPC."""
|
|
98
|
+
...
|
|
99
|
+
|
|
100
|
+
def ScheduleInform(
|
|
101
|
+
self,
|
|
102
|
+
CommandKey: str = "Test",
|
|
103
|
+
DelaySeconds: int = 20,
|
|
104
|
+
cpe_id: str | None = None,
|
|
105
|
+
) -> list[dict[str, Any]]:
|
|
106
|
+
"""ScheduleInform RPC."""
|
|
107
|
+
...
|
|
108
|
+
|
|
109
|
+
def GetRPCMethods(self, cpe_id: str | None = None) -> list[dict[str, Any]]:
|
|
110
|
+
"""GetRPCMethods RPC."""
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
def Download(
|
|
114
|
+
self,
|
|
115
|
+
url: str,
|
|
116
|
+
filetype: str = "1 Firmware Upgrade Image",
|
|
117
|
+
targetfilename: str = "",
|
|
118
|
+
filesize: int = 200,
|
|
119
|
+
username: str = "",
|
|
120
|
+
password: str = "",
|
|
121
|
+
commandkey: str = "",
|
|
122
|
+
delayseconds: int = 10,
|
|
123
|
+
successurl: str = "",
|
|
124
|
+
failureurl: str = "",
|
|
125
|
+
cpe_id: str | None = None,
|
|
126
|
+
) -> list[dict[str, Any]]:
|
|
127
|
+
"""Download RPC."""
|
|
128
|
+
...
|
|
129
|
+
|
|
130
|
+
def provision_cpe_via_tr069(
|
|
131
|
+
self,
|
|
132
|
+
tr069provision_api_list: list[dict[str, list[dict[str, str]]]],
|
|
133
|
+
cpe_id: str,
|
|
134
|
+
) -> None:
|
|
135
|
+
"""Provision a CPE by executing a sequence of TR-069 API calls."""
|
|
136
|
+
...
|
|
137
|
+
|
|
138
|
+
def list_cpes(
|
|
139
|
+
self,
|
|
140
|
+
criteria: dict[str, str] | None = None,
|
|
141
|
+
) -> list[str]:
|
|
142
|
+
"""Return CPE IDs known to the ACS, optionally filtered by criteria."""
|
|
143
|
+
...
|
|
144
|
+
|
|
145
|
+
def delete_cpe_record(self, cpe_id: str) -> bool:
|
|
146
|
+
"""Delete the CPE record from the ACS inventory. Return True on success."""
|
|
147
|
+
...
|
|
148
|
+
|
|
149
|
+
def get_cpe_connection_status(self, cpe_id: str) -> CpeConnectionStatus:
|
|
150
|
+
"""Return the ACS-side view of the CPE's connection state and cached metadata."""
|
|
151
|
+
...
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Traffic-shaping template — managed SD-WAN appliance.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for an appliance's bandwidth and QoS shaping:
|
|
4
|
+
per-uplink bandwidth caps, a global per-client cap, and an ordered set of
|
|
5
|
+
shaping rules that match a traffic class and limit / DSCP-mark / prioritize it.
|
|
6
|
+
|
|
7
|
+
In scope: uplink bandwidth, global per-client bandwidth, and the shaping-rule
|
|
8
|
+
list (which also carries DSCP marking).
|
|
9
|
+
|
|
10
|
+
Support note: per-uplink caps, shaping rules, and DSCP marking are universal
|
|
11
|
+
across reviewed appliance families; the **global per-client cap is not** —
|
|
12
|
+
several families expose no per-client/per-host primitive, and their drivers
|
|
13
|
+
raise unsupported-capability on the per-client methods (a coverage gap, not
|
|
14
|
+
a contract leak).
|
|
15
|
+
|
|
16
|
+
Out of scope: SD-WAN path selection / SLA steering (see ``sdwan_policy_manager``),
|
|
17
|
+
firewall rules (see ``l3_firewall`` / ``l7_firewall``), and link impairment
|
|
18
|
+
(``netem`` lives on the traffic-controller device, not the appliance).
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from typing import Protocol, runtime_checkable
|
|
24
|
+
|
|
25
|
+
from testprotocols.models.sdwan_appliance import ShapingRule
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@runtime_checkable
|
|
29
|
+
class TrafficShaping(Protocol):
|
|
30
|
+
"""Abstract contract for an appliance's bandwidth / QoS shaping."""
|
|
31
|
+
|
|
32
|
+
def set_uplink_bandwidth(self, uplink: str, down_kbps: int, up_kbps: int) -> None:
|
|
33
|
+
"""Set the down/up bandwidth limit (kbps) for the named WAN *uplink*."""
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
def get_uplink_bandwidth(self) -> dict[str, tuple[int, int]]:
|
|
37
|
+
"""Return ``{uplink: (down_kbps, up_kbps)}`` for every uplink."""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def set_global_client_bandwidth(self, down_kbps: int, up_kbps: int) -> None:
|
|
41
|
+
"""Set the global per-client down/up bandwidth limit (kbps)."""
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
def get_global_client_bandwidth(self) -> tuple[int, int]:
|
|
45
|
+
"""Return the global per-client ``(down_kbps, up_kbps)`` limit."""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
def set_shaping_rules(self, rules: list[ShapingRule]) -> None:
|
|
49
|
+
"""Replace the ordered shaping-rule list with *rules*."""
|
|
50
|
+
...
|
|
51
|
+
|
|
52
|
+
def get_shaping_rules(self) -> list[ShapingRule]:
|
|
53
|
+
"""Return the shaping rules in evaluation order."""
|
|
54
|
+
...
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""UPnP / Client template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for UPnP client operations including
|
|
4
|
+
port mapping rule creation and deletion.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Protocol, runtime_checkable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class UpnpClient(Protocol):
|
|
14
|
+
"""Abstract contract for UPnP client operations."""
|
|
15
|
+
|
|
16
|
+
def create_upnp_rule(
|
|
17
|
+
self,
|
|
18
|
+
interface: str,
|
|
19
|
+
ipaddr: str,
|
|
20
|
+
int_port: str,
|
|
21
|
+
ext_port: str,
|
|
22
|
+
protocol: str,
|
|
23
|
+
extra_args: str,
|
|
24
|
+
url: str,
|
|
25
|
+
) -> str:
|
|
26
|
+
"""Create a UPnP port-mapping rule and return the result string."""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
def delete_upnp_rule(
|
|
30
|
+
self,
|
|
31
|
+
interface: str,
|
|
32
|
+
ext_port: str,
|
|
33
|
+
protocol: str,
|
|
34
|
+
url: str,
|
|
35
|
+
) -> str:
|
|
36
|
+
"""Delete a UPnP port-mapping rule and return the result string."""
|
|
37
|
+
...
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""VLAN / Client template.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for VLAN client operations including
|
|
4
|
+
virtual interface creation and deletion.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Protocol, runtime_checkable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class VlanClient(Protocol):
|
|
14
|
+
"""Abstract contract for VLAN client operations."""
|
|
15
|
+
|
|
16
|
+
def add_vlan_interface(self, vlan_id: str) -> None:
|
|
17
|
+
"""Create a VLAN interface for *vlan_id*."""
|
|
18
|
+
...
|
|
19
|
+
|
|
20
|
+
def delete_vlan_interface(self, vlan_id: str) -> None:
|
|
21
|
+
"""Delete the VLAN interface for *vlan_id*."""
|
|
22
|
+
...
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""WAN link administration template — host-substrate WAN edge.
|
|
2
|
+
|
|
3
|
+
Defines the abstract contract for administratively bringing a WAN link down
|
|
4
|
+
or up by label. This is a **host-substrate lever**: a Linux-based WAN edge
|
|
5
|
+
(the digital twin) can admin-down its own uplink, but an API-managed
|
|
6
|
+
appliance generally cannot — its management plane exposes no such operation,
|
|
7
|
+
and link impairment for appliance tests is the traffic-controller's job (the
|
|
8
|
+
same boundary as the netem precedent; see SPLITS.md). The methods moved here
|
|
9
|
+
from ``router.Router`` so the read surface stays universal across both
|
|
10
|
+
WAN-edge archetypes while link administration rides only on the twin.
|
|
11
|
+
|
|
12
|
+
In scope: administrative up/down of a WAN link identified by label.
|
|
13
|
+
|
|
14
|
+
Out of scope: link impairment — latency/loss/blackout shaping (see
|
|
15
|
+
``netem_controller``), uplink status reads (see ``router`` /
|
|
16
|
+
``appliance_uplinks``), and per-netdev interface config (see ``ip_interface``).
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Protocol, runtime_checkable
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@runtime_checkable
|
|
25
|
+
class WanLinkAdmin(Protocol):
|
|
26
|
+
"""Abstract contract for administrative WAN link up/down."""
|
|
27
|
+
|
|
28
|
+
def bring_wan_down(self, label: str) -> None:
|
|
29
|
+
"""Bring down the WAN interface identified by *label*."""
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
def bring_wan_up(self, label: str) -> None:
|
|
33
|
+
"""Bring up the WAN interface identified by *label*."""
|
|
34
|
+
...
|