pa_api.xmlapi.types.config.address
1# Given a list of subnets, 2# Find all NAT rules related to an address in the subnet 3 4from ipaddress import IPv4Network, IPv6Network, ip_network 5from typing import Optional, Union 6 7from pydantic import AliasChoices, AliasPath, Field 8from pydantic.functional_validators import field_validator, model_validator 9from typing_extensions import Self 10 11from pa_api.xmlapi.types.utils import List, String, XMLBaseModel 12 13IPNetwork = Union[IPv4Network, IPv6Network] 14 15 16def get_ip_network(ip_netmask): 17 try: 18 if ip_netmask: 19 return ip_network(ip_netmask, strict=False) 20 except Exception: 21 return None 22 23 24# https://docs.pydantic.dev/latest/concepts/alias/#aliaspath-and-aliaschoices 25class Address(XMLBaseModel): 26 name: str = Field(validation_alias="@name") 27 type: Optional[str] = None 28 prefix: Optional[str] = None 29 ip_netmask: Optional[str] = Field( 30 alias="ip-netmask", 31 validation_alias=AliasChoices( 32 AliasPath("ip-netmask", "#text"), 33 "ip-netmask", 34 ), 35 default=None, 36 ) 37 ip_network: Optional[IPNetwork] = None 38 ip_range: Optional[str] = Field(alias="ip-range", default=None) 39 fqdn: Optional[String] = None 40 tags: List[String] = Field( 41 validation_alias=AliasPath("tag", "member"), default=None 42 ) 43 44 @field_validator("tags", mode="before") 45 @classmethod 46 def validate_tags(cls, v) -> List[str]: 47 if not v: 48 return [] 49 if not isinstance(v, list): 50 return [v] 51 return v 52 53 @model_validator(mode="after") 54 def validate_ip_network(self) -> Self: 55 if self.ip_network is None: 56 self.ip_network = get_ip_network(self.ip_netmask) 57 if not isinstance(self.ip_network, (IPv4Network, IPv6Network)): 58 self.ip_network = None 59 return self 60 61 @model_validator(mode="after") 62 def validate_type(self) -> Self: 63 address_type = None 64 if self.prefix: 65 address_type = "prefix" 66 elif self.ip_netmask: 67 address_type = "ip-netmask" 68 elif self.ip_range: 69 address_type = "ip-range" 70 elif self.fqdn: 71 address_type = "fqdn" 72 self.type = address_type 73 return self 74 75 76def find_addresses(tree): 77 # addresses_xml = tree.xpath(".//address/entry") 78 addresses_xml = tree.xpath("./devices/entry/device-group//address/entry") 79 address_objects = [Address.from_xml(n) for n in addresses_xml] 80 81 addresses = [] 82 subnets = [] 83 for a in address_objects: 84 network = a.ip_network 85 # We do not consider ip ranges for now 86 if not network: 87 continue 88 if network.prefixlen == network.max_prefixlen: 89 addresses.append(a) 90 else: 91 subnets.append(a) 92 return addresses, subnets
IPNetwork =
typing.Union[ipaddress.IPv4Network, ipaddress.IPv6Network]
def
get_ip_network(ip_netmask):
26class Address(XMLBaseModel): 27 name: str = Field(validation_alias="@name") 28 type: Optional[str] = None 29 prefix: Optional[str] = None 30 ip_netmask: Optional[str] = Field( 31 alias="ip-netmask", 32 validation_alias=AliasChoices( 33 AliasPath("ip-netmask", "#text"), 34 "ip-netmask", 35 ), 36 default=None, 37 ) 38 ip_network: Optional[IPNetwork] = None 39 ip_range: Optional[str] = Field(alias="ip-range", default=None) 40 fqdn: Optional[String] = None 41 tags: List[String] = Field( 42 validation_alias=AliasPath("tag", "member"), default=None 43 ) 44 45 @field_validator("tags", mode="before") 46 @classmethod 47 def validate_tags(cls, v) -> List[str]: 48 if not v: 49 return [] 50 if not isinstance(v, list): 51 return [v] 52 return v 53 54 @model_validator(mode="after") 55 def validate_ip_network(self) -> Self: 56 if self.ip_network is None: 57 self.ip_network = get_ip_network(self.ip_netmask) 58 if not isinstance(self.ip_network, (IPv4Network, IPv6Network)): 59 self.ip_network = None 60 return self 61 62 @model_validator(mode="after") 63 def validate_type(self) -> Self: 64 address_type = None 65 if self.prefix: 66 address_type = "prefix" 67 elif self.ip_netmask: 68 address_type = "ip-netmask" 69 elif self.ip_range: 70 address_type = "ip-range" 71 elif self.fqdn: 72 address_type = "fqdn" 73 self.type = address_type 74 return self
Usage docs: https://docs.pydantic.dev/2.9/concepts/models/
A base class for creating Pydantic models.
Attributes:
__class_vars__: The names of the class variables defined on the model.
__private_attributes__: Metadata about the private attributes of the model.
__signature__: The synthesized __init__
[Signature
][inspect.Signature] of the model.
__pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
__pydantic_core_schema__: The core schema of the model.
__pydantic_custom_init__: Whether the model has a custom `__init__` function.
__pydantic_decorators__: Metadata containing the decorators defined on the model.
This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
__pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to
__args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
__pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
__pydantic_post_init__: The name of the post-init method for the model, if defined.
__pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
__pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
__pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.
__pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
is set to `'allow'`.
__pydantic_fields_set__: The names of fields explicitly set during instantiation.
__pydantic_private__: Values of private attributes set on the model instance.
fqdn: Optional[Annotated[str, BeforeValidator(func=<function ensure_str at 0x7f0db0c89bd0>, json_schema_input_type=PydanticUndefined)]]
@model_validator(mode='after')
def
validate_type(self) -> typing_extensions.Self:
62 @model_validator(mode="after") 63 def validate_type(self) -> Self: 64 address_type = None 65 if self.prefix: 66 address_type = "prefix" 67 elif self.ip_netmask: 68 address_type = "ip-netmask" 69 elif self.ip_range: 70 address_type = "ip-range" 71 elif self.fqdn: 72 address_type = "fqdn" 73 self.type = address_type 74 return self
model_config: ClassVar[pydantic.config.ConfigDict] =
{}
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
model_fields: ClassVar[Dict[str, pydantic.fields.FieldInfo]] =
{'name': FieldInfo(annotation=str, required=True, alias_priority=2, validation_alias='@name'), 'type': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'prefix': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'ip_netmask': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias='ip-netmask', alias_priority=2, validation_alias=AliasChoices(choices=[AliasPath(path=['ip-netmask', '#text']), 'ip-netmask'])), 'ip_network': FieldInfo(annotation=Union[IPv4Network, IPv6Network, NoneType], required=False, default=None), 'ip_range': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias='ip-range', alias_priority=2), 'fqdn': FieldInfo(annotation=Union[Annotated[str, BeforeValidator], NoneType], required=False, default=None), 'tags': FieldInfo(annotation=List[Annotated[str, BeforeValidator]], required=False, default=None, alias_priority=2, validation_alias=AliasPath(path=['tag', 'member']), metadata=[BeforeValidator(func=<function ensure_list>, json_schema_input_type=PydanticUndefined)])}
Metadata about the fields defined on the model,
mapping of field names to [FieldInfo
][pydantic.fields.FieldInfo] objects.
This replaces Model.__fields__
from Pydantic V1.
model_computed_fields: ClassVar[Dict[str, pydantic.fields.ComputedFieldInfo]] =
{}
A dictionary of computed field names and their corresponding ComputedFieldInfo
objects.
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- dict
- json
- parse_obj
- parse_raw
- parse_file
- from_orm
- construct
- copy
- schema
- schema_json
- validate
- update_forward_refs
def
find_addresses(tree):
77def find_addresses(tree): 78 # addresses_xml = tree.xpath(".//address/entry") 79 addresses_xml = tree.xpath("./devices/entry/device-group//address/entry") 80 address_objects = [Address.from_xml(n) for n in addresses_xml] 81 82 addresses = [] 83 subnets = [] 84 for a in address_objects: 85 network = a.ip_network 86 # We do not consider ip ranges for now 87 if not network: 88 continue 89 if network.prefixlen == network.max_prefixlen: 90 addresses.append(a) 91 else: 92 subnets.append(a) 93 return addresses, subnets