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 { environment {
PYENVPIPELINE_VIRTUALENV = '1' PYENVPIPELINE_VIRTUALENV = '1'
GIT_SSH_COMMAND = 'ssh -o StrictHostKeyChecking=accept-new' 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_PROJECT_DIR = '/home/www-mandelstudio/mandelstudio'
STAGING_AUDIT_MANAGE = '/var/lib/virtualenv/mandelstudio/bin/manage.py' STAGING_AUDIT_MANAGE = '/var/lib/virtualenv/mandelstudio/bin/manage.py'
} }

View File

@@ -10,7 +10,7 @@ pipeline {
skipDefaultCheckout(true) skipDefaultCheckout(true)
} }
environment { environment {
STAGING_AUDIT_MINION = 'welkombij.mandelblog.com' STAGING_AUDIT_PROJECT_NAME = 'mandelstudio'
STAGING_AUDIT_PROJECT_DIR = '/home/www-mandelstudio/mandelstudio' STAGING_AUDIT_PROJECT_DIR = '/home/www-mandelstudio/mandelstudio'
STAGING_AUDIT_MANAGE = '/var/lib/virtualenv/mandelstudio/bin/manage.py' 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 ## Jenkins requirements
No dedicated staging SSH credential is required for the multilingual audit stage. 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: 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_PROJECT_DIR=/home/www-mandelstudio/mandelstudio`
- `STAGING_AUDIT_MANAGE=/var/lib/virtualenv/mandelstudio/bin/manage.py` - `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 ## Local rerun
To rerun the same remote audit flow locally: To rerun the same remote audit flow locally:
```bash ```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_PROJECT_DIR='/home/www-mandelstudio/mandelstudio'
export STAGING_AUDIT_MANAGE='/var/lib/virtualenv/mandelstudio/bin/manage.py' export STAGING_AUDIT_MANAGE='/var/lib/virtualenv/mandelstudio/bin/manage.py'
./scripts/run_remote_multilingual_audit.sh ./scripts/run_remote_multilingual_audit.sh

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail 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_PROJECT_DIR:?STAGING_AUDIT_PROJECT_DIR is required}"
: "${STAGING_AUDIT_MANAGE:?STAGING_AUDIT_MANAGE 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" REMOTE_CMD="cd '${STAGING_AUDIT_PROJECT_DIR}' && '${STAGING_AUDIT_MANAGE}' audit_locales --format=json"
set +e 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 json
import os
import subprocess import subprocess
import sys import sys
minion = sys.argv[1] project = os.environ["STAGING_AUDIT_PROJECT_NAME"]
remote_cmd = sys.argv[2] remote_cmd = os.environ["REMOTE_CMD"]
timeout_seconds = int(sys.argv[3]) timeout_seconds = int(os.environ["AUDIT_TIMEOUT_SECONDS"])
cmd = [ cmd = [
"/usr/bin/salt", "--out=json", minion, "sudo", "-n", "-u", "mandel", "-g", "www-data",
"cmd.run_all", remote_cmd, "python_shell=True", "/srv/apps/mandel-dashboard/.venv/bin/python",
"/srv/apps/mandel-dashboard/bin/deploy_stg_from_jenkins.py",
project,
"--command",
remote_cmd,
] ]
try: try:
result = subprocess.run( result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout_seconds, check=False)
cmd,
capture_output=True,
text=True,
timeout=timeout_seconds,
check=False,
)
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
print(json.dumps({ print(json.dumps({
"run_id": None, "error": "audit_failed",
"total_urls_checked": 0, "details": f"Audit command timed out after {timeout_seconds} seconds",
"issues_found": 0, "exit_code": 124,
"summary": {},
"issues": {},
"error": f"Salt multilingual audit timed out after {timeout_seconds} seconds",
}, indent=2)) }, indent=2))
sys.exit(2) sys.exit(2)
stdout = result.stdout.strip()
stderr = result.stderr.strip()
if result.returncode != 0: if result.returncode != 0:
print(json.dumps({ if stdout:
"run_id": None, print(stdout)
"total_urls_checked": 0, else:
"issues_found": 0,
"summary": {},
"issues": {},
"error": f"Salt audit transport failed with exit status {result.returncode}: {(result.stderr or result.stdout).strip()}",
}, 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({ print(json.dumps({
"run_id": None, "error": "audit_failed",
"total_urls_checked": 0, "details": stderr or f"Audit command failed with exit status {result.returncode}",
"issues_found": 0, "exit_code": result.returncode,
"summary": {},
"issues": {},
"error": f"Remote multilingual audit failed with exit status {retcode}: {(stderr or stdout).strip()}",
}, indent=2)) }, 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) sys.exit(2)
print(stdout)
print(json.dumps(audit, indent=2, sort_keys=True))
PY2 PY2
status=$? status=$?
set -e set -e