API REST Proxmox : premiers appels¶
Tout ce que fait la GUI Proxmox VE passe par une API REST JSON exposée sur https://<nœud>:8006/api2/json/. Savoir l'appeler avec curl vous permet de scripter l'inventaire, la supervision ou des actions simples, et de comprendre ce que font Terraform et Ansible sous le capot.
Notions clés¶
| Notion | Détail |
|---|---|
| URL de base | https://pve01.corp.local:8006/api2/json/ (aussi /api2/extjs/ pour la GUI) |
| Arborescence | /cluster, /nodes/{node}, /storage, /access, /pools, /version |
| Verbes | GET lit, POST crée ou lance une action, PUT modifie, DELETE supprime |
| Réponse | Objet JSON avec un champ data |
| Tâches asynchrones | Une action longue (démarrage, clone, sauvegarde) renvoie un UPID à suivre |
| N'importe quel nœud | Chaque nœud du cluster accepte tous les appels et relaie vers le bon nœud |
| Référence | API Viewer ou pvesh usage <chemin> --verbose |
Deux façons de s'authentifier¶
| Ticket (session) | Jeton API | |
|---|---|---|
| Obtention | POST /access/ticket avec utilisateur et mot de passe (et 2FA) |
Créé une fois avec pveum user token add |
| Envoi | Cookie PVEAuthCookie + en-tête CSRFPreventionToken pour POST/PUT/DELETE |
En-tête Authorization: PVEAPIToken=USER@REALM!ID=SECRET |
| Durée | 2 heures, renouvelable | Jusqu'à expiration ou révocation |
| Usage | Scripts interactifs, tests | Outils automatisés (recommandé) |
flowchart LR
S[Script] -->|PVEAPIToken=...| P[pveproxy :8006 sur pve01]
P --> D[pvedaemon : contrôle des ACL]
D -->|action sur pve02| R[relais vers pve02]
D -->|réponse JSON / UPID| S
Premiers appels avec un jeton¶
Créez un jeton en lecture seule pour vos essais, comme décrit dans Jetons API et comptes de service, puis :
export PVE='https://pve01.corp.local:8006/api2/json'
export AUTH='Authorization: PVEAPIToken=svc-monitoring@pve!zabbix=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
curl -s -H "$AUTH" "$PVE/version" | jq .data
curl -s -H "$AUTH" "$PVE/cluster/status" | jq '.data[] | {name, type, online, quorate}'
curl -s -H "$AUTH" "$PVE/cluster/resources?type=vm" \
| jq -r '.data[] | [.vmid, .name, .node, .status] | @tsv'
curl -s -H "$AUTH" "$PVE/nodes/pve01/storage/pbs-local/status" | jq .data
Les variables sont entre guillemets simples à la déclaration : le ! du jeton ne doit pas être interprété par le shell.
Une action : démarrer une VM et suivre la tâche¶
Avec un jeton disposant de VM.PowerMgmt sur /vms/101 :
UPID=$(curl -s -X POST -H "$AUTH" "$PVE/nodes/pve01/qemu/101/status/start" | jq -r .data)
echo "$UPID" # UPID:pve01:000A1B2C:...:qmstart:101:svc-ops@pve!ci:
curl -s -H "$AUTH" "$PVE/nodes/pve01/tasks/$UPID/status" | jq '.data | {status, exitstatus}'
# status "stopped" et exitstatus "OK" = tâche terminée avec succès
Le paramètre d'une modification se passe en formulaire : curl -X PUT -H "$AUTH" --data-urlencode 'description=Serveur web' "$PVE/nodes/pve01/qemu/101/config".
Avec un ticket (sans jeton)¶
curl -s -d 'username=jdupont@pve' --data-urlencode 'password=<mdp>' \
"$PVE/access/ticket" | jq -r '.data | .ticket, .CSRFPreventionToken'
# appels suivants :
curl -s -b "PVEAuthCookie=<ticket>" -H "CSRFPreventionToken: <csrf>" -X POST \
"$PVE/nodes/pve01/qemu/101/status/shutdown"
Un compte avec 2FA reçoit un ticket partiel et doit compléter le second facteur : pour l'automatisation, utilisez un jeton.
Recommandations MSP¶
- Un jeton par outil, en
privsep 1, avec le rôle minimal. Jamais le mot de passeroot@pamdans un script. - Vérifier le certificat : évitez
-k. Utilisez un certificat valide ou--cacert /etc/pve/pve-root-ca.pemcopié sur le poste client. - Viser un FQDN ou une IP de nœud stable ; pour un cluster, prévoir une liste de nœuds de repli dans le script.
- Les appels de lecture sont libres pour le client. Les appels qui modifient cluster, Ceph, SDN ou HA restent soumis à la matrice de responsabilité.
- Pour l'API PBS : même logique sur le port 8007, en-tête
Authorization: PBSAPIToken=....
Pièges vus en support
401 No ticket: en-tête mal formé, souvent un!mangé par le shell ou un espace en trop.403 Permission check failed: jeton enprivsep 1sans ACL propre, ou chemin non couvert.501 Method not implemented: mauvais verbe HTTP (GET au lieu de POST surstatus/start).- Script qui enchaîne des actions sans attendre la fin de la tâche (UPID) : verrous
lock: clone, VM non démarrée. - Boucle de supervision trop agressive (plusieurs appels par seconde) : charge inutile sur
pveproxy. Préférer/cluster/resourcesen un appel.
Testez-vous¶
-
Quel point d'API donne en un appel l'état de toutes les VM du cluster ?
Réponse
GET /cluster/resources?type=vm. -
Un
POST .../status/startrépond tout de suite. La VM est-elle démarrée ?Réponse
Pas forcément : la réponse est un UPID de tâche. Il faut suivre
/nodes/{node}/tasks/{upid}/statusjusqu'àstatus: stoppedetexitstatus: OK. -
Quel en-tête est obligatoire, en plus du cookie, pour une écriture avec un ticket ?
Réponse
CSRFPreventionToken. Il n'est pas nécessaire avec un jeton API. -
Comment trouver les paramètres acceptés par
/nodes/{node}/qemu/{vmid}/config?Réponse
Dans l'API Viewer ou avec
pvesh usage /nodes/pve01/qemu/101/config --verbose.
Pour aller plus loin¶
- CLI essentielles · Terraform / OpenTofu · Ansible
- Documentation officielle : Proxmox VE API (wiki) · API Viewer · API Tokens