Use deploy entrypoint for multilingual audit

This commit is contained in:
2026-03-30 00:03:52 +02:00
parent b9d9a7e88e
commit 3f5d5b637b
4 changed files with 30 additions and 66 deletions

2
Jenkinsfile vendored
View File

@@ -9,7 +9,7 @@ pipeline {
environment {
PYENVPIPELINE_VIRTUALENV = '1'
GIT_SSH_COMMAND = 'ssh -o StrictHostKeyChecking=accept-new'
STAGING_AUDIT_MINION = 'welkombij.mandelblog.com'
STAGING_AUDIT_PROJECT_NAME = 'mandelstudio'
STAGING_AUDIT_PROJECT_DIR = '/home/www-mandelstudio/mandelstudio'
STAGING_AUDIT_MANAGE = '/var/lib/virtualenv/mandelstudio/bin/manage.py'
}

View File

@@ -10,7 +10,7 @@ pipeline {
skipDefaultCheckout(true)
}
environment {
STAGING_AUDIT_MINION = 'welkombij.mandelblog.com'
STAGING_AUDIT_PROJECT_NAME = 'mandelstudio'
STAGING_AUDIT_PROJECT_DIR = '/home/www-mandelstudio/mandelstudio'
STAGING_AUDIT_MANAGE = '/var/lib/virtualenv/mandelstudio/bin/manage.py'
}

View File

@@ -58,10 +58,10 @@ This keeps deploys safe without making warning-level cleanup a hard blocker.
## Jenkins requirements
No dedicated staging SSH credential is required for the multilingual audit stage.
The audit runs from the Jenkins built-in node through the same `serverpillar` / Salt transport used by staging deployment.
The audit runs through `/srv/apps/mandel-dashboard/bin/deploy_stg_from_jenkins.py --command`, using the same sudo-whitelisted deployment entrypoint as staging deployment.
Current implementation uses the following environment defaults:
- `STAGING_AUDIT_MINION=welkombij.mandelblog.com`
- `STAGING_AUDIT_PROJECT_NAME=mandelstudio`
- `STAGING_AUDIT_PROJECT_DIR=/home/www-mandelstudio/mandelstudio`
- `STAGING_AUDIT_MANAGE=/var/lib/virtualenv/mandelstudio/bin/manage.py`
@@ -101,7 +101,7 @@ This happens when the remote audit times out or fails, and is intentional so Jen
## Local rerun
To rerun the same remote audit flow locally:
```bash
export STAGING_AUDIT_MINION='welkombij.mandelblog.com'
export STAGING_AUDIT_PROJECT_NAME='mandelstudio'
export STAGING_AUDIT_PROJECT_DIR='/home/www-mandelstudio/mandelstudio'
export STAGING_AUDIT_MANAGE='/var/lib/virtualenv/mandelstudio/bin/manage.py'
./scripts/run_remote_multilingual_audit.sh

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
: "${STAGING_AUDIT_MINION:?STAGING_AUDIT_MINION is required}"
: "${STAGING_AUDIT_PROJECT_NAME:?STAGING_AUDIT_PROJECT_NAME is required}"
: "${STAGING_AUDIT_PROJECT_DIR:?STAGING_AUDIT_PROJECT_DIR is required}"
: "${STAGING_AUDIT_MANAGE:?STAGING_AUDIT_MANAGE is required}"
@@ -15,81 +15,45 @@ trap 'rm -f "$TMP_FILE"' EXIT
REMOTE_CMD="cd '${STAGING_AUDIT_PROJECT_DIR}' && '${STAGING_AUDIT_MANAGE}' audit_locales --format=json"
set +e
sudo -n -u mandel -g www-data /srv/apps/mandel-dashboard/.venv/bin/python - "$STAGING_AUDIT_MINION" "$REMOTE_CMD" "$AUDIT_TIMEOUT_SECONDS" <<'PY2' > "$TMP_FILE"
STAGING_AUDIT_PROJECT_NAME="$STAGING_AUDIT_PROJECT_NAME" REMOTE_CMD="$REMOTE_CMD" AUDIT_TIMEOUT_SECONDS="$AUDIT_TIMEOUT_SECONDS" python3 - <<'PY2' > "$TMP_FILE"
import json
import os
import subprocess
import sys
minion = sys.argv[1]
remote_cmd = sys.argv[2]
timeout_seconds = int(sys.argv[3])
project = os.environ["STAGING_AUDIT_PROJECT_NAME"]
remote_cmd = os.environ["REMOTE_CMD"]
timeout_seconds = int(os.environ["AUDIT_TIMEOUT_SECONDS"])
cmd = [
"/usr/bin/salt", "--out=json", minion,
"cmd.run_all", remote_cmd, "python_shell=True",
"sudo", "-n", "-u", "mandel", "-g", "www-data",
"/srv/apps/mandel-dashboard/.venv/bin/python",
"/srv/apps/mandel-dashboard/bin/deploy_stg_from_jenkins.py",
project,
"--command",
remote_cmd,
]
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout_seconds,
check=False,
)
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout_seconds, check=False)
except subprocess.TimeoutExpired:
print(json.dumps({
"run_id": None,
"total_urls_checked": 0,
"issues_found": 0,
"summary": {},
"issues": {},
"error": f"Salt multilingual audit timed out after {timeout_seconds} seconds",
"error": "audit_failed",
"details": f"Audit command timed out after {timeout_seconds} seconds",
"exit_code": 124,
}, indent=2))
sys.exit(2)
stdout = result.stdout.strip()
stderr = result.stderr.strip()
if result.returncode != 0:
if stdout:
print(stdout)
else:
print(json.dumps({
"run_id": None,
"total_urls_checked": 0,
"issues_found": 0,
"summary": {},
"issues": {},
"error": f"Salt audit transport failed with exit status {result.returncode}: {(result.stderr or result.stdout).strip()}",
"error": "audit_failed",
"details": stderr or f"Audit command failed with exit status {result.returncode}",
"exit_code": result.returncode,
}, indent=2))
sys.exit(2)
try:
payload = json.loads(result.stdout)
if not isinstance(payload, dict) or minion not in payload:
raise ValueError("Missing minion payload")
minion_payload = payload[minion]
if not isinstance(minion_payload, dict):
raise ValueError("Unexpected minion payload type")
retcode = int(minion_payload.get("retcode", 1))
stdout = minion_payload.get("stdout", "")
stderr = minion_payload.get("stderr", "")
if retcode != 0:
print(json.dumps({
"run_id": None,
"total_urls_checked": 0,
"issues_found": 0,
"summary": {},
"issues": {},
"error": f"Remote multilingual audit failed with exit status {retcode}: {(stderr or stdout).strip()}",
}, indent=2))
sys.exit(2)
audit = json.loads(stdout)
except Exception as exc:
print(json.dumps({
"run_id": None,
"total_urls_checked": 0,
"issues_found": 0,
"summary": {},
"issues": {},
"error": f"Unable to parse salt audit response: {exc}",
}, indent=2))
sys.exit(2)
print(json.dumps(audit, indent=2, sort_keys=True))
print(stdout)
PY2
status=$?
set -e