1
0
mirror of https://github.com/checktheroads/hyperglass synced 2024-05-11 05:55:08 +00:00
2020-01-31 02:06:27 -10:00

211 lines
5.6 KiB
Python

"""Validate VRF configuration variables."""
# Standard Library Imports
from ipaddress import IPv4Address
from ipaddress import IPv4Network
from ipaddress import IPv6Address
from ipaddress import IPv6Network
from typing import List
from typing import Optional
# Third Party Imports
from pydantic import FilePath
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
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."""
title: Optional[StrictStr]
class InfoConfig(HyperglassModel):
"""Validation model for help configuration."""
enable: StrictBool = True
file: Optional[FilePath]
params: InfoConfigParams = InfoConfigParams()
class Info(HyperglassModel):
"""Validation model for per-VRF, per-Command help."""
bgp_aspath: InfoConfig = InfoConfig()
bgp_community: InfoConfig = InfoConfig()
bgp_route: InfoConfig = InfoConfig()
ping: InfoConfig = InfoConfig()
traceroute: InfoConfig = InfoConfig()
class DeviceVrf4(HyperglassModelExtra):
"""Validation model for IPv4 AFI definitions."""
source_address: IPv4Address
access_list: List[AccessList4] = [AccessList4()]
class DeviceVrf6(HyperglassModelExtra):
"""Validation model for IPv6 AFI definitions."""
source_address: IPv6Address
access_list: List[AccessList6] = [AccessList6()]
class Vrf(HyperglassModel):
"""Validation model for per VRF/afi config in devices.yaml."""
name: StrictStr
display_name: StrictStr
info: Info = Info()
ipv4: Optional[DeviceVrf4]
ipv6: Optional[DeviceVrf6]
@root_validator
def set_dynamic(cls, values):
"""Set dynamic attributes before VRF initialization.
Arguments:
values {dict} -- Post-validation VRF attributes
Returns:
{dict} -- VRF with new attributes set
"""
if values["name"] == "default":
protocol4 = "ipv4_default"
protocol6 = "ipv6_default"
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} -- AFI object
"""
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().
Returns:
{int} -- Hash of VRF name
"""
return hash((self.name,))
def __eq__(self, other):
"""Make VRF object comparable so the object can be deduplicated with set().
Arguments:
other {object} -- Object to compare
Returns:
{bool} -- True if comparison attributes are the same value
"""
result = False
if isinstance(other, HyperglassModel):
result = self.name == other.name
return result
class DefaultVrf(HyperglassModel):
"""Validation model for default routing table VRF."""
name: constr(regex="default") = "default"
display_name: StrictStr = "Global"
info: Info = Info()
class DefaultVrf4(HyperglassModel):
"""Validation model for IPv4 default routing table VRF definition."""
source_address: IPv4Address
access_list: List[AccessList4] = [AccessList4()]
class DefaultVrf6(HyperglassModel):
"""Validation model for IPv6 default routing table VRF definition."""
source_address: IPv6Address
access_list: List[AccessList6] = [AccessList6()]
ipv4: Optional[DefaultVrf4]
ipv6: Optional[DefaultVrf6]