Skip to content

Containerlab

containerlab

Containerlab topology parser for extracting cEOS version information.

This module parses containerlab topology YAML files and extracts the EOS versions used by cEOS nodes, enabling batch download of all required cEOS images.

ContainerlabFile

Bases: BaseModel

Represents a containerlab topology file.

ContainerlabKind

Bases: BaseModel

Represents a kind definition in a containerlab topology.

ContainerlabNode

Bases: BaseModel

Represents a node definition in a containerlab topology.

ContainerlabTopologyData

Bases: BaseModel

Represents the topology section of a containerlab file.

extract_ceos_versions

extract_ceos_versions(topology_file: Path) -> List[str]

Extract deduplicated cEOS versions from a containerlab topology file.

Parameters:

Name Type Description Default
topology_file Path

Path to the containerlab topology YAML file.

required

Returns:

Type Description
List[str]

Sorted list of unique EOS version strings found in cEOS nodes.

Raises:

Type Description
FileNotFoundError

If the topology file does not exist.

YAMLError

If the file contains invalid YAML.

Source code in eos_downloader/logics/containerlab.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
def extract_ceos_versions(topology_file: Path) -> List[str]:
    """Extract deduplicated cEOS versions from a containerlab topology file.

    Parameters
    ----------
    topology_file : Path
        Path to the containerlab topology YAML file.

    Returns
    -------
    List[str]
        Sorted list of unique EOS version strings found in cEOS nodes.

    Raises
    ------
    FileNotFoundError
        If the topology file does not exist.
    yaml.YAMLError
        If the file contains invalid YAML.
    """
    if not topology_file.exists():
        raise FileNotFoundError(f"Topology file not found: {topology_file}")

    with topology_file.open("r", encoding="utf-8") as f:
        data = yaml.safe_load(f)

    if data is None:
        logger.warning(f"Empty topology file: {topology_file}")
        return []

    topology = ContainerlabFile.model_validate(data)

    # Get the default ceos image from kinds if defined
    ceos_kind = topology.topology.kinds.get("ceos")
    default_image = ceos_kind.image if ceos_kind else None

    versions: set[str] = set()

    for node_name, node in topology.topology.nodes.items():
        # Only process ceos nodes
        if node.kind != "ceos":
            continue

        # Resolve image: node-level overrides kind-level
        image = node.image or default_image

        if image is None:
            logger.warning(f"cEOS node '{node_name}' has no resolvable image")
            continue

        version = _parse_version_from_image(image)
        if version is not None:
            versions.add(version)

    return sorted(versions)