2019-12-29 23:57:39 -07:00
""" Validate VRF configuration variables. """
2019-09-11 01:35:31 -07:00
2020-02-03 02:35:11 -07:00
# Standard Library
from typing import List , Optional
from ipaddress import IPv4Address , IPv4Network , IPv6Address , IPv6Network
2019-09-11 01:35:31 -07:00
2020-02-03 02:35:11 -07:00
# Third Party
from pydantic import (
Field ,
FilePath ,
StrictStr ,
StrictBool ,
conint ,
constr ,
validator ,
root_validator ,
)
2019-09-11 01:35:31 -07:00
2020-02-03 02:35:11 -07:00
# Project
from hyperglass . configuration . models . _utils import HyperglassModel , HyperglassModelExtra
2020-01-17 02:50:57 -07:00
2020-01-31 02:06:27 -10:00
class AccessList4 ( HyperglassModel ) :
""" Validation model for IPv4 access-lists. """
2020-02-01 16:11:01 -10:00
network : IPv4Network = Field (
" 0.0.0.0/0 " ,
title = " Network " ,
description = " IPv4 Network/Prefix that should be permitted or denied. " ,
)
action : constr ( regex = r " permit|deny " ) = Field (
" permit " ,
title = " Action " ,
description = " Permit or deny any networks contained within the prefix. " ,
)
ge : conint ( ge = 0 , le = 32 ) = Field (
0 ,
title = " Greater Than or Equal To " ,
description = " Similar to `ge` in a Cisco prefix-list, the `ge` field defines the **bottom** threshold for prefix size. For example, a value of `24` would result in a query for `192.0.2.0/23` being denied, but a query for `192.0.2.0/32` would be permitted. If this field is set to a value smaller than the `network` field ' s prefix length, this field ' s value will be overwritten to the prefix length of the prefix in the `network` field. " ,
)
le : conint ( ge = 0 , le = 32 ) = Field (
32 ,
title = " Less Than or Equal To " ,
description = " Similar to `le` in a Cisco prefix-list, the `le` field defines the **top** threshold for prefix size. For example, a value of `24` would result in a query for `192.0.2.0/23` being permitted, but a query for `192.0.2.0/32` would be denied. " ,
)
2020-01-31 02:06:27 -10:00
@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. """
2020-02-01 16:11:01 -10:00
network : IPv6Network = Field (
" ::/0 " ,
title = " Network " ,
description = " IPv6 Network/Prefix that should be permitted or denied. " ,
)
action : constr ( regex = r " permit|deny " ) = Field (
" permit " ,
title = " Action " ,
description = " Permit or deny any networks contained within the prefix. " ,
)
ge : conint ( ge = 0 , le = 128 ) = Field (
0 ,
title = " Greater Than or Equal To " ,
description = " Similar to `ge` in a Cisco prefix-list, the `ge` field defines the **bottom** threshold for prefix size. For example, a value of `64` would result in a query for `2001:db8::/48` being denied, but a query for `2001:db8::1/128` would be permitted. If this field is set to a value smaller than the `network` field ' s prefix length, this field ' s value will be overwritten to the prefix length of the prefix in the `network` field. " ,
)
le : conint ( ge = 0 , le = 128 ) = Field (
128 ,
title = " Less Than or Equal To " ,
description = " Similar to `le` in a Cisco prefix-list, the `le` field defines the **top** threshold for prefix size. For example, a value of `64` would result in a query for `2001:db8::/48` being permitted, but a query for `2001:db8::1/128` would be denied. " ,
)
2020-01-31 02:06:27 -10:00
@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
2020-01-17 02:50:57 -07:00
class InfoConfigParams ( HyperglassModelExtra ) :
""" Validation model for per-help params. """
title : Optional [ StrictStr ]
2020-02-01 16:11:01 -10:00
class Config :
""" Pydantic model configuration. """
title = " Help Parameters "
description = " Set dynamic or reusable values which may be used in the help/information content. Params my be access by using Python string formatting syntax, e.g. ` {param_name} `. Any arbitrary values may be added. "
2020-01-17 02:50:57 -07:00
class InfoConfig ( HyperglassModel ) :
""" Validation model for help configuration. """
enable : StrictBool = True
file : Optional [ FilePath ]
params : InfoConfigParams = InfoConfigParams ( )
2019-10-09 03:10:52 -07:00
2020-02-01 16:11:01 -10:00
class Config :
""" Pydantic model configuration. """
fields = {
" enable " : {
" title " : " Enable " ,
" description " : " Enable or disable the display of help/information content for this query type. " ,
} ,
" file " : {
" title " : " File Name " ,
" description " : " Path to a valid text or Markdown file containing custom content. " ,
} ,
}
2019-10-09 03:10:52 -07:00
2020-01-16 02:52:00 -07:00
class Info ( HyperglassModel ) :
2020-01-17 02:50:57 -07:00
""" Validation model for per-VRF, per-Command help. """
2020-01-16 02:52:00 -07:00
2020-01-17 02:50:57 -07:00
bgp_aspath : InfoConfig = InfoConfig ( )
bgp_community : InfoConfig = InfoConfig ( )
bgp_route : InfoConfig = InfoConfig ( )
ping : InfoConfig = InfoConfig ( )
traceroute : InfoConfig = InfoConfig ( )
2020-01-16 02:52:00 -07:00
2020-02-01 16:11:01 -10:00
class Config :
""" Pydantic model configuration. """
title = " VRF Information "
description = " Per-VRF help & information content. "
fields = {
" bgp_aspath " : {
" title " : " BGP AS Path " ,
" description " : " Show information about bgp_aspath queries when selected. " ,
} ,
" bgp_community " : {
" title " : " BGP Community " ,
" description " : " Show information about bgp_community queries when selected. " ,
} ,
" bgp_route " : {
" title " : " BGP Route " ,
" description " : " Show information about bgp_route queries when selected. " ,
} ,
" ping " : {
" title " : " Ping " ,
" description " : " Show information about ping queries when selected. " ,
} ,
" traceroute " : {
" title " : " Traceroute " ,
" description " : " Show information about traceroute queries when selected. " ,
} ,
}
2020-01-16 02:52:00 -07:00
2020-01-31 02:06:27 -10:00
class DeviceVrf4 ( HyperglassModelExtra ) :
2019-12-29 23:57:39 -07:00
""" Validation model for IPv4 AFI definitions. """
2019-10-09 03:10:52 -07:00
source_address : IPv4Address
2020-01-31 02:06:27 -10:00
access_list : List [ AccessList4 ] = [ AccessList4 ( ) ]
2020-03-22 17:46:08 -07:00
force_cidr : StrictBool = False
2019-10-09 03:10:52 -07:00
2020-01-31 02:06:27 -10:00
class DeviceVrf6 ( HyperglassModelExtra ) :
2019-12-29 23:57:39 -07:00
""" Validation model for IPv6 AFI definitions. """
2019-10-09 03:10:52 -07:00
source_address : IPv6Address
2020-01-31 02:06:27 -10:00
access_list : List [ AccessList6 ] = [ AccessList6 ( ) ]
2020-03-22 17:46:08 -07:00
force_cidr : StrictBool = False
2019-10-09 03:10:52 -07:00
2019-10-04 16:54:32 -07:00
class Vrf ( HyperglassModel ) :
2019-12-29 23:57:39 -07:00
""" Validation model for per VRF/afi config in devices.yaml. """
2019-09-11 01:35:31 -07:00
2020-01-16 02:52:00 -07:00
name : StrictStr
display_name : StrictStr
info : Info = Info ( )
2019-12-30 01:44:19 -07:00
ipv4 : Optional [ DeviceVrf4 ]
ipv6 : Optional [ DeviceVrf6 ]
2019-09-30 07:51:17 -07:00
2020-01-31 02:06:27 -10:00
@root_validator
def set_dynamic ( cls , values ) :
""" Set dynamic attributes before VRF initialization.
Arguments :
values { dict } - - Post - validation VRF attributes
2019-12-31 18:29:43 -07:00
Returns :
2020-01-31 02:06:27 -10:00
{ dict } - - VRF with new attributes set
2019-12-31 18:29:43 -07:00
"""
2020-01-31 02:06:27 -10:00
if values [ " name " ] == " default " :
protocol4 = " ipv4_default "
protocol6 = " ipv6_default "
else :
protocol4 = " ipv4_vpn "
protocol6 = " ipv6_vpn "
2019-10-09 03:10:52 -07:00
2020-01-31 02:06:27 -10:00
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
2020-03-19 09:25:57 -07:00
if values . get ( " name " ) == " default " and values . get ( " display_name " ) is None :
values [ " display_name " ] = " Global "
2020-01-31 02:06:27 -10:00
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.
2019-12-31 18:29:43 -07:00
Returns :
2020-01-31 02:06:27 -10:00
{ object } - - AFI object
2019-12-31 18:29:43 -07:00
"""
2020-01-31 02:06:27 -10:00
if i not in ( 4 , 6 ) :
raise AttributeError ( f " Must be 4 or 6, got ' { i } " )
return getattr ( self , f " ipv { i } " )
2019-09-11 01:35:31 -07:00
2020-01-16 02:52:00 -07:00
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
"""
2020-01-31 02:06:27 -10:00
result = False
if isinstance ( other , HyperglassModel ) :
result = self . name == other . name
return result
2020-01-16 02:52:00 -07:00
2020-02-01 16:11:01 -10:00
class Config :
""" Pydantic model configuration. """
title = " VRF "
description = " Per-VRF configuration. "
fields = {
" name " : {
" title " : " Name " ,
" description " : " VRF name as configured on the router/device. " ,
} ,
" display_name " : {
" title " : " Display Name " ,
" description " : " Display name of VRF for use in the hyperglass UI. If none is specified, hyperglass will attempt to generate one. " ,
} ,
}