mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
validation & construction overhaul
This commit is contained in:
@@ -5,16 +5,16 @@ from ipaddress import IPv4Address
|
||||
from ipaddress import IPv4Network
|
||||
from ipaddress import IPv6Address
|
||||
from ipaddress import IPv6Network
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
# Third Party Imports
|
||||
from pydantic import FilePath
|
||||
from pydantic import IPvAnyNetwork
|
||||
from pydantic import StrictBool
|
||||
from pydantic import StrictStr
|
||||
from pydantic import conint
|
||||
from pydantic import constr
|
||||
from pydantic import root_validator
|
||||
from pydantic import validator
|
||||
|
||||
# Project Imports
|
||||
@@ -22,6 +22,56 @@ from hyperglass.configuration.models._utils import HyperglassModel
|
||||
from hyperglass.configuration.models._utils import HyperglassModelExtra
|
||||
|
||||
|
||||
class AccessList4(HyperglassModel):
|
||||
"""Validation model for IPv4 access-lists."""
|
||||
|
||||
network: IPv4Network = "0.0.0.0/0"
|
||||
action: constr(regex="permit|deny") = "permit"
|
||||
ge: conint(ge=0, le=32) = 0
|
||||
le: conint(ge=0, le=32) = 32
|
||||
|
||||
@validator("ge")
|
||||
def validate_model(cls, value, values):
|
||||
"""Ensure ge is at least the size of the input prefix.
|
||||
|
||||
Arguments:
|
||||
value {int} -- Initial ge value
|
||||
values {dict} -- Other post-validation fields
|
||||
|
||||
Returns:
|
||||
{int} -- Validated ge value
|
||||
"""
|
||||
net_len = values["network"].prefixlen
|
||||
if net_len > value:
|
||||
value = net_len
|
||||
return value
|
||||
|
||||
|
||||
class AccessList6(HyperglassModel):
|
||||
"""Validation model for IPv6 access-lists."""
|
||||
|
||||
network: IPv6Network = "::/0"
|
||||
action: constr(regex=r"permit|deny") = "permit"
|
||||
ge: conint(ge=0, le=128) = 0
|
||||
le: conint(ge=0, le=128) = 128
|
||||
|
||||
@validator("ge")
|
||||
def validate_model(cls, value, values):
|
||||
"""Ensure ge is at least the size of the input prefix.
|
||||
|
||||
Arguments:
|
||||
value {int} -- Initial ge value
|
||||
values {dict} -- Other post-validation fields
|
||||
|
||||
Returns:
|
||||
{int} -- Validated ge value
|
||||
"""
|
||||
net_len = values["network"].prefixlen
|
||||
if net_len > value:
|
||||
value = net_len
|
||||
return value
|
||||
|
||||
|
||||
class InfoConfigParams(HyperglassModelExtra):
|
||||
"""Validation model for per-help params."""
|
||||
|
||||
@@ -46,18 +96,18 @@ class Info(HyperglassModel):
|
||||
traceroute: InfoConfig = InfoConfig()
|
||||
|
||||
|
||||
class DeviceVrf4(HyperglassModel):
|
||||
class DeviceVrf4(HyperglassModelExtra):
|
||||
"""Validation model for IPv4 AFI definitions."""
|
||||
|
||||
vrf_name: StrictStr
|
||||
source_address: IPv4Address
|
||||
access_list: List[AccessList4] = [AccessList4()]
|
||||
|
||||
|
||||
class DeviceVrf6(HyperglassModel):
|
||||
class DeviceVrf6(HyperglassModelExtra):
|
||||
"""Validation model for IPv6 AFI definitions."""
|
||||
|
||||
vrf_name: StrictStr
|
||||
source_address: IPv6Address
|
||||
access_list: List[AccessList6] = [AccessList6()]
|
||||
|
||||
|
||||
class Vrf(HyperglassModel):
|
||||
@@ -68,36 +118,51 @@ class Vrf(HyperglassModel):
|
||||
info: Info = Info()
|
||||
ipv4: Optional[DeviceVrf4]
|
||||
ipv6: Optional[DeviceVrf6]
|
||||
access_list: List[Dict[constr(regex=("allow|deny")), IPvAnyNetwork]] = [
|
||||
{"allow": IPv4Network("0.0.0.0/0")},
|
||||
{"allow": IPv6Network("::/0")},
|
||||
]
|
||||
|
||||
@validator("ipv4", "ipv6", pre=True, always=True)
|
||||
def set_default_vrf_name(cls, value, values):
|
||||
"""If per-AFI name is undefined, set it to the global VRF name.
|
||||
@root_validator
|
||||
def set_dynamic(cls, values):
|
||||
"""Set dynamic attributes before VRF initialization.
|
||||
|
||||
Arguments:
|
||||
values {dict} -- Post-validation VRF attributes
|
||||
|
||||
Returns:
|
||||
{str} -- VRF Name
|
||||
{dict} -- VRF with new attributes set
|
||||
"""
|
||||
if isinstance(value, DefaultVrf) and value.vrf_name is None:
|
||||
value["vrf_name"] = values["name"]
|
||||
elif isinstance(value, Dict) and value.get("vrf_name") is None:
|
||||
value["vrf_name"] = values["name"]
|
||||
return value
|
||||
if values["name"] == "default":
|
||||
protocol4 = "ipv4_default"
|
||||
protocol6 = "ipv6_default"
|
||||
|
||||
@validator("access_list", pre=True)
|
||||
def validate_action(cls, value):
|
||||
"""Transform ACL networks to IPv4Network/IPv6Network objects.
|
||||
else:
|
||||
protocol4 = "ipv4_vpn"
|
||||
protocol6 = "ipv6_vpn"
|
||||
|
||||
if values.get("ipv4") is not None:
|
||||
values["ipv4"].protocol = protocol4
|
||||
values["ipv4"].version = 4
|
||||
|
||||
if values.get("ipv6") is not None:
|
||||
values["ipv6"].protocol = protocol6
|
||||
values["ipv6"].version = 6
|
||||
|
||||
return values
|
||||
|
||||
def __getitem__(self, i):
|
||||
"""Access the VRF's AFI by IP protocol number.
|
||||
|
||||
Arguments:
|
||||
i {int} -- IP Protocol number (4|6)
|
||||
|
||||
Raises:
|
||||
AttributeError: Raised if passed number is not 4 or 6.
|
||||
|
||||
Returns:
|
||||
{object} -- IPv4Network/IPv6Network object
|
||||
{object} -- AFI object
|
||||
"""
|
||||
for li in value:
|
||||
for action, network in li.items():
|
||||
if isinstance(network, (IPv4Network, IPv6Network)):
|
||||
li[action] = str(network)
|
||||
return value
|
||||
if i not in (4, 6):
|
||||
raise AttributeError(f"Must be 4 or 6, got '{i}")
|
||||
|
||||
return getattr(self, f"ipv{i}")
|
||||
|
||||
def __hash__(self):
|
||||
"""Make VRF object hashable so the object can be deduplicated with set().
|
||||
@@ -116,31 +181,30 @@ class Vrf(HyperglassModel):
|
||||
Returns:
|
||||
{bool} -- True if comparison attributes are the same value
|
||||
"""
|
||||
return self.name == other.name
|
||||
result = False
|
||||
if isinstance(other, HyperglassModel):
|
||||
result = self.name == other.name
|
||||
return result
|
||||
|
||||
|
||||
class DefaultVrf(HyperglassModel):
|
||||
"""Validation model for default routing table VRF."""
|
||||
|
||||
name: StrictStr = "default"
|
||||
name: constr(regex="default") = "default"
|
||||
display_name: StrictStr = "Global"
|
||||
info: Info = Info()
|
||||
access_list: List[Dict[constr(regex=("allow|deny")), IPvAnyNetwork]] = [
|
||||
{"allow": IPv4Network("0.0.0.0/0")},
|
||||
{"allow": IPv6Network("::/0")},
|
||||
]
|
||||
|
||||
class DefaultVrf4(HyperglassModel):
|
||||
"""Validation model for IPv4 default routing table VRF definition."""
|
||||
|
||||
vrf_name: StrictStr = "default"
|
||||
source_address: IPv4Address
|
||||
access_list: List[AccessList4] = [AccessList4()]
|
||||
|
||||
class DefaultVrf6(HyperglassModel):
|
||||
"""Validation model for IPv6 default routing table VRF definition."""
|
||||
|
||||
vrf_name: StrictStr = "default"
|
||||
source_address: IPv6Address
|
||||
access_list: List[AccessList6] = [AccessList6()]
|
||||
|
||||
ipv4: Optional[DefaultVrf4]
|
||||
ipv6: Optional[DefaultVrf6]
|
||||
|
||||
Reference in New Issue
Block a user