refactor: the CARP state table lives with the driver that speaks CARP
CI / test (3.10) (push) Failing after 15s
CI / test (3.11) (push) Failing after 15s
CI / test (3.12) (push) Successful in 30s
CI / test (3.10) (pull_request) Successful in 30s
CI / test (3.11) (pull_request) Successful in 28s
CI / test (3.12) (pull_request) Successful in 29s
CI / test (3.10) (push) Failing after 15s
CI / test (3.11) (push) Failing after 15s
CI / test (3.12) (push) Successful in 30s
CI / test (3.10) (pull_request) Successful in 30s
CI / test (3.11) (pull_request) Successful in 28s
CI / test (3.12) (pull_request) Successful in 29s
carp_virtual_ip() and its state table moved here from napalm-device-types (4.10.1, NAPALM/napalm-device-types#39): under the agreed structure the base package carries only the shape of the reading, and what a CARP state means is protocol knowledge. Tests moved along (test_carp_states.py).
This commit is contained in:
1 parent
00172f7a69
commit
c868d41322
3 files changed
+177
-5
No files matched your search
@@ -9,17 +9,78 @@ VHID's MASTER. An address without a VHID stays on this node and is no virtual IP
|
||||
each VHID's CARP password in it. The overview has none, so a secret never reaches
|
||||
the caller.
|
||||
|
||||
What a state means (MASTER holds, BACKUP stands by) is the same on every CARP
|
||||
firewall: :func:`napalm_device_types.virtual_ips.carp_virtual_ip`.
|
||||
What a state means -- MASTER holds, BACKUP stands by -- is CARP protocol
|
||||
knowledge, so it lives here with the driver that speaks CARP
|
||||
(:func:`carp_virtual_ip`), not in napalm-device-types, which carries only the
|
||||
shape of the reading.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ipaddress
|
||||
from typing import Any
|
||||
from typing import Any, Optional
|
||||
|
||||
from napalm_device_types.models import VirtualIpDict
|
||||
from napalm_device_types.virtual_ips import carp_virtual_ip
|
||||
|
||||
#: CARP's state of a VHID on one member -> (running, holds).
|
||||
_CARP_STATES: dict[str, tuple[bool, bool]] = {
|
||||
"MASTER": (True, True),
|
||||
"BACKUP": (True, False),
|
||||
"INIT": (False, False),
|
||||
"DISABLED": (False, False),
|
||||
}
|
||||
|
||||
|
||||
def _address(text: str) -> Optional[tuple[str, Optional[int]]]:
|
||||
"""``"10.0.0.1/24"`` -> ``("10.0.0.1", 24)``; None for what is no address."""
|
||||
host, slash, prefix = text.partition("/")
|
||||
try:
|
||||
address = ipaddress.ip_address(host)
|
||||
except ValueError:
|
||||
return None
|
||||
if not slash:
|
||||
return str(address), None
|
||||
if not prefix.isdigit() or int(prefix) > address.max_prefixlen:
|
||||
return None
|
||||
return str(address), int(prefix)
|
||||
|
||||
|
||||
def carp_virtual_ip(
|
||||
*,
|
||||
address: str,
|
||||
prefix_length: Optional[int],
|
||||
vhid: object,
|
||||
state: Optional[str],
|
||||
instance: str,
|
||||
interface: Optional[str],
|
||||
) -> Optional[VirtualIpDict]:
|
||||
"""One address bound to a CARP VHID, as a virtual IP; None for what is no address.
|
||||
|
||||
Who holds it comes from CARP's *state* on this member, not from its
|
||||
interfaces: MASTER holds it, BACKUP stands by, INIT and DISABLED neither run
|
||||
nor hold. A state this does not know says nothing (``running`` and ``holds``
|
||||
None), and the caller falls back on the interfaces. *address* may carry its
|
||||
prefix (``"10.0.0.1/24"``), which then wins over *prefix_length*.
|
||||
"""
|
||||
parsed = _address(address.strip()) if address else None
|
||||
if parsed is None:
|
||||
return None
|
||||
normalised, written = parsed
|
||||
prefix = written if written is not None else prefix_length
|
||||
if prefix is not None and not 0 <= prefix <= ipaddress.ip_address(normalised).max_prefixlen:
|
||||
prefix = None
|
||||
vhid_text = str(vhid).strip() if vhid is not None else ""
|
||||
running, holds = _CARP_STATES.get((state or "").strip().upper(), (None, None))
|
||||
return {
|
||||
"mechanism": "carp",
|
||||
"instance": instance or f"vhid {vhid_text}",
|
||||
"address": normalised,
|
||||
"prefix_length": prefix,
|
||||
"interface": interface,
|
||||
"group_key": f"vhid:{vhid_text}" if vhid_text.isdigit() else None,
|
||||
"running": running,
|
||||
"holds": holds,
|
||||
}
|
||||
|
||||
|
||||
def _interfaces(overview: Any) -> list[Any]:
|
||||
|
||||
Reference in new issue
Block a user