From 1ac75e1017b97afdeada97db4a2a2ac924237101 Mon Sep 17 00:00:00 2001 From: Mondo Diaz Date: Wed, 21 Jan 2026 23:20:48 +0000 Subject: [PATCH] Fix factory reset and improve reset_stage CI job - Add create_default_admin() call to factory reset (admin user wasn't being created after reset, only on server restart) - Add retry logic to reset_stage CI job (3 attempts with 5s delay) - Use proper context manager for httpx client - Increase timeout to 120s for reset operation - Add retry: 1 at job level for transient failures --- .gitlab-ci.yml | 73 ++++++++++++++++++++++++++----------------- backend/app/routes.py | 4 +++ 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2c03029..73ed57c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -154,6 +154,7 @@ reset_stage: needs: [integration_test_stage] image: deps.global.bsf.tools/docker/python:3.12-slim timeout: 5m + retry: 1 # Retry once on transient failures before_script: - pip install --index-url "$PIP_INDEX_URL" httpx script: @@ -162,10 +163,13 @@ reset_stage: import httpx import sys import os + import time BASE_URL = os.environ.get("STAGE_URL", "") ADMIN_USER = "admin" ADMIN_PASS = "changeme123" # Default admin password + MAX_RETRIES = 3 + RETRY_DELAY = 5 # seconds if not BASE_URL: print("ERROR: STAGE_URL environment variable not set") @@ -173,37 +177,50 @@ reset_stage: print(f"=== Resetting stage environment at {BASE_URL} ===") - client = httpx.Client(base_url=BASE_URL, timeout=60.0) + def do_reset(): + with httpx.Client(base_url=BASE_URL, timeout=120.0) as client: + # Login as admin + print("Logging in as admin...") + login_response = client.post( + "/api/v1/auth/login", + json={"username": ADMIN_USER, "password": ADMIN_PASS}, + ) + if login_response.status_code != 200: + raise Exception(f"Login failed: {login_response.status_code} - {login_response.text}") + print("Login successful") - # Login as admin - print("Logging in as admin...") - login_response = client.post( - "/api/v1/auth/login", - json={"username": ADMIN_USER, "password": ADMIN_PASS}, - ) - if login_response.status_code != 200: - print(f"Login failed: {login_response.status_code} - {login_response.text}") - sys.exit(1) - print("Login successful") + # Call factory reset endpoint + print("Calling factory reset endpoint...") + reset_response = client.post( + "/api/v1/admin/factory-reset", + headers={"X-Confirm-Reset": "yes-delete-all-data"}, + ) - # Call factory reset endpoint - print("Calling factory reset endpoint...") - reset_response = client.post( - "/api/v1/admin/factory-reset", - headers={"X-Confirm-Reset": "yes-delete-all-data"}, - ) + if reset_response.status_code == 200: + result = reset_response.json() + print("Factory reset successful!") + print(f" Database tables dropped: {result['results']['database_tables_dropped']}") + print(f" S3 objects deleted: {result['results']['s3_objects_deleted']}") + print(f" Database reinitialized: {result['results']['database_reinitialized']}") + print(f" Seeded: {result['results']['seeded']}") + return True + else: + raise Exception(f"Factory reset failed: {reset_response.status_code} - {reset_response.text}") - if reset_response.status_code == 200: - result = reset_response.json() - print(f"Factory reset successful!") - print(f" Database tables dropped: {result['results']['database_tables_dropped']}") - print(f" S3 objects deleted: {result['results']['s3_objects_deleted']}") - print(f" Database reinitialized: {result['results']['database_reinitialized']}") - print(f" Seeded: {result['results']['seeded']}") - sys.exit(0) - else: - print(f"Factory reset failed: {reset_response.status_code} - {reset_response.text}") - sys.exit(1) + # Retry loop + for attempt in range(1, MAX_RETRIES + 1): + try: + print(f"Attempt {attempt}/{MAX_RETRIES}") + if do_reset(): + sys.exit(0) + except Exception as e: + print(f"Attempt {attempt} failed: {e}") + if attempt < MAX_RETRIES: + print(f"Retrying in {RETRY_DELAY} seconds...") + time.sleep(RETRY_DELAY) + else: + print("All retry attempts failed") + sys.exit(1) RESET_SCRIPT rules: - if: '$CI_COMMIT_BRANCH == "main"' diff --git a/backend/app/routes.py b/backend/app/routes.py index 5efe674..3f82ae7 100644 --- a/backend/app/routes.py +++ b/backend/app/routes.py @@ -6481,8 +6481,12 @@ def factory_reset( # Step 4: Re-seed with default data (need fresh session after schema recreate) logger.info("Seeding database with defaults...") from .seed import seed_database + from .auth import create_default_admin fresh_db = SessionLocal() try: + # Create default admin user first (normally done at startup) + create_default_admin(fresh_db) + # Then seed other test data seed_database(fresh_db) fresh_db.commit() finally: