Deuxième mode de réplication, séparé de la réplication cluster vers cluster
(sélecteur « Clusters (API) | Nœuds (fichiers) » en haut de page) : un profil
réplique la configuration système d'un nœud maître vers des nœuds cibles.
- réseau par /nodes/{node}/network (interfaces.new puis rechargement), adresses
et passerelles propres à chaque nœud, mapping des noms d'interfaces par cible ;
DNS par /nodes/{node}/dns ; multipath.conf, wwids (ajout seul), chrony,
sysctl.d, interfaces.d (hors sdn) par SSH
- découverte des nœuds (/cluster/status), accès SSH par nœud (mot de passe du
cluster ou propre), clé d'hôte épinglée, contrôle du nom du nœud
- dry-run avec diff des fichiers ; apply (admin) avec contrôle SHA-256,
sauvegarde et restore.sh sur le nœud, écriture atomique, rechargements,
restauration si un rechargement échoue, timer systemd de restauration si le
nœud est injoignable après le rechargement du réseau, confirmation tapée
- vue Nœuds et profils, journal séparé par mode, démo avec nœuds simulés
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
12 KiB
API Proxmox VE 9.x utilisée par pve-confsync
Vérifiée le 2026-10-13 (comptes : 2026-10-23) dans les sources Proxmox (miroirs GitHub officiels), faute d'accès à l'API viewer (https://pve.proxmox.com/pve-docs/api-viewer/) depuis l'environnement de développement. Versions lues : pve-manager 9.2.21, libpve-network-perl 1.6.7, pve-cluster 9.1.6. À recouper avec l'API viewer et les deux clusters de labo avant la phase 1.
Toutes les routes sont relatives à /api2/json. Authentification par ticket du compte
root@pam : POST /access/ticket (username, password) renvoie ticket et
CSRFPreventionToken (AccessControl.pm L198) ; le ticket
est envoyé dans le cookie PVEAuthCookie, le jeton CSRF dans l'en-tête
CSRFPreventionToken sur les écritures. Durée de vie du ticket : 2 h
(AccessControl.pm L58) ; pve-confsync se reconnecte après 90 min
ou sur un 401. Un compte root avec TFA renvoie NeedTFA
(L167) : refusé. Écritures en
application/x-www-form-urlencoded (tableaux = paramètre répété), suppression de champs
via le paramètre delete=a,b.
Version et cluster
| Méthode | Chemin | Usage | Droit |
|---|---|---|---|
| GET | /cluster/status |
nœuds en ligne | Sys.Audit sur / |
| GET | /nodes/{node}/version |
version (9.2.21), release (9.2) : refus si majeur ≠ 9 |
— |
| GET | /version |
repli pour un nœud isolé (API2.pm) | — |
| GET | /nodes/{node}/tasks/{upid}/status |
suivi de la tâche de rechargement SDN | — |
Options datacenter (datacenter.cfg)
| Méthode | Chemin | Droit |
|---|---|---|
| GET | /cluster/options (Cluster.pm) |
Sys.Audit sur / (sinon seuls console et tag-style) |
| PUT | /cluster/options (Cluster.pm) |
Sys.Modify sur / |
Points d'attention (DataCenterConfig.pm) :
- le GET renvoie des valeurs déjà analysées :
tag-style,next-id,user-tag-access,migration,ha,crs,notify,webauthn,u2fsous forme d'objets,registered-tagsetuser-tag-access.user-allow-listsous forme de tableaux ; le PUT attend des property strings (shape=full,color-map=a:ff0000, listes séparées par;). L'adaptateur stocke la forme canonique « property string, clés triées ». - le GET ajoute toujours
description(vide possible),mac_prefix(BC:24:11par défaut, L11) etallowed-tags(lecture seule) : retirés à la normalisation. - formats :
tag-styleL286,user-tag-accessL321,next-idL203.
SDN (SDN.pm)
| Méthode | Chemin | Usage | Droit |
|---|---|---|---|
| POST | /cluster/sdn/lock |
verrou global, renvoie le lock-token ; refusé s'il existe des changements en attente (sauf allow-pending=1) |
SDN.Allocate sur /sdn |
| DELETE | /cluster/sdn/lock |
libère le verrou (lock-token ou force=1) |
SDN.Allocate |
| POST | /cluster/sdn/rollback |
annule les changements en attente (lock-token, release-lock) |
SDN.Allocate |
| PUT | /cluster/sdn |
commit + rechargement réseau de tous les nœuds, renvoie un UPID (lock-token, release-lock) |
SDN.Allocate |
| GET | /cluster/sdn/dry-run?node= |
diff frr / interfaces.d/sdn (libpve-network-perl ≥ 1.3.0, mars 2026) : non utilisé en phase 0 | Sys.Audit sur /nodes/{node} |
| GET | /nodes/{node}/sdn/zones |
statut des zones par nœud (available, pending, error) |
SDN.Audit |
Le verrou et le paramètre lock-token sur toutes les écritures existent depuis
libpve-network-perl 1.1.3 (juillet 2025, avant PVE 9.0) : disponibles sur tout PVE 9.x.
Zones, VNets, subnets
| Objet | Liste / création | Élément | Notes |
|---|---|---|---|
| zone | /cluster/sdn/zones |
/cluster/sdn/zones/{zone} |
GET d'un élément = SDN.Allocate : on lit donc la liste (SDN.Audit suffit) |
| vnet | /cluster/sdn/vnets |
/cluster/sdn/vnets/{vnet} |
|
| subnet | /cluster/sdn/vnets/{vnet}/subnets |
.../subnets/{zone}-{ip}-{masque} |
création : subnet=<cidr>, type=subnet ; id calculé (SubnetPlugin.pm) |
Les GET acceptent running=1 (configuration appliquée) ou pending=1 ; sans paramètre,
la configuration courante, en attente comprise. La référence est lue en running=1,
les clients sans paramètre.
Champs (schémas : VlanPlugin.pm, VxlanPlugin.pm, VnetPlugin.pm, SubnetPlugin.pm) :
- zone vlan :
bridge(obligatoire),bridge-disable-mac-learning,nodes,mtu,dns,reversedns,dnszone,ipam - zone vxlan :
peers,vxlan-port(4789),fabric,nodes,mtu,dns,reversedns,dnszone,ipam - vnet :
zone(obligatoire),tag,alias,vlanaware,isolate-ports - subnet :
vnet,gateway,snat,dnszoneprefix,dhcp-range(tableau),dhcp-dns-server - calculés par PVE, ignorés :
digest,state,pending, et pour les subnetscidr,network,mask,zone
Comptes du royaume pve (vérifié le 2026-10-23, pve-access-control dff26b45, pve-cluster 86d4bb9e)
| Objet | Liste / création | Élément | Notes |
|---|---|---|---|
| groupe | /access/groups (Group.pm L26) |
/access/groups/{groupid} |
champ comment ; users calculé, ignoré |
| rôle | /access/roles (Role.pm L31) |
/access/roles/{roleid} (PUT) |
rôles special (intégrés) ignorés, non modifiables (L146) ; privs trié |
| utilisateur | /access/users?full=1 (User.pm L156) |
/access/users/{userid} |
seuls les @pve ; tokens, realm-type, champs de verrou TFA ignorés ; groups liste triée ; password jamais envoyé par l'API ; root@pam jamais supprimé |
Mots de passe. L'API ne renvoie pas les hachés : ils sont dans
/etc/pve/priv/shadow.cfg (lignes user:hash:, utilisateur sans royaume,
Auth/PVE.pm L13-L50). Lecture et écriture par SSH en root :
- lecture :
cat /etc/pve/priv/shadow.cfg; - écriture : script perl sous
PVE::Auth::PVE::lock_shadow_config(L51) aveccfs_read_file/cfs_write_file, commestore_password(L95-L98) : le haché est recopié tel quel, sans le recalculer.cfs_read_filesans version relit toujours le fichier (Cluster.pm).
À valider sur un vrai cluster : script d'écriture du shadow, forme réelle de
/access/users?full=1, mise à jour d'un utilisateur avec champs vidés.
Réplication de nœuds (vérifié le 2026-10-23, pve-manager f643ce4b, pve-common master)
| Méthode | Chemin | Usage |
|---|---|---|
| GET | /nodes/{node}/network (Network.pm) |
interfaces, lues dans interfaces.new s'il existe ; lo retiré |
| POST | /nodes/{node}/network |
création (iface, type + champs) dans interfaces.new |
| PUT | /nodes/{node}/network/{iface} |
mise à jour (type obligatoire, delete=) |
| DELETE | /nodes/{node}/network/{iface} |
suppression (prune) |
| PUT | /nodes/{node}/network |
renomme interfaces.new puis ifreload -a dans une tâche (UPID) |
| DELETE | /nodes/{node}/network |
annule les changements en attente (supprime interfaces.new) |
| GET / PUT | /nodes/{node}/dns (Nodes.pm) |
search (obligatoire au PUT), dns1 à dns3 ; le PUT réécrit tous les serveurs |
Points d'attention :
- champs écrits (
$confdesc) :type,comments,comments6,autostart,bridge_vlan_aware,bridge_vids,bridge_ports,ovs_*,slaves,bond_mode,bond-primary,bond_xmit_hash_policy,vlan-raw-device,vlan-id,gateway,gateway6,cidr,cidr6,mtu. Le GET renvoie aussiaddress/netmask(forme canonique :cidr),bridge_stp,bridge_fd,bond_miimon(écrits par défaut par PVE),options(lignes inconnues de l'API, jamais écrites),active,exists,families,method,priority: non répliqués. - le PUT d'une interface recalcule
methodetfamiliesà partir des paramètres reçus : sansaddress/cidr, une interface statique devientmanual. pve-confsync envoie donc toute la configuration de l'interface à chaque mise à jour. interfaces.d/*n'est pas lu par l'API (Interfaces.pm) : répliqué en fichier par SSH.
Scripts SSH (première ligne # confsync:<étape>) : lecture (stat, base64 -w0),
préparation (contrôle SHA-256, cp -p vers la sauvegarde, restore.sh, écriture par
mktemp + mv), restauration, systemd-run --on-active=120s / systemctl stop <unité>.timer,
rechargements. Le script de préparation est testé tel quel avec le shell local
(internal/nodesync/script_test.go) ; le reste est à valider sur les clusters de labo.
Droits
Accès en root@pam (API + SSH, même mot de passe), sans TFA. La référence (primaire)
n'est jamais écrite. Le certificat TLS et la clé d'hôte SSH sont épinglés au premier test.