Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
libvirt-python
requests
peewee
fedora-distro-aliases>=1.5
#guestfs - after it is on pypi ( https://bugzilla.redhat.com/show_bug.cgi?id=1075594 )

# Test suite requirements
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def run(self):
"peewee",
"requests",
"packaging",
"fedora-distro-aliases>=1.5",
],
extras_require={"image_resolve_caching": ["requests_cache>=1.2"]},
)
75 changes: 75 additions & 0 deletions test/test_fedora.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# Copyright 2026, Red Hat, Inc.
# License: GPL-2.0+ <http://spdx.org/licenses/GPL-2.0+>
# See the LICENSE file for more details on Licensing

"""Tests for Fedora version resolution via fedora-distro-aliases."""

from munch import Munch

from testcloud.distro_utils import fedora


def _distro(version, version_number):
return Munch(version=version, version_number=version_number)


def _aliases(development, latest_stable):
return {
"fedora-development": development,
"fedora-latest-stable": latest_stable,
}


class TestResolveFedoraVersion:
"""``_resolve_fedora_version`` normalizes version strings using the
aliases returned by ``fedora-distro-aliases``."""

def test_numeric_rawhide(self):
aliases = _aliases(
development=[_distro("rawhide", "45")],
latest_stable=[_distro("44", "44")],
)
assert fedora._resolve_fedora_version("45", aliases) == "rawhide"

def test_numeric_branched(self):
aliases = _aliases(
development=[_distro("44", "44"), _distro("rawhide", "45")],
latest_stable=[_distro("43", "43")],
)
assert fedora._resolve_fedora_version("44", aliases) == "branched"

def test_latest_resolves_to_stable(self):
aliases = _aliases(
development=[_distro("rawhide", "45")],
latest_stable=[_distro("44", "44")],
)
assert fedora._resolve_fedora_version("latest", aliases) == "44"

def test_branched_falls_back_to_rawhide(self):
aliases = _aliases(
development=[_distro("rawhide", "45")],
latest_stable=[_distro("44", "44")],
)
assert fedora._resolve_fedora_version("branched", aliases) == "rawhide"

def test_rawhide_passthrough(self):
aliases = _aliases(
development=[_distro("rawhide", "45")],
latest_stable=[_distro("44", "44")],
)
assert fedora._resolve_fedora_version("rawhide", aliases) == "rawhide"

def test_numeric_passthrough(self):
aliases = _aliases(
development=[_distro("rawhide", "45")],
latest_stable=[_distro("44", "44")],
)
assert fedora._resolve_fedora_version("43", aliases) == "43"

def test_latest_without_stable(self):
aliases = _aliases(
development=[_distro("rawhide", "45")],
latest_stable=[],
)
assert fedora._resolve_fedora_version("latest", aliases) == "latest"
59 changes: 43 additions & 16 deletions testcloud/distro_utils/fedora.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import re
import requests

from fedora_distro_aliases import get_distro_aliases, Cache

from testcloud import config
from testcloud import exceptions
from testcloud.distro_utils.misc import get_requests_session
Expand All @@ -15,6 +17,43 @@
config_data = config.get_config()


def _get_fedora_aliases():
"""Fetch Fedora release aliases from Bodhi with optional caching."""
cache = None
if config_data.CACHE_IMAGES:
cache = Cache(
path="{}/fedora_distro_aliases_cache.json".format(config_data.DATA_DIR),
ttl=config_data.TRUST_DEADLINE * 60 * 60 * 24,
)
return get_distro_aliases(cache=cache)


def _resolve_fedora_version(version, aliases):
"""
Normalize a Fedora version string against live release data.

Maps numeric versions that match a development release to their alias
(e.g. ``"45"`` -> ``"rawhide"``) and resolves ``"latest"`` to the
current stable release number.
"""
devel = aliases["fedora-development"]
stable = aliases["fedora-latest-stable"]

for distro in devel:
if version == str(distro.version_number):
version = "rawhide" if distro.version == "rawhide" else "branched"
break

if version == "branched" and all(d.version == "rawhide" for d in devel):
log.warning("Branched release currently doesn't exist, using rawhide...")
version = "rawhide"

if version == "latest" and stable:
version = str(stable[0].version_number)

return version


def _process_coreos_url(version: str, arch: str, platform: str) -> str:
"""
Returns an CoreOS url in either qemu or openstack format
Expand Down Expand Up @@ -78,21 +117,12 @@ def get_fedora_image_url(version: str, arch: str) -> str:

# get Fedora Cloud url
try:
oraculum_releases = session.get("https://packager-dashboard.fedoraproject.org/api/v1/releases").json()
except (ConnectionError, IndexError, requests.exceptions.JSONDecodeError):
log.error("Couldn't fetch Fedora releases from oraculum...")
aliases = _get_fedora_aliases()
version = _resolve_fedora_version(version, aliases)
except Exception:
log.error("Couldn't fetch Fedora releases...")
raise exceptions.TestcloudImageError

if oraculum_releases["fedora"]["branched"] and version == str(oraculum_releases["fedora"]["branched"]):
version = "branched"

if not oraculum_releases["fedora"]["branched"] and version == "branched":
log.warning("Branched release currently doesn't exist, using rawhide...")
version = "rawhide"

if version == str(oraculum_releases["fedora"]["rawhide"]):
version = "rawhide"

if version == "qa-matrix":
if arch != "x86_64":
log.error("non-x86_64 architecture is not supported with Fedora qa-matrix.")
Expand Down Expand Up @@ -122,9 +152,6 @@ def get_fedora_image_url(version: str, arch: str) -> str:
raise exceptions.TestcloudImageError
return str(url)

if version == "latest":
version = str(oraculum_releases["fedora"]["stable"])

try:
releases = session.get("https://getfedora.org/releases.json").json()
except (ConnectionError, requests.exceptions.JSONDecodeError):
Expand Down