Sync from dev @ 497baf0
Source: main (497baf0) Excluded: live tenant exports, generated artifacts, and dev-only tooling.
This commit is contained in:
77
infra/change-probe/queue_consumer/__init__.py
Normal file
77
infra/change-probe/queue_consumer/__init__.py
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Azure Function queue trigger that calls the Azure DevOps REST API to queue a backup pipeline run."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import azure.functions as func
|
||||
|
||||
|
||||
def _repo_root() -> str:
|
||||
"""Resolve the repository root so we can invoke scripts/trigger_backup_pipeline.py."""
|
||||
env_root = os.environ.get("REPO_ROOT", "").strip()
|
||||
if env_root:
|
||||
return os.path.abspath(env_root)
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
|
||||
def main(msg: func.QueueMessage) -> None:
|
||||
body = msg.get_body().decode("utf-8")
|
||||
logging.info(f"Queue consumer received message: {body}")
|
||||
|
||||
org = os.environ.get("ADO_ORGANIZATION", "").strip()
|
||||
project = os.environ.get("ADO_PROJECT", "").strip()
|
||||
pipeline_id = os.environ.get("ADO_PIPELINE_ID", "").strip()
|
||||
token = os.environ.get("ADO_TOKEN", "").strip()
|
||||
branch = os.environ.get("ADO_BRANCH", "main").strip()
|
||||
|
||||
if not all([org, project, pipeline_id, token]):
|
||||
logging.error("Missing one or more ADO configuration variables (ADO_ORGANIZATION, ADO_PROJECT, ADO_PIPELINE_ID, ADO_TOKEN).")
|
||||
# Re-raising causes the Functions runtime to retry the message after the visibility timeout.
|
||||
raise RuntimeError("Incomplete ADO configuration")
|
||||
|
||||
trigger_script = os.path.join(_repo_root(), "scripts", "trigger_backup_pipeline.py")
|
||||
if not os.path.exists(trigger_script):
|
||||
logging.error(f"Trigger script not found at {trigger_script}")
|
||||
raise RuntimeError("Trigger script missing")
|
||||
|
||||
cmd = [
|
||||
sys.executable,
|
||||
trigger_script,
|
||||
"--organization",
|
||||
org,
|
||||
"--project",
|
||||
project,
|
||||
"--pipeline-id",
|
||||
pipeline_id,
|
||||
"--token",
|
||||
token,
|
||||
"--branch",
|
||||
branch,
|
||||
]
|
||||
|
||||
logging.info(f"Triggering ADO pipeline {pipeline_id} ...")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60,
|
||||
)
|
||||
except subprocess.TimeoutExpired:
|
||||
logging.error("Trigger script timed out after 60 seconds.")
|
||||
raise
|
||||
except Exception as exc:
|
||||
logging.error(f"Failed to run trigger script ({exc}).")
|
||||
raise
|
||||
|
||||
if result.returncode != 0:
|
||||
logging.error(f"Trigger script failed (exit {result.returncode}): {result.stderr}")
|
||||
raise RuntimeError(f"Trigger script failed: {result.stderr}")
|
||||
|
||||
logging.info(f"Trigger script succeeded: {result.stdout.strip()}")
|
||||
12
infra/change-probe/queue_consumer/function.json
Normal file
12
infra/change-probe/queue_consumer/function.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"scriptFile": "__init__.py",
|
||||
"bindings": [
|
||||
{
|
||||
"name": "msg",
|
||||
"type": "queueTrigger",
|
||||
"direction": "in",
|
||||
"queueName": "backup-trigger-queue",
|
||||
"connection": "AzureWebJobsStorage"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user