diff --git a/.github/workflows/nightly-test.yaml b/.github/workflows/nightly-test.yaml index 8a542622b..e8dab660c 100644 --- a/.github/workflows/nightly-test.yaml +++ b/.github/workflows/nightly-test.yaml @@ -45,6 +45,8 @@ jobs: # Test the latest (up to) 6 releases for the flavour # TODO(ben): upgrade nightly to run all flavours TEST_VERSION_UPGRADE_CHANNELS: "recent 6 classic" + # Upgrading from 1.30 is not supported. + TEST_VERSION_UPGRADE_MIN_RELEASE: "1.31" TEST_STRICT_INTERFACE_CHANNELS: "recent 6 strict" run: | export PATH="/home/runner/.local/bin:$PATH" diff --git a/tests/integration/tests/test_util/config.py b/tests/integration/tests/test_util/config.py index 11cb12576..f85021573 100644 --- a/tests/integration/tests/test_util/config.py +++ b/tests/integration/tests/test_util/config.py @@ -119,6 +119,11 @@ VERSION_UPGRADE_CHANNELS = ( os.environ.get("TEST_VERSION_UPGRADE_CHANNELS", "").strip().split() ) + +# The minimum Kubernetes release to upgrade from (e.g. "1.31") +# Only relevant when using 'recent' in VERSION_UPGRADE_CHANNELS. +VERSION_UPGRADE_MIN_RELEASE = os.environ.get("TEST_VERSION_UPGRADE_MIN_RELEASE") + # A list of space-separated channels for which the strict interface tests should be run in sequential order. # Alternatively, use 'recent strict' to get the latest channels for strict. STRICT_INTERFACE_CHANNELS = ( diff --git a/tests/integration/tests/test_util/snap.py b/tests/integration/tests/test_util/snap.py index fe0219fe2..f64c64cb9 100644 --- a/tests/integration/tests/test_util/snap.py +++ b/tests/integration/tests/test_util/snap.py @@ -6,7 +6,9 @@ import re import urllib.error import urllib.request -from typing import List +from typing import List, Optional + +from test_util.util import major_minor LOG = logging.getLogger(__name__) @@ -60,7 +62,11 @@ def filter_arch_and_flavor(channels: List[dict], arch: str, flavor: str) -> List def get_most_stable_channels( - num_of_channels: int, flavor: str, arch: str, include_latest=True + num_of_channels: int, + flavor: str, + arch: str, + include_latest: bool = True, + min_release: Optional[str] = None, ) -> List[str]: """Get an ascending list of latest channels based on the number of channels flavour and architecture.""" @@ -76,6 +82,11 @@ def get_most_stable_channels( for channel, major, minor, risk in arch_flavor_channels: version_key = (int(major), int(minor)) + if min_release is not None: + _min_release = major_minor(min_release) + if _min_release is not None and version_key < _min_release: + continue + if version_key not in channel_map or RISK_LEVELS.index( risk ) < RISK_LEVELS.index(channel_map[version_key][1]): diff --git a/tests/integration/tests/test_util/util.py b/tests/integration/tests/test_util/util.py index cb09b8c6e..352589c48 100644 --- a/tests/integration/tests/test_util/util.py +++ b/tests/integration/tests/test_util/util.py @@ -381,6 +381,21 @@ def tracks_least_risk(track: str, arch: str) -> str: return channel +def major_minor(version: str) -> Optional[tuple]: + """Determine the major and minor version of a Kubernetes version string. + + Args: + version: the version string to determine the major and minor version for + + Returns: + a tuple containing the major and minor version or None if the version string is invalid + """ + if match := TRACK_RE.match(version): + maj, min, _ = match.groups() + return int(maj), int(min) + return None + + def previous_track(snap_version: str) -> str: """Determine the snap track preceding the provided version. @@ -392,12 +407,6 @@ def previous_track(snap_version: str) -> str: """ LOG.debug("Determining previous track for %s", snap_version) - def _maj_min(version: str): - if match := TRACK_RE.match(version): - maj, min, _ = match.groups() - return int(maj), int(min) - return None - if not snap_version: assumed = "latest" LOG.info( @@ -414,20 +423,20 @@ def _maj_min(version: str): ) return assumed - if maj_min := _maj_min(snap_version): + if maj_min := major_minor(snap_version): maj, min = maj_min if min == 0: with urllib.request.urlopen( f"https://dl.k8s.io/release/stable-{maj - 1}.txt" ) as r: stable = r.read().decode().strip() - maj_min = _maj_min(stable) + maj_min = major_minor(stable) else: maj_min = (maj, min - 1) elif snap_version.startswith("latest") or "/" not in snap_version: with urllib.request.urlopen("https://dl.k8s.io/release/stable.txt") as r: stable = r.read().decode().strip() - maj_min = _maj_min(stable) + maj_min = major_minor(stable) flavor_track = {"": "classic", "strict": ""}.get(config.FLAVOR, config.FLAVOR) track = f"{maj_min[0]}.{maj_min[1]}" + (flavor_track and f"-{flavor_track}") diff --git a/tests/integration/tests/test_version_upgrades.py b/tests/integration/tests/test_version_upgrades.py index 6df9171ae..d8798c874 100644 --- a/tests/integration/tests/test_version_upgrades.py +++ b/tests/integration/tests/test_version_upgrades.py @@ -26,7 +26,16 @@ def test_version_upgrades(instances: List[harness.Instance], tmp_path): "'recent' requires the number of releases as second argument and the flavour as third argument" ) _, num_channels, flavour = channels - channels = snap.get_most_stable_channels(int(num_channels), flavour, cp.arch) + channels = snap.get_most_stable_channels( + int(num_channels), + flavour, + cp.arch, + min_release=config.VERSION_UPGRADE_MIN_RELEASE, + ) + if len(channels) < 2: + pytest.fail( + f"Need at least 2 channels to upgrade, got {len(channels)} for flavour {flavour}" + ) current_channel = channels[0] LOG.info(