Files
serv_benchmark/03_api_backend.md
2025-12-07 13:52:48 +01:00

12 KiB
Raw Blame History

03 Spécification API Backend (FastAPI)

Objectif : définir précisément les endpoints backend, les schémas JSON échangés et les règles métier associées.

LAPI sera exposée sous /api.


1. Contenu attendu de ce fichier

Ce document doit servir de référence au développeur backend. Il décrit :

  1. Le format du payload JSON envoyé par le script de benchmark (bench.sh) vers le backend.
  2. Les endpoints REST nécessaires :
    • Réception dun benchmark.
    • Consultation des devices.
    • Consultation de lhistorique des benchmarks.
    • Gestion des liens constructeur.
    • Gestion des documents (PDF, images).
  3. Les règles dauthentification (token simple).
  4. Les codes derreur principaux et attentes de validation.

2. Schéma JSON payload dun benchmark

Endpoint cible : POST /api/benchmark

Le script client envoie un JSON de la forme :

{
  "device_identifier": "elitedesk-800g3",
  "bench_script_version": "1.0.0",
  "hardware": {
    "cpu": {
      "vendor": "Intel",
      "model": "Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz",
      "microarchitecture": "Skylake",
      "cores": 4,
      "threads": 8,
      "base_freq_ghz": 3.4,
      "max_freq_ghz": 4.0,
      "cache_l1_kb": 256,
      "cache_l2_kb": 1024,
      "cache_l3_kb": 8192,
      "flags": ["avx", "avx2", "aes"],
      "tdp_w": 65
    },
    "ram": {
      "total_mb": 65536,
      "slots_total": 4,
      "slots_used": 4,
      "ecc": false,
      "layout": [
        {
          "slot": "DIMM_A1",
          "size_mb": 16384,
          "type": "DDR4",
          "speed_mhz": 2133,
          "vendor": "Corsair",
          "part_number": "XYZ"
        }
      ]
    },
    "gpu": {
      "vendor": "Intel",
      "model": "Intel HD Graphics 530",
      "driver_version": "xxx",
      "memory_dedicated_mb": null,
      "memory_shared_mb": 512,
      "api_support": ["OpenGL 4.5"]
    },
    "storage": {
      "devices": [
        {
          "name": "/dev/nvme0n1",
          "type": "NVMe",
          "interface": "PCIe 3.0 x4",
          "capacity_gb": 1000,
          "vendor": "Samsung",
          "model": "970 EVO Plus",
          "smart_health": "PASSED",
          "temperature_c": 42
        }
      ],
      "partitions": [
        {
          "name": "/dev/nvme0n1p1",
          "mount_point": "/",
          "fs_type": "ext4",
          "used_gb": 50,
          "total_gb": 100
        }
      ]
    },
    "network": {
      "interfaces": [
        {
          "name": "eth0",
          "type": "ethernet",
          "mac": "aa:bb:cc:dd:ee:ff",
          "ip": "10.0.0.10",
          "speed_mbps": 1000,
          "driver": "e1000e"
        }
      ]
    },
    "motherboard": {
      "vendor": "HP",
      "model": "HP 8054",
      "bios_version": "P01 Ver. 02.48",
      "bios_date": "2023-05-10"
    },
    "os": {
      "name": "Debian",
      "version": "12 (bookworm)",
      "kernel_version": "6.1.0-xx-amd64",
      "architecture": "x86_64",
      "virtualization_type": "none"
    },
    "sensors": {
      "cpu_temp_c": 45,
      "disk_temps_c": {
        "/dev/nvme0n1": 42
      }
    },
    "raw_info": {
      "lscpu": "raw text…",
      "lsblk": "raw text…"
    }
  },
  "results": {
    "cpu": {
      "events_per_sec": 12000,
      "duration_s": 10,
      "score": 90
    },
    "memory": {
      "throughput_mib_s": 20000,
      "score": 95
    },
    "disk": {
      "read_mb_s": 1200,
      "write_mb_s": 1000,
      "iops_read": 50000,
      "iops_write": 45000,
      "latency_ms": 1.2,
      "score": 94
    },
    "network": {
      "upload_mbps": 930,
      "download_mbps": 940,
      "ping_ms": 1.2,
      "jitter_ms": 0.3,
      "packet_loss_percent": 0.0,
      "score": 88
    },
    "gpu": {
      "glmark2_score": null,
      "score": null
    },
    "global_score": 92
  }
}

Remarques importantes :

  • Certains champs peuvent être null ou absents en fonction de la machine (ex: pas de GPU dédié).
  • Le backend doit être robuste à labsence de certains blocs (ex: pas de network si aucun test réseau).

3. Logique de traitement côté backend

  1. Auth

    • Lecture du header Authorization: Bearer <TOKEN>.
    • Comparaison avec une valeur stockée dans la config/ENV (API_TOKEN).
    • Si token invalide ou absent : réponse 401.
  2. Résolution du device

    • Chercher un enregistrement devices avec hostname == device_identifier.
    • Si trouvé :
      • Utiliser device_id existant.
    • Sinon :
      • Créer un nouveau device minimal avec :
        • hostname = device_identifier
        • created_at, updated_at = maintenant.
  3. Création dun hardware_snapshot

    • Mapper le contenu hardware vers la table hardware_snapshots telle que définie dans 02_model_donnees.md.
    • Exemples :
      • hardware.cpu.vendor -> cpu_vendor
      • hardware.ram.total_mb -> ram_total_mb
      • hardware.storage.devices -> JSON dans storage_devices_json
      • etc.
    • captured_at = now() (ou run_at du benchmark si fourni).
  4. Création dun benchmark

    • run_at = now() (ou fourni explicitement plus tard).
    • bench_script_version = champ du payload.
    • Scores :
      • cpu_score = results.cpu.score (si présent).
      • memory_score = results.memory.score
      • disk_score = results.disk.score
      • network_score = results.network.score
      • gpu_score = results.gpu.score
      • global_score = results.global_score
    • details_json = JSON complet de results (ou éventuellement de results + métriques brutes).
  5. Réponse

    • En cas de succès, renvoyer :
      {
        "status": "ok",
        "device_id": 1,
        "benchmark_id": 42
      }
      

4. Endpoints détaillés

4.1. POST /api/benchmark

  • Rôle : point dentrée unique des résultats du script client.
  • Auth : header Authorization: Bearer <TOKEN>.
  • Body : JSON (voir schéma ci-dessus).
  • Codes de réponse :
    • 200 succès.
    • 400 JSON invalide / validation Pydantic échouée.
    • 401 token invalide ou manquant.
    • 500 erreur interne.

4.2. GET /api/devices

Objectif : lister les devices avec un résumé de leur dernier benchmark.

Paramètres query :

  • page (int, optionnel, défaut 1)
  • page_size (int, optionnel, défaut 20)
  • search (string, optionnel filtre sur hostname/description/tags)

Réponse (exemple simplifié) :

{
  "items": [
    {
      "id": 1,
      "hostname": "elitedesk-800g3",
      "description": "HP EliteDesk 800 G3 SFF",
      "location": "Bureau",
      "tags": ["lab", "dev"],
      "last_benchmark": {
        "id": 42,
        "run_at": "2025-12-07T10:32:00Z",
        "global_score": 92,
        "cpu_score": 90,
        "memory_score": 95,
        "disk_score": 94,
        "network_score": 88,
        "gpu_score": null
      }
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}

4.3. GET /api/devices/{device_id}

Objectif : récupérer le détail dun device.

Réponse (exemple) :

{
  "id": 1,
  "hostname": "elitedesk-800g3",
  "fqdn": "elitedesk-800g3.maison43",
  "description": "HP EliteDesk 800 G3 SFF (serveur dev)",
  "asset_tag": "LAB-001",
  "location": "Bureau",
  "owner": "Gilles",
  "tags": ["lab", "proxmox"],
  "created_at": "2025-12-01T10:00:00Z",
  "updated_at": "2025-12-07T10:32:00Z",
  "last_hardware_snapshot": {
    "captured_at": "2025-12-07T10:32:00Z",
    "cpu_vendor": "Intel",
    "cpu_model": "Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz",
    "cpu_cores": 4,
    "cpu_threads": 8,
    "ram_total_mb": 65536,
    "storage_summary": "NVMe 1TB + HDD 2TB",
    "gpu_summary": "Intel HD Graphics 530",
    "os_name": "Debian",
    "os_version": "12 (bookworm)",
    "kernel_version": "6.1.0-xx-amd64"
  },
  "last_benchmark": {
    "id": 42,
    "run_at": "2025-12-07T10:32:00Z",
    "global_score": 92,
    "cpu_score": 90,
    "memory_score": 95,
    "disk_score": 94,
    "network_score": 88,
    "gpu_score": null
  }
}

4.4. GET /api/devices/{device_id}/benchmarks

Objectif : récupérer lhistorique de benchmarks dun device.

Paramètres :

  • limit (int, défaut 20)
  • offset (int, défaut 0)

Réponse :

{
  "items": [
    {
      "id": 42,
      "run_at": "2025-12-07T10:32:00Z",
      "global_score": 92,
      "cpu_score": 90,
      "memory_score": 95,
      "disk_score": 94,
      "network_score": 88,
      "gpu_score": null
    },
    {
      "id": 35,
      "run_at": "2025-12-05T09:10:00Z",
      "global_score": 89,
      "cpu_score": 88,
      "memory_score": 92,
      "disk_score": 90,
      "network_score": 85,
      "gpu_score": null
    }
  ],
  "total": 2,
  "limit": 20,
  "offset": 0
}

4.5. GET /api/benchmarks/{benchmark_id}

Objectif : récupérer les détails complets dun benchmark.

Réponse :

{
  "id": 42,
  "device_id": 1,
  "hardware_snapshot_id": 10,
  "run_at": "2025-12-07T10:32:00Z",
  "bench_script_version": "1.0.0",
  "global_score": 92,
  "cpu_score": 90,
  "memory_score": 95,
  "disk_score": 94,
  "network_score": 88,
  "gpu_score": null,
  "details": {
    "cpu": {
      "events_per_sec": 12000,
      "duration_s": 10,
      "score": 90
    },
    "memory": {
      "throughput_mib_s": 20000,
      "score": 95
    },
    "disk": {
      "read_mb_s": 1200,
      "write_mb_s": 1000,
      "iops_read": 50000,
      "iops_write": 45000,
      "latency_ms": 1.2,
      "score": 94
    },
    "network": {
      "upload_mbps": 930,
      "download_mbps": 940,
      "ping_ms": 1.2,
      "jitter_ms": 0.3,
      "packet_loss_percent": 0,
      "score": 88
    },
    "gpu": {
      "glmark2_score": null,
      "score": null
    },
    "global_score": 92
  }
}

Note : details reflète details_json de la base.


4.6. Liens constructeur

Réponse :

[
  {
    "id": 1,
    "label": "Support HP",
    "url": "https://support.hp.com/..."
  },
  {
    "id": 2,
    "label": "Page produit",
    "url": "https://www.hp.com/..."
  }
]

POST /api/devices/{device_id}/links

Body :

{
  "label": "Support HP",
  "url": "https://support.hp.com/..."
}

Réponse : lobjet créé avec id.

PUT /api/links/{id}

Body idem POST (label + url).

DELETE /api/links/{id}

  • Réponse : 204 No Content en cas de succès.

4.7. Documents

GET /api/devices/{device_id}/docs

Réponse :

[
  {
    "id": 1,
    "doc_type": "manual",
    "filename": "manual_elitedesk.pdf",
    "mime_type": "application/pdf",
    "size_bytes": 3456789,
    "uploaded_at": "2025-05-01T10:00:00Z"
  }
]

POST /api/devices/{device_id}/docs

  • Type : multipart/form-data
  • Champs :
    • file (fichier binaire)
    • doc_type (string)

Réponse : métadonnées du document créé.

GET /api/docs/{doc_id}/download

  • Sert le fichier binaire avec le bon Content-Type.

5. Authentification

MVP : token simple.

  • Variable denv API_TOKEN côté backend.
  • Chaque requête POST /api/benchmark doit inclure :
Authorization: Bearer <API_TOKEN>
  • Les endpoints de lecture (GET) peuvent être :
    • soit publics sur le LAN,
    • soit protégés par un autre mécanisme (reverse proxy) hors scope de cette spec.

6. Gestion des erreurs et validations

  • Utiliser des modèles Pydantic pour :
    • valider la structure de hardware et results autant que possible sans être bloquant.
    • autoriser des champs optionnels (None / manquants).
  • Codes derreur génériques :
    • 400 : données invalides (schema).
    • 401 : auth.
    • 404 : ressources inexistantes (device, benchmark, link, doc).
    • 413 : payload trop volumineux (facultatif selon config).
    • 500 : erreur interne.

Logs :

  • Logguer les erreurs de parsing JSON.
  • Logguer lorigine (IP) des appels POST /api/benchmark.