Skip to content

Models

Inventory Models

inventory

Data models for AVD inventory structures.

This module defines the core data models for representing AVD inventories, including devices, fabrics, and complete inventory structures.

DeviceDefinition dataclass

DeviceDefinition(
    hostname: str,
    platform: str,
    mgmt_ip: Union[str, IPv4Address, IPv6Address],
    device_type: str,
    fabric: str,
    groups: List[str] = list(),
    pod: Optional[str] = None,
    rack: Optional[str] = None,
    mgmt_gateway: Optional[
        Union[str, IPv4Address, IPv6Address]
    ] = None,
    serial_number: Optional[str] = None,
    system_mac_address: Optional[str] = None,
    structured_config: Dict[str, Any] = dict(),
    custom_variables: Dict[str, Any] = dict(),
)

Core device definition data model.

Represents a single network device in the AVD inventory with all its properties and configuration data.

Parameters:

Name Type Description Default
hostname str

Device hostname (must be valid DNS name)

required
platform str

EOS platform type (validated against supported platforms)

required
mgmt_ip Union[IPv4Address, IPv6Address]

Management IP address

required
device_type str

Device role type (validated against supported types)

required
fabric str

Fabric name this device belongs to

required
groups List[str]

List of inventory groups this device belongs to, by default empty list

list()
pod Optional[str]

Pod identifier, by default None

None
rack Optional[str]

Rack identifier, by default None

None
mgmt_gateway Optional[Union[IPv4Address, IPv6Address]]

Management gateway IP, by default None

None
serial_number Optional[str]

Device serial number, by default None

None
system_mac_address Optional[str]

System MAC address, by default None

None
structured_config Dict[str, Any]

AVD structured configuration, by default empty dict

dict()
custom_variables Dict[str, Any]

Custom variables for this device, by default empty dict

dict()

__post_init__

__post_init__() -> None

Validate device definition after initialization.

Source code in avd_cli/models/inventory.py
def __post_init__(self) -> None:
    """Validate device definition after initialization."""
    self._validate_hostname()
    self._validate_platform()
    self._validate_device_type()
    self._normalize_ip_addresses()

FabricDefinition dataclass

FabricDefinition(
    name: str,
    design_type: str,
    devices_by_type: Dict[
        str, List[DeviceDefinition]
    ] = dict(),
    bgp_asn_range: Optional[str] = None,
    mlag_peer_l3_vlan: int = 4093,
    mlag_peer_vlan: int = 4094,
)

Fabric topology definition.

Represents a complete fabric with all its devices organized by type. Uses flexible device dictionary to support any AVD design type.

Parameters:

Name Type Description Default
name str

Fabric name

required
design_type str

Design type (e.g., ‘l3ls-evpn’, ‘mpls’, ‘l2ls’)

required
devices_by_type Dict[str, List[DeviceDefinition]]

Dictionary mapping device type to list of devices, by default empty dict

dict()
bgp_asn_range Optional[str]

BGP ASN range for the fabric, by default None

None
mlag_peer_l3_vlan int

MLAG peer L3 VLAN ID, by default 4093

4093
mlag_peer_vlan int

MLAG peer VLAN ID, by default 4094

4094

border_leaf_devices property

border_leaf_devices: List[DeviceDefinition]

Get border leaf devices (backward compatibility).

Returns:

Type Description
List[DeviceDefinition]

List of border leaf devices

leaf_devices property

leaf_devices: List[DeviceDefinition]

Get leaf devices (backward compatibility).

Returns:

Type Description
List[DeviceDefinition]

List of leaf devices

spine_devices property

spine_devices: List[DeviceDefinition]

Get spine devices (backward compatibility).

Returns:

Type Description
List[DeviceDefinition]

List of spine devices

get_all_devices

get_all_devices() -> List[DeviceDefinition]

Get all devices in fabric across all types.

Returns:

Type Description
List[DeviceDefinition]

Combined list of all devices in the fabric

Source code in avd_cli/models/inventory.py
def get_all_devices(self) -> List[DeviceDefinition]:
    """Get all devices in fabric across all types.

    Returns
    -------
    List[DeviceDefinition]
        Combined list of all devices in the fabric
    """
    all_devices = []
    for device_list in self.devices_by_type.values():
        all_devices.extend(device_list)
    return all_devices

get_devices_by_type

get_devices_by_type(
    device_type: str,
) -> List[DeviceDefinition]

Get devices filtered by type.

Parameters:

Name Type Description Default
device_type str

Device type to filter by

required

Returns:

Type Description
List[DeviceDefinition]

List of devices matching the specified type

Source code in avd_cli/models/inventory.py
def get_devices_by_type(self, device_type: str) -> List[DeviceDefinition]:
    """Get devices filtered by type.

    Parameters
    ----------
    device_type : str
        Device type to filter by

    Returns
    -------
    List[DeviceDefinition]
        List of devices matching the specified type
    """
    return self.devices_by_type.get(device_type, [])

InventoryData dataclass

InventoryData(
    root_path: Path,
    fabrics: List[FabricDefinition] = list(),
    global_vars: Dict[str, Any] = dict(),
    group_vars: Dict[str, Dict[str, Any]] = dict(),
    host_vars: Dict[str, Dict[str, Any]] = dict(),
)

Complete inventory data structure.

Represents the entire AVD inventory with all fabrics and global variables.

Parameters:

Name Type Description Default
root_path Path

Root path to the inventory directory

required
fabrics List[FabricDefinition]

List of fabric definitions, by default empty list

list()
global_vars Dict[str, Any]

Global variables applicable to all devices, by default empty dict

dict()
group_vars Dict[str, Dict[str, Any]]

Group variables (resolved from group_vars/), by default empty dict

dict()
host_vars Dict[str, Dict[str, Any]]

Host variables (resolved from host_vars/), by default empty dict

dict()

filter_devices

filter_devices(
    device_filter: Optional[DeviceFilter],
) -> None

Filter devices in inventory based on patterns.

This method applies device filtering in-place, modifying the inventory to contain only devices that match the filter patterns. Devices are matched by hostname OR group membership (union logic).

Parameters:

Name Type Description Default
device_filter Optional[DeviceFilter]

Filter to apply. If None, no filtering is performed.

required

Raises:

Type Description
ValueError

If no devices match the filter patterns

Examples:

>>> from avd_cli.utils.device_filter import DeviceFilter
>>> filter = DeviceFilter(patterns=["leaf-*"])
>>> inventory.filter_devices(filter)
>>> # inventory now contains only devices matching "leaf-*"
Source code in avd_cli/models/inventory.py
def filter_devices(self, device_filter: Optional["DeviceFilter"]) -> None:  # noqa: F821
    """Filter devices in inventory based on patterns.

    This method applies device filtering in-place, modifying the inventory
    to contain only devices that match the filter patterns. Devices are
    matched by hostname OR group membership (union logic).

    Parameters
    ----------
    device_filter : Optional[DeviceFilter]
        Filter to apply. If None, no filtering is performed.

    Raises
    ------
    ValueError
        If no devices match the filter patterns

    Examples
    --------
    >>> from avd_cli.utils.device_filter import DeviceFilter
    >>> filter = DeviceFilter(patterns=["leaf-*"])
    >>> inventory.filter_devices(filter)
    >>> # inventory now contains only devices matching "leaf-*"
    """
    if device_filter is None:
        return

    # Collect all devices that match the filter
    filtered_devices = []
    for fabric in self.fabrics:
        # Filter each device list in the fabric (modify in-place to avoid read-only error)
        filtered_spines = [
            d for d in fabric.spine_devices
            if device_filter.matches_device(d.hostname, d.groups + [d.fabric])
        ]
        filtered_leaves = [
            d for d in fabric.leaf_devices
            if device_filter.matches_device(d.hostname, d.groups + [d.fabric])
        ]
        filtered_borders = [
            d for d in fabric.border_leaf_devices
            if device_filter.matches_device(d.hostname, d.groups + [d.fabric])
        ]

        # Clear and update lists in-place
        fabric.spine_devices.clear()
        fabric.spine_devices.extend(filtered_spines)
        fabric.leaf_devices.clear()
        fabric.leaf_devices.extend(filtered_leaves)
        fabric.border_leaf_devices.clear()
        fabric.border_leaf_devices.extend(filtered_borders)

        # Collect all filtered devices
        filtered_devices.extend(fabric.get_all_devices())

    # Validate at least one device matched
    if not filtered_devices:
        raise ValueError(
            f"No devices matched the filter patterns: {device_filter.patterns}"
        )

get_all_devices

get_all_devices() -> List[DeviceDefinition]

Get all devices across all fabrics.

Returns:

Type Description
List[DeviceDefinition]

Combined list of all devices from all fabrics

Source code in avd_cli/models/inventory.py
def get_all_devices(self) -> List[DeviceDefinition]:
    """Get all devices across all fabrics.

    Returns
    -------
    List[DeviceDefinition]
        Combined list of all devices from all fabrics
    """
    devices = []
    for fabric in self.fabrics:
        devices.extend(fabric.get_all_devices())
    return devices

get_device_by_hostname

get_device_by_hostname(
    hostname: str,
) -> Optional[DeviceDefinition]

Find device by hostname.

Parameters:

Name Type Description Default
hostname str

Hostname to search for

required

Returns:

Type Description
Optional[DeviceDefinition]

Device if found, None otherwise

Source code in avd_cli/models/inventory.py
def get_device_by_hostname(self, hostname: str) -> Optional[DeviceDefinition]:
    """Find device by hostname.

    Parameters
    ----------
    hostname : str
        Hostname to search for

    Returns
    -------
    Optional[DeviceDefinition]
        Device if found, None otherwise
    """
    for device in self.get_all_devices():
        if device.hostname == hostname:
            return device
    return None

validate

validate(
    skip_topology_validation: bool = False,
) -> List[str]

Validate complete inventory structure.

Checks for common issues like duplicate hostnames, duplicate IPs, etc.

Parameters:

Name Type Description Default
skip_topology_validation bool

Skip topology-specific validations (e.g., spine presence). Useful for cli-config workflow where structured configs are used directly, by default False

False

Returns:

Type Description
List[str]

List of validation error messages (empty if valid)

Source code in avd_cli/models/inventory.py
def validate(self, skip_topology_validation: bool = False) -> List[str]:
    """Validate complete inventory structure.

    Checks for common issues like duplicate hostnames, duplicate IPs, etc.

    Parameters
    ----------
    skip_topology_validation : bool, optional
        Skip topology-specific validations (e.g., spine presence).
        Useful for cli-config workflow where structured configs are used directly,
        by default False

    Returns
    -------
    List[str]
        List of validation error messages (empty if valid)
    """
    errors = []

    # Check for duplicate hostnames
    hostnames = [d.hostname for d in self.get_all_devices()]
    duplicates = [h for h in hostnames if hostnames.count(h) > 1]
    if duplicates:
        errors.append(f"Duplicate hostnames found: {set(duplicates)}")

    # Check for duplicate management IPs
    mgmt_ips = [str(d.mgmt_ip) for d in self.get_all_devices()]
    duplicate_ips = [ip for ip in mgmt_ips if mgmt_ips.count(ip) > 1]
    if duplicate_ips:
        errors.append(f"Duplicate management IPs: {set(duplicate_ips)}")

    # Validate topology only for design types that require specific structure
    if not skip_topology_validation:
        for fabric in self.fabrics:
            # Only validate spine presence for L3LS-EVPN design
            if fabric.design_type == "l3ls-evpn" and not fabric.spine_devices:
                errors.append(f"Fabric {fabric.name} (l3ls-evpn) has no spine devices")

            # For MPLS, validate P or PE routers exist
            if fabric.design_type == "mpls":
                all_devices = fabric.get_all_devices()
                if not all_devices:
                    errors.append(f"Fabric {fabric.name} (mpls) has no devices")

    return errors