Réplication de nœuds : réseau et DNS par l'API, multipath, chrony, sysctl par SSH
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>
This commit is contained in:
1 parent
dc1a7ff40e
commit
1e667ce8b9
24 files changed
+4973
-65
No files matched your search
@@ -16,6 +16,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"pve-confsync/internal/nodesync"
|
||||
"pve-confsync/internal/service"
|
||||
"pve-confsync/internal/store"
|
||||
)
|
||||
@@ -40,6 +41,10 @@ type Server struct {
|
||||
state *service.State
|
||||
stateAt time.Time
|
||||
|
||||
// last comparison of each node replication profile
|
||||
nodeMu sync.Mutex
|
||||
nodeStates map[string]*nodesync.State
|
||||
|
||||
applyMu sync.Mutex // one synchronization at a time
|
||||
jobs sync.WaitGroup
|
||||
}
|
||||
@@ -83,6 +88,18 @@ func (s *Server) Handler() http.Handler {
|
||||
mux.Handle("GET /api/settings", s.role(viewer, s.handleSettings))
|
||||
mux.Handle("PUT /api/settings", s.role(admin, s.handleSaveSettings))
|
||||
|
||||
mux.Handle("GET /api/nodes", s.role(viewer, s.handleNodes))
|
||||
mux.Handle("POST /api/nodes/discover", s.role(admin, s.handleDiscover))
|
||||
mux.Handle("PUT /api/nodes/{cluster}/{node}", s.role(admin, s.handleSaveNode))
|
||||
mux.Handle("POST /api/nodes/{cluster}/{node}/check", s.role(admin, s.handleCheckNode))
|
||||
mux.Handle("POST /api/nodes/{cluster}/{node}/forget", s.role(admin, s.handleForgetNode))
|
||||
mux.Handle("PUT /api/profiles/{name}", s.role(admin, s.handleSaveProfile))
|
||||
mux.Handle("DELETE /api/profiles/{name}", s.role(admin, s.handleDeleteProfile))
|
||||
mux.Handle("GET /api/nodestate", s.role(viewer, s.handleNodeState))
|
||||
mux.Handle("POST /api/nodedryrun", s.role(operator, s.handleNodeDryRun))
|
||||
// writing system files as root on the nodes: administrators only
|
||||
mux.Handle("POST /api/nodeapply", s.role(admin, s.handleNodeApply))
|
||||
|
||||
mux.Handle("GET /api/users", s.role(admin, s.handleUsers))
|
||||
mux.Handle("PUT /api/users/{name}", s.role(admin, s.handleSaveUser))
|
||||
mux.Handle("DELETE /api/users/{name}", s.role(admin, s.handleDeleteUser))
|
||||
|
||||
Reference in new issue
Block a user