Récupération des Défaillances CI
Entrée : un numéro de PR ou une requête pour vérifier les défaillances CI. Exigence d'authentification : nécessite l'accès au réseau d'entreprise pour résoudre l'URL de base Jenkins. Sortie : un résumé des tests échoués avec les détails d'erreur, et optionnellement les stdout/stderr complets pour des défaillances spécifiques.
Important : SSL et Authentification
Jenkins nécessite SSL avec vérification de certificat désactivée. Utilisez toujours le contournement de contexte ssl en Python ou les flags -sk dans curl :
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
L'approche curl -s retourne souvent des pages HTML de connexion ; préférez l'approche Python urllib avec contournement SSL.
Phase 0 — Obtenir les Informations de la Dernière Exécution CI
Déterminez d'abord le commit de la dernière exécution CI, le numéro de build et les comptages de passage/défaillance de haut niveau :
source ~/utils/github/set_github_token.sh
PR_NUM=<pr_number>
# Récupère le dernier commentaire du bot CI (contient le numéro de build et le commit)
gh api "repos/NVIDIA/TensorRT-LLM/issues/${PR_NUM}/comments" --paginate --jq \
'[.[] | select(.user.login == "tensorrt-cicd") | select(.body | test("L0_MergeRequest_PR"))] | last | .body'
# Récupère le commit HEAD de la PR et son statut blossom-ci (comptages de passage/défaillance)
HEAD_SHA=$(gh api "repos/NVIDIA/TensorRT-LLM/pulls/${PR_NUM}" --jq '.head.sha')
gh api "repos/NVIDIA/TensorRT-LLM/commits/${HEAD_SHA}/statuses" --jq \
'[.[] | select(.context == "blossom-ci")] | first | {state, description}'
Le champ description affiche les comptages agrégés comme "23969 passed, 1 failed, 8962 skipped".
Phase 1 — Obtenir le Numéro de Build Jenkins
Extrayez le numéro de build L0_MergeRequest_PR du commentaire du bot CI :
BUILD_NUM=$(gh api "repos/NVIDIA/TensorRT-LLM/issues/${PR_NUM}/comments" --paginate --jq \
'[.[] | select(.user.login == "tensorrt-cicd") | select(.body | test("L0_MergeRequest_PR"))] | last | .body' \
| grep -oP 'L0_MergeRequest_PR/\K\d+')
Phase 1.5 — Vérifier les Défaillances de Stage du Pipeline (avant d'explorer les détails des tests)
De nombreuses défaillances CI sont au niveau infrastructure (problèmes de nœud Slurm, arrêts de pipeline, épuisement des ressources) où aucun code de test n'est exécuté du tout. Vérifiez toujours d'abord les stages du pipeline :
import json, ssl, urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
JENKINS_BASE = "https://prod.blsm.nvidia.com/sw-tensorrt-top-1/job/LLM/job/main/job/L0_MergeRequest_PR"
BUILD_NUM = <build_number>
# Obtient l'aperçu des stages du pipeline
url = f"{JENKINS_BASE}/{BUILD_NUM}/wfapi/describe"
resp = urllib.request.urlopen(urllib.request.Request(url), context=ctx, timeout=30)
data = json.loads(resp.read())
print(f"Pipeline status: {data.get('status')}")
for stage in data.get('stages', []):
status = stage.get('status', '')
if status not in ('SUCCESS', 'SKIPPED', 'NOT_EXECUTED'):
name = stage.get('name', '')
print(f" [{status}] {name}")
if 'error' in stage:
print(f" Error: {stage['error']}")
Phase 1.6 — Analyse du Journal de Console (Très Précieuse pour les Défaillances Infrastructure)
Le journal de console Jenkins contient un résumé d'analyse des défaillances CI avec des sections comme ## Recommended Actions et ## Infrastructure Notes. C'est la source la plus précieuse pour comprendre les défaillances infrastructure :
url = f"{JENKINS_BASE}/{BUILD_NUM}/consoleText"
resp = urllib.request.urlopen(urllib.request.Request(url), context=ctx, timeout=30)
text = resp.read().decode('utf-8', errors='replace')
# Extrait les lignes liées aux défaillances de la fin du journal
for line in text[-8000:].split('\n'):
lo = line.lower()
if any(kw in lo for kw in ['fail', 'error', 'abort', 'likely cause',
'recommended action', 'infrastructure',
'no test code', 'stage result']):
print(line.strip()[:300])
Sections clés à rechercher dans le journal de console :
Failing job/Failed stage: quel sous-job et stage Jenkins a échouéLikely cause: analyse automatisée des causes racines (problèmes Slurm, timeouts de pipeline, etc.)No test code was executed: confirme une défaillance infrastructure uniquement (aucun correctif de code nécessaire)Recommended Actions: si re-déclencher CI ou investiguer les changements de code
Phase 2 — Interroger l'API testReport Jenkins pour les Défaillances de Tests
Ne procédez ici que si les phases 1.5/1.6 indiquent des défaillances de tests réelles (pas des problèmes infrastructure) :
url = f"{JENKINS_BASE}/{BUILD_NUM}/testReport/api/json"
resp = urllib.request.urlopen(urllib.request.Request(url), context=ctx, timeout=30)
data = json.loads(resp.read())
print(f'Summary: {data["passCount"]} passed, {data["failCount"]} failed, {data["skipCount"]} skipped')
failed = []
for suite in data.get('suites', []):
for case in suite.get('cases', []):
if case.get('status') in ('FAILED', 'REGRESSION'):
failed.append(case)
if not failed:
print('No test failures in testReport!')
else:
print(f'Failed tests ({len(failed)}):')
for f in failed:
print(f' - {f["className"]}.{f["name"]}')
err = (f.get('errorDetails') or '')[:200]
if err:
print(f' Error: {err}')
Phase 3 — Obtenir stdout/stderr Complets pour une Défaillance de Test Spécifique
Le errorStackTrace peut être incomplet quand les erreurs proviennent de sous-processus. Récupérez stdout et stderr pour le cas de test spécifique afin de trouver la vraie erreur :
for suite in data.get('suites', []):
for case in suite.get('cases', []):
if case.get('status') in ('FAILED', 'REGRESSION'):
name = f'{case["className"]}.{case["name"]}'
if '<search_term>' in name:
print(f'=== {name} ===')
print('--- Error ---')
print(case.get('errorDetails', ''))
print('--- Stack Trace ---')
print(case.get('errorStackTrace', ''))
print('--- Stdout (last 3000 chars) ---')
print((case.get('stdout') or '')[-3000:])
print('--- Stderr (last 3000 chars) ---')
print((case.get('stderr') or '')[-3000:])
break
Champs Disponibles par Cas de Test Échoué (API testReport Jenkins)
className,name: identifiant du teststatus:FAILEDouREGRESSIONerrorDetails: message d'erreurerrorStackTrace: trace de pile complète (peut être incomplète pour les erreurs de sous-processus)stdout,stderr: sortie complète du test (peut être volumineux, vérifiez-les quand la trace de pile est insuffisante)
Motifs de Défaillance Courants
| Motif | Diagnostic | Action |
|---|---|---|
No test code was executed + erreurs Slurm |
Infrastructure : épuisement des ressources du nœud Slurm | Re-déclencher CI |
Stage ABORTED + Downstream job did not succeed |
Défaillance en cascade due à la politique fail-fast | Corriger le stage cause racine, re-déclencher |
newosproc / errno=11 / fork/exec |
Épuisement de la table des processus kernel sur le nœud de connexion | Attendre et re-déclencher |
testReport: 0 failed mais blossom-ci: N failed |
Défaillances au niveau stage, pas au niveau tests | Vérifier Phase 1.5/1.6 |
testReport: N failed avec des noms de tests réels |
Défaillances du code de test réelles | Investiguer les erreurs de test en Phase 3 |
Anti-Motifs
- Ne devinez pas les URL Jenkins ; utilisez toujours la base connue
https://prod.blsm.nvidia.com/sw-tensorrt-top-1/job/LLM/job/main/job/L0_MergeRequest_PR. - N'utilisez pas
curl -spour l'API Jenkins ; cela retourne des pages HTML de connexion. Utilisez Pythonurllibavec contournement SSL. - Ne passez pas directement à testReport (Phase 2) sans vérifier d'abord les stages du pipeline (Phase 1.5) — de nombreuses défaillances sont infrastructure uniquement avec zéro défaillances de tests.
- N'arrêtez pas à
errorStackTraces'il mentionne des défaillances de wrapper génériques commeProcess exited with status 1; vérifiezstdoutetstderrpour la vraie erreur. - Ne récupérez pas tous les cas de test quand vous recherchez une défaillance spécifique ; utilisez le filtre
<search_term>en Phase 3.