Merge pull request 'Restore MinIO for LaSuite upgrade baselines' (#47) from fix/lasuite-base-minio into main
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing

Merge LaSuite baseline image and convergence repairs
This commit was merged in pull request #47.
This commit is contained in:
2026-10-26 17:46:39 +00:00
8 changed files with 105 additions and 2 deletions
+8 -2
View File
@@ -93,9 +93,15 @@ def assert_serving(domain: str, meta) -> None:
Steps 1–2 are BOUNDED POLLS (no bare sleep), so a state-mutating op (upgrade/restore) that leaves
the app briefly reconverging settles, while a persistent failure still fails within the timeout."""
deadline = time.time() + meta.DEPLOY_TIMEOUT
while time.time() < deadline and not lifecycle.services_converged(domain):
converged = False
while time.time() < deadline:
# Keep both observations inside the retry budget: a service may restart
# between the initial convergence sample and its confirmation.
if lifecycle.services_converged(domain) and lifecycle.services_converged(domain):
converged = True
break
time.sleep(5)
assert lifecycle.services_converged(domain), f"{domain}: services did not converge"
assert converged, f"{domain}: services did not converge"
path = meta.HEALTH_PATH
ok = tuple(meta.HEALTH_OK)
+4
View File
@@ -487,6 +487,10 @@ def deploy_app(
# may already include the environmental compose.ccci.yml). Stripped before the head redeploy
# (generic.perform_upgrade) so the PR head runs unmodified.
if apply_previous:
# This untracked overlay also trips abra's pinned-deploy clean-tree gate.
# The exact version was checked out above; chaos deploys that base plus
# its repair, just as for compose.ccci.yml, without fetching latest.
chaos = True
cf = compose_file_add(extra.get("COMPOSE_FILE", "compose.yml"), PREVIOUS_COMPOSE)
abra.env_set(domain, "COMPOSE_FILE", cf)
provide_previous_overlay(recipe)
+1
View File
@@ -0,0 +1 @@
0.4.0+v5.4.1
@@ -0,0 +1,14 @@
# The published base points at the removed docker.io/minio/minio image.
# Keep its /data layout, credentials and bucket initialization; run the same
# available MinIO build used by current recipes without Bitnami's wrapper.
services:
minio:
image: docker.io/bitnamilegacy/minio:2025.7.23-debian-12-r5@sha256:6dabb4a2088c9a79908de3bc05f4586c23ad2182c8908e7e3acbf61c1467fb20
user: "0:0"
environment:
MC_CONFIG_DIR: /tmp/mc-base-init
entrypoint:
- /bin/sh
- -c
- /minio-initialize.sh & exec "$$@"
- --
+1
View File
@@ -0,0 +1 @@
0.12.0+v0.21.0
@@ -0,0 +1,14 @@
# The published base points at the removed docker.io/minio/minio image.
# Keep its /data layout, credentials and bucket initialization; run the same
# available MinIO build used by current recipes without Bitnami's wrapper.
services:
minio:
image: docker.io/bitnamilegacy/minio:2025.7.23-debian-12-r5@sha256:6dabb4a2088c9a79908de3bc05f4586c23ad2182c8908e7e3acbf61c1467fb20
user: "0:0"
environment:
MC_CONFIG_DIR: /tmp/mc-base-init
entrypoint:
- /bin/sh
- -c
- /minio-initialize.sh & exec "$$@"
- --
+34
View File
@@ -116,3 +116,37 @@ def test_previous_status_stale_without_marker(monkeypatch):
monkeypatch.setattr(lifecycle, "previous_target_version", lambda r: None)
st = lifecycle.previous_status("rx", "version", "0.7.0+3.3.1")
assert st["apply"] is False and st["stale"] is True and "marker" in st["reason"]
def test_previous_overlay_deploys_checked_out_base_without_clean_tree_gate(monkeypatch):
events = []
for name in (
"acquire_app_lock",
"provide_ccci_overlay",
"provide_previous_overlay",
"prepull_images",
):
monkeypatch.setattr(lifecycle, name, lambda *a, **kw: None)
for name in ("app_config_remove", "app_new", "env_set", "secret_generate"):
monkeypatch.setattr(lifecycle.abra, name, lambda *a, **kw: None)
monkeypatch.setattr(lifecycle.meta_mod, "extra_env", lambda *a: {})
monkeypatch.setattr(lifecycle.meta_mod, "hook_ctx", lambda *a: None)
monkeypatch.setattr(lifecycle.abra, "has_lightweight_version_tags", lambda r: False)
monkeypatch.setattr(lifecycle, "has_ccci_overlay", lambda r: False)
monkeypatch.setattr(
lifecycle.abra, "recipe_checkout", lambda r, v: events.append(("checkout", v))
)
monkeypatch.setattr(
lifecycle.abra, "deploy", lambda d, **kw: events.append(("deploy", kw["chaos"]))
)
for apply_previous in (False, True):
events.clear()
lifecycle.deploy_app(
"example",
"example.invalid",
version="1.0.0",
apply_previous=apply_previous,
meta=object(),
_count_deploy=False,
)
assert events == [("checkout", "1.0.0"), ("deploy", apply_previous)]
+29
View File
@@ -0,0 +1,29 @@
"""Convergence confirmation must retry a transient second-sample failure."""
from types import SimpleNamespace
import pytest
from harness import generic
def _setup(monkeypatch, samples):
clock = [0]
monkeypatch.setattr(generic.time, "time", lambda: clock[0])
monkeypatch.setattr(generic.time, "sleep", lambda n: clock.__setitem__(0, clock[0] + n))
monkeypatch.setattr(generic.lifecycle, "services_converged", lambda d: next(samples))
monkeypatch.setattr(generic.lifecycle, "http_fetch", lambda *a: (200, "application"))
monkeypatch.setattr(generic, "served_cert", lambda d: (True, "*.ci.autonomic.zone"))
return SimpleNamespace(DEPLOY_TIMEOUT=20, HTTP_TIMEOUT=20, HEALTH_PATH="/", HEALTH_OK=(200,))
def test_confirmation_failure_retries_until_services_settle(monkeypatch):
meta = _setup(monkeypatch, iter([True, False, True, True]))
generic.assert_serving("example.ci.autonomic.zone", meta)
def test_persistent_confirmation_failure_still_fails(monkeypatch):
import itertools
meta = _setup(monkeypatch, itertools.cycle([True, False]))
with pytest.raises(AssertionError, match="services did not converge"):
generic.assert_serving("example.ci.autonomic.zone", meta)