Skip to content

capstone.proxmox.iso_downloader

Description: This module is responsible for downloading the latest ISO for Proxmox VE and verifying it hasn't been tampered with using via SHA-256 checksum.

get_iso_folder_path(iso_name)

Get the full path for the Proxmox ISO folder in the ISO directory.

Parameters:

Name Type Description Default
iso_name str

The name of the ISO file.

required

Returns:

Name Type Description
Path Path

The full path to the ISOs folder.

Source code in capstone/proxmox/iso_downloader.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def get_iso_folder_path(iso_name: str) -> Path:
    """Get the full path for the Proxmox ISO folder in the ISO directory.

    Args:
        iso_name (str): The name of the ISO file.

    Returns:
        Path: The full path to the ISOs folder.
    """
    DATA_DIR = (
        Path(__file__).resolve().parents[2] / "data"
        if not IS_TESTING()
        else Path(__file__).resolve().parents[2] / "tests"
    )
    ISO_DIR = DATA_DIR / "isos"

    for iso_dir in [DATA_DIR, ISO_DIR]:
        if not iso_dir.exists():
            iso_dir.mkdir(parents=True, exist_ok=True)

    return ISO_DIR / iso_name

get_latest_proxmox_iso_url(url='https://www.proxmox.com/en/downloads/proxmox-virtual-environment')

Fetches the latest Proxmox VE ISO download URL and its SHA-256 checksum.

Parameters:

Name Type Description Default
url str

The Proxmox downloads page URL. Defaults to the official

'https://www.proxmox.com/en/downloads/proxmox-virtual-environment'

Returns: tuple[str, str]: A tuple containing the ISO download URL and its SHA-256 checksum. This is empty i.e. ("", "") on failure.

Source code in capstone/proxmox/iso_downloader.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
def get_latest_proxmox_iso_url(
    url: str = "https://www.proxmox.com/en/downloads/proxmox-virtual-environment",
) -> tuple[str, str]:
    """Fetches the latest Proxmox VE ISO download URL and its SHA-256 checksum.

    Args:
        url (str, optional): The Proxmox downloads page URL. Defaults to the official
        Proxmox VE downloads page.
    Returns:
        tuple[str, str]: A tuple containing the ISO download URL and its SHA-256 checksum.
        This is empty i.e. ("", "") on failure.
    """

    # Fetch the Proxmox downloads page using requests
    try:
        response = get(url, timeout=10)
        response.raise_for_status()
    except Exception as e:
        LOGGER.error(f"Failed to fetch Proxmox downloads page: {e}")
        return "", ""
    data = response.text

    # parse the HTML to find the latest ISO link
    soup = BeautifulSoup(data, "html.parser")
    latest_downloads = soup.find("ul", class_="latest-downloads")
    second_li = latest_downloads.find_all("li")[1]  # type: ignore
    dl_btns = second_li.find("div", class_="download-entry-buttons")  # type: ignore
    iso_link = dl_btns.find("a", class_="button-primary")  # type: ignore

    # get the SHA-256 checksum
    div_container = second_li.find("div", class_="download-entry-info")  # type: ignore
    div_dl = div_container.find("dl")  # type: ignore
    sha_div = div_dl.find("div", class_="download-entry-shasum")  # type: ignore
    sha_dd = sha_div.find("dd")  # type: ignore
    sha_dd_code = sha_dd.find("code")  # type: ignore

    return iso_link["href"], sha_dd_code.text.strip()  # type: ignore

main()

Main Entry point for the Proxmox ISO downloader module.

Source code in capstone/proxmox/iso_downloader.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
def main():  # pragma: no cover start
    """Main Entry point for the Proxmox ISO downloader module."""
    setup_logging()

    # 1. get the url and hash for the latest iso
    latest_url, latest_sha256 = get_latest_proxmox_iso_url()

    # verify the url and sha are valid
    if not _validate_latest(latest_url, latest_sha256):
        LOGGER.error(
            "Failed to validate the latest Proxmox VE ISO URL or SHA-256 checksum."
        )
        return

    # 2. Check if we need to download the iso or if we already have it
    iso_name = latest_url.split("/")[-1].replace(".iso", "")
    have_to_download = _need_to_download(get_iso_folder_path(iso_name), latest_sha256)

    # 3. Download only if needed
    if not have_to_download:
        LOGGER.info("No download needed.")
        return

    LOGGER.info(f"Please Wait. Downloading Proxmox VE ISO from {latest_url}...")
    iso_file_path = get_iso_folder_path(iso_name) / f"{iso_name}.iso"
    _handle_download(latest_url, iso_file_path)

    # 4. Verify the download
    if verify_sha256(str(iso_file_path), latest_sha256):
        LOGGER.info("Downloaded ISO is valid.")
    else:
        LOGGER.error("Downloaded ISO is invalid, removing file.")
        iso_file_path.unlink()
        return

    LOGGER.info(f"{iso_name} download and verification complete.")

validate_iso_url(url)

Validates the Proxmox VE ISO URL format.

Parameters:

Name Type Description Default
url str

The ISO download URL to validate.

required

Returns:

Name Type Description
bool bool

True if the URL is valid, False otherwise.

Source code in capstone/proxmox/iso_downloader.py
47
48
49
50
51
52
53
54
55
56
57
58
def validate_iso_url(url: str) -> bool:
    """Validates the Proxmox VE ISO URL format.

    Args:
        url (str): The ISO download URL to validate.

    Returns:
        bool: True if the URL is valid, False otherwise.
    """

    pattern = r"^https://enterprise\.proxmox\.com/iso/proxmox-ve_[\d\.]+-.*\.iso$"
    return bool(match(pattern, url))