Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
becd068637 | ||
|
|
b3dda81b49 | ||
|
|
b20ace8763 |
@@ -194,6 +194,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
// runSecondaryConfigRender wird weiter unten gestartet sobald
|
// runSecondaryConfigRender wird weiter unten gestartet sobald
|
||||||
// clusterAggregator verfügbar ist (braucht mTLS-Client für Cert-Sync).
|
// clusterAggregator verfügbar ist (braucht mTLS-Client für Cert-Sync).
|
||||||
|
} else if nodeID != "" && st != nil && st.Completed && st.FQDN != "" {
|
||||||
|
// Primary/Founder (kein joined Secondary): self (role=primary) an
|
||||||
|
// alle Peers pushen, damit deren lokale ha_nodes den Primary frisch
|
||||||
|
// hält — sonst zeigt die vom Secondary ausgelieferte UI den Primary
|
||||||
|
// als offline. No-op solange keine Peers existieren (Single-Node).
|
||||||
|
go runPeerPush(context.Background(), pool, clusterStore, nodeID, st.FQDN, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 3.3: Cluster-CA + Peer-Cert. Founder-Pfad — auf einem
|
// Phase 3.3: Cluster-CA + Peer-Cert. Founder-Pfad — auf einem
|
||||||
@@ -826,12 +832,20 @@ func runSecondaryConfigRender(ctx context.Context, pool *pgxpoolPool, box *secre
|
|||||||
}
|
}
|
||||||
|
|
||||||
// runPrimaryPush periodically pushes this secondary node's config_hash to the
|
// runPrimaryPush periodically pushes this secondary node's config_hash to the
|
||||||
// primary via mTLS. The primary's ha_nodes view only gets config_hash written
|
// primary via mTLS. The primary's ha_nodes view only gets config_hash + last_seen
|
||||||
// during join-time autoRegister — after that the primary never hears about
|
// written during join-time autoRegister — after that the primary never hears about
|
||||||
// hash changes unless we push. Without this, the drift banner shows stale
|
// the secondary unless we push. Without this, the drift banner shows stale hashes
|
||||||
// hashes from join-time forever.
|
// from join-time forever AND the secondary's last_seen freezes → SweepStaleNodes
|
||||||
|
// marks it offline.
|
||||||
|
//
|
||||||
|
// WICHTIG: tick MUSS deutlich unter dem Stale-Threshold (4× 30s = 2 min, siehe
|
||||||
|
// scheduler.staleThreshold / cluster.SweepStaleNodes) liegen. Sonst flippt der
|
||||||
|
// Secondary zwischen den Pushes zwangsläufig auf "offline" (bei 5-min-Tick:
|
||||||
|
// 2 min online, 3 min offline). 30s = 4 Pushes pro Stale-Fenster → ein
|
||||||
|
// verpasster Push (Netz-Glitch) ist unkritisch. Der Receiver (AgentRegisterPeer)
|
||||||
|
// lädt nftables nur bei IP-Änderung neu → kein Reload-Sturm durch häufige Pushes.
|
||||||
func runPrimaryPush(ctx context.Context, pool *pgxpoolPool, nodeID, fqdn, version, primaryURL string) {
|
func runPrimaryPush(ctx context.Context, pool *pgxpoolPool, nodeID, fqdn, version, primaryURL string) {
|
||||||
const tick = 5 * time.Minute
|
const tick = 30 * time.Second
|
||||||
t := time.NewTicker(tick)
|
t := time.NewTicker(tick)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
push := func() {
|
push := func() {
|
||||||
@@ -855,6 +869,51 @@ func runPrimaryPush(ctx context.Context, pool *pgxpoolPool, nodeID, fqdn, versio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runPeerPush läuft auf dem Primary/Founder und pusht alle 30s die eigene
|
||||||
|
// Identität (role=primary) an jeden Peer via mTLS — das Gegenstück zu
|
||||||
|
// runPrimaryPush (Secondary→Primary). Zusammen ergibt das einen
|
||||||
|
// bidirektionalen Cross-Node-Heartbeat: beide Nodes sehen sich gegenseitig
|
||||||
|
// als online, egal von welchem Node die UI ausgeliefert wird. Tick wie
|
||||||
|
// runPrimaryPush deutlich unter dem 2-min-Stale-Threshold. No-op solange
|
||||||
|
// keine Peers existieren (Single-Node) bzw. wenn ein Peer down ist (Debug-Log).
|
||||||
|
func runPeerPush(ctx context.Context, pool *pgxpoolPool, store *cluster.Store, nodeID, fqdn, version string) {
|
||||||
|
const tick = 30 * time.Second
|
||||||
|
t := time.NewTicker(tick)
|
||||||
|
defer t.Stop()
|
||||||
|
push := func() {
|
||||||
|
pCtx, cancel := context.WithTimeout(ctx, 25*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
peers, err := store.List(pCtx)
|
||||||
|
if err != nil {
|
||||||
|
slog.Warn("cluster: peer-push list failed", "error", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hash, _ := cluster.ComputeConfigHash(pCtx, pool)
|
||||||
|
for i := range peers {
|
||||||
|
p := peers[i]
|
||||||
|
if p.ID == nodeID {
|
||||||
|
continue // nicht an sich selbst pushen
|
||||||
|
}
|
||||||
|
target := p.APIURL
|
||||||
|
if target == "" {
|
||||||
|
target = "https://" + p.FQDN
|
||||||
|
}
|
||||||
|
if err := clusterjoin.PushSelfToPeer(target, "", nodeID, fqdn, version, hash, "primary"); err != nil {
|
||||||
|
slog.Debug("cluster: push-to-peer failed", "peer", p.FQDN, "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
push() // immediate push on API startup
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-t.C:
|
||||||
|
push()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func randomEphemeralSecret() []byte {
|
func randomEphemeralSecret() []byte {
|
||||||
b := make([]byte, 32)
|
b := make([]byte, 32)
|
||||||
if _, err := rand.Read(b); err != nil {
|
if _, err := rand.Read(b); err != nil {
|
||||||
|
|||||||
@@ -866,6 +866,7 @@ type registerPeerRequest struct {
|
|||||||
MgmtIP string `json:"mgmt_ip"` // optional
|
MgmtIP string `json:"mgmt_ip"` // optional
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
ConfigHash *string `json:"config_hash"` // nil=absent (don't change), ""=no user config
|
ConfigHash *string `json:"config_hash"` // nil=absent (don't change), ""=no user config
|
||||||
|
Role string `json:"role"` // "" → "peer" (joining peer); "primary" beim Push des Primary
|
||||||
}
|
}
|
||||||
|
|
||||||
// AgentRegisterPeer: vom Joiner nach issue-cert via mTLS aufgerufen.
|
// AgentRegisterPeer: vom Joiner nach issue-cert via mTLS aufgerufen.
|
||||||
@@ -904,12 +905,21 @@ func (h *ClusterHandler) AgentRegisterPeer(c *gin.Context) {
|
|||||||
// Node, hier ist der „Self" der joining-Peer auf dieser Primary-Seite.
|
// Node, hier ist der „Self" der joining-Peer auf dieser Primary-Seite.
|
||||||
// Der Name passt nicht 100% semantisch, aber das SQL ist exakt das was
|
// Der Name passt nicht 100% semantisch, aber das SQL ist exakt das was
|
||||||
// wir brauchen.)
|
// wir brauchen.)
|
||||||
|
// Rolle aus dem Request (default "peer"). Ein joining-Peer sendet keine
|
||||||
|
// Rolle → "peer". Der Primary-Push sendet "primary", damit die vom
|
||||||
|
// Secondary ausgelieferte UI den Primary korrekt als primary zeigt.
|
||||||
|
// Cert-CN authentifiziert die FQDN; role ist node-lokal/Anzeige (echte
|
||||||
|
// Rollenerkennung läuft über pg_publication).
|
||||||
|
role := strings.TrimSpace(req.Role)
|
||||||
|
if role == "" {
|
||||||
|
role = "peer"
|
||||||
|
}
|
||||||
n := models.HANode{
|
n := models.HANode{
|
||||||
ID: req.ID,
|
ID: req.ID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
FQDN: req.FQDN,
|
FQDN: req.FQDN,
|
||||||
APIURL: req.APIURL,
|
APIURL: req.APIURL,
|
||||||
Role: "peer",
|
Role: role,
|
||||||
Status: "online", // peer IS online — it just connected via mTLS
|
Status: "online", // peer IS online — it just connected via mTLS
|
||||||
}
|
}
|
||||||
if req.PublicIP != "" {
|
if req.PublicIP != "" {
|
||||||
@@ -965,7 +975,14 @@ func (h *ClusterHandler) AgentRegisterPeer(c *gin.Context) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("cluster: peer registered via mTLS",
|
// Bei neuem Peer / IP-Wechsel als Info loggen (relevantes Ereignis),
|
||||||
|
// sonst Debug — die periodischen 30s-Pushes (runPrimaryPush/runPeerPush)
|
||||||
|
// würden sonst das Log fluten.
|
||||||
|
logFn := slog.Debug
|
||||||
|
if ipChanged {
|
||||||
|
logFn = slog.Info
|
||||||
|
}
|
||||||
|
logFn("cluster: peer registered via mTLS",
|
||||||
"id", out.ID, "fqdn", out.FQDN, "role", out.Role, "status", out.Status,
|
"id", out.ID, "fqdn", out.FQDN, "role", out.Role, "status", out.Status,
|
||||||
"client_cn", cn, "remote", c.ClientIP())
|
"client_cn", cn, "remote", c.ClientIP())
|
||||||
response.OK(c, out)
|
response.OK(c, out)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/configgen"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/configgen"
|
||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/handlers/response"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/handlers/response"
|
||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/models"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/models"
|
||||||
|
aptsvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/apt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ruStateMu serialisiert Lesen/Schreiben der Rolling-Update-State-Datei
|
// ruStateMu serialisiert Lesen/Schreiben der Rolling-Update-State-Datei
|
||||||
@@ -32,17 +33,24 @@ const (
|
|||||||
phaseFailed = "failed"
|
phaseFailed = "failed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FinishRollingUpdateIfPending wird beim API-Start aufgerufen. Wenn die
|
// FinishRollingUpdateIfPending wird beim API-Start aufgerufen.
|
||||||
// State-Datei "updating-primary" enthält, bedeutet das dass der Primary
|
// - "updating-primary": der Primary ist gerade erfolgreich neugestartet →
|
||||||
// gerade erfolgreich neugestartet ist → Update abgeschlossen → "done" schreiben.
|
// Update abgeschlossen → "done".
|
||||||
|
// - "updating-secondary"/"waiting-secondary": die orchestrierende Goroutine
|
||||||
|
// lief in DIESEM (jetzt neu gestarteten) Prozess und ist mit ihm gestorben.
|
||||||
|
// Die Phase kann nicht weiterlaufen → auf "idle" zurücksetzen, sonst zeigt
|
||||||
|
// die UI ewig "Rolling Update läuft". (Vorher blieb so ein Stand hängen.)
|
||||||
func FinishRollingUpdateIfPending() {
|
func FinishRollingUpdateIfPending() {
|
||||||
st := readRollingUpdateState()
|
st := readRollingUpdateState()
|
||||||
if st.Phase == phaseUpdatingPrimary {
|
switch st.Phase {
|
||||||
|
case phaseUpdatingPrimary:
|
||||||
writeRollingUpdateState(RollingUpdateState{
|
writeRollingUpdateState(RollingUpdateState{
|
||||||
Phase: phaseDone,
|
Phase: phaseDone,
|
||||||
SecondaryID: st.SecondaryID,
|
SecondaryID: st.SecondaryID,
|
||||||
SecondaryFQDN: st.SecondaryFQDN,
|
SecondaryFQDN: st.SecondaryFQDN,
|
||||||
})
|
})
|
||||||
|
case phaseUpdatingSecondary, phaseWaitingSecondary:
|
||||||
|
writeRollingUpdateState(RollingUpdateState{Phase: phaseIdle})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,15 +162,21 @@ func (h *ClusterHandler) RollingUpdateStatus(c *gin.Context) {
|
|||||||
func (h *ClusterHandler) runRollingUpdate(secondary *models.HANode) {
|
func (h *ClusterHandler) runRollingUpdate(secondary *models.HANode) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Vor dem Upgrade die aktuelle Secondary-Version als Baseline merken —
|
// Zielversion = das verfügbare apt-Candidate (worauf wir hochziehen) und
|
||||||
// der Flip wird gegen DIESEN Wert geprüft (nicht gegen die Primary-
|
// die aktuelle Secondary-Version als Baseline. Beides steuert, ob der
|
||||||
// Version, die fälschlich sofort/nie „flippen" konnte).
|
// Secondary überhaupt etwas zu tun hat.
|
||||||
|
candidate := rollingCandidateVersion(ctx)
|
||||||
baseline := secondaryVersion(ctx, h, secondary)
|
baseline := secondaryVersion(ctx, h, secondary)
|
||||||
target := baseline
|
|
||||||
if target == "" {
|
|
||||||
target = h.Version // Fallback, falls Baseline nicht abrufbar
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Ist der Secondary bereits auf der Zielversion, gibt es nichts
|
||||||
|
// hochzuziehen — KEIN Trigger, KEIN Warten. Sonst würde auf einen
|
||||||
|
// Version-Flip gewartet, der nie kommt → 10-min-Timeout (der frühere Bug,
|
||||||
|
// wenn beide Nodes schon aktuell waren).
|
||||||
|
secondaryUpToDate := candidate != "" && baseline != "" && baseline == candidate
|
||||||
|
if secondaryUpToDate {
|
||||||
|
slog.Info("rolling-update: secondary already at target — skipping secondary step",
|
||||||
|
"version", candidate)
|
||||||
|
} else {
|
||||||
// 1. Secondary triggern
|
// 1. Secondary triggern
|
||||||
slog.Info("rolling-update: posting trigger-update to secondary", "fqdn", secondary.FQDN)
|
slog.Info("rolling-update: posting trigger-update to secondary", "fqdn", secondary.FQDN)
|
||||||
result := h.Aggregator.PostPeer(ctx, *secondary, "/agent/cluster/trigger-update")
|
result := h.Aggregator.PostPeer(ctx, *secondary, "/agent/cluster/trigger-update")
|
||||||
@@ -184,7 +198,8 @@ func (h *ClusterHandler) runRollingUpdate(secondary *models.HANode) {
|
|||||||
SecondaryID: secondary.ID,
|
SecondaryID: secondary.ID,
|
||||||
SecondaryFQDN: secondary.FQDN,
|
SecondaryFQDN: secondary.FQDN,
|
||||||
})
|
})
|
||||||
slog.Info("rolling-update: waiting for secondary version flip")
|
slog.Info("rolling-update: waiting for secondary version flip",
|
||||||
|
"baseline", baseline, "candidate", candidate)
|
||||||
|
|
||||||
// Kurze Wartezeit damit apt auf dem Secondary erst losläuft
|
// Kurze Wartezeit damit apt auf dem Secondary erst losläuft
|
||||||
time.Sleep(20 * time.Second)
|
time.Sleep(20 * time.Second)
|
||||||
@@ -198,8 +213,13 @@ func (h *ClusterHandler) runRollingUpdate(secondary *models.HANode) {
|
|||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(results[0].Data, &ver); err == nil {
|
if err := json.Unmarshal(results[0].Data, &ver); err == nil {
|
||||||
slog.Info("rolling-update: secondary version", "version", ver.Version, "baseline", target)
|
slog.Info("rolling-update: secondary version", "version", ver.Version,
|
||||||
if ver.Version != "" && ver.Version != target {
|
"baseline", baseline, "candidate", candidate)
|
||||||
|
// Erfolg = Secondary hat die Zielversion erreicht (candidate)
|
||||||
|
// ODER hat sich gegenüber der Baseline überhaupt bewegt
|
||||||
|
// (Fallback, wenn candidate nicht ermittelbar war).
|
||||||
|
if ver.Version != "" &&
|
||||||
|
((candidate != "" && ver.Version == candidate) || ver.Version != baseline) {
|
||||||
versionFlipped = true
|
versionFlipped = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -218,8 +238,23 @@ func (h *ClusterHandler) runRollingUpdate(secondary *models.HANode) {
|
|||||||
slog.Warn("rolling-update: secondary version flip timeout")
|
slog.Warn("rolling-update: secondary version flip timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Primary (uns selbst) aktualisieren — identisch zu /system/upgrade.
|
||||||
|
// Ist der Primary bereits auf der Zielversion (z. B. beide Nodes schon
|
||||||
|
// aktuell), gibt es nichts zu tun → direkt "done". Sonst liefe ein
|
||||||
|
// apt-Lauf ohne Paket-Wechsel → kein Restart → Phase hinge ewig in
|
||||||
|
// "updating-primary".
|
||||||
|
if candidate != "" && h.Version == candidate {
|
||||||
|
slog.Info("rolling-update: primary already at target — nothing to upgrade", "version", candidate)
|
||||||
|
writeRollingUpdateState(RollingUpdateState{
|
||||||
|
Phase: phaseDone,
|
||||||
|
SecondaryID: secondary.ID,
|
||||||
|
SecondaryFQDN: secondary.FQDN,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Primary (uns selbst) aktualisieren — identisch zu /system/upgrade
|
|
||||||
writeRollingUpdateState(RollingUpdateState{
|
writeRollingUpdateState(RollingUpdateState{
|
||||||
Phase: phaseUpdatingPrimary,
|
Phase: phaseUpdatingPrimary,
|
||||||
SecondaryID: secondary.ID,
|
SecondaryID: secondary.ID,
|
||||||
@@ -280,6 +315,15 @@ rm -f /var/lib/edgeguard/upgrade.sh
|
|||||||
slog.Info("rolling-update: primary upgrade dispatched, process will restart")
|
slog.Info("rolling-update: primary upgrade dispatched, process will restart")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rollingCandidateVersion liefert best-effort die verfügbare apt-Candidate-
|
||||||
|
// Version des Meta-Pakets "edgeguard" — also die Version, auf die das Rolling-
|
||||||
|
// Update hochzieht. Leerer String, wenn apt sie nicht ermitteln kann (dann
|
||||||
|
// fällt runRollingUpdate auf reine Baseline-Flip-Erkennung zurück).
|
||||||
|
func rollingCandidateVersion(ctx context.Context) string {
|
||||||
|
vers := aptsvc.PackageVersions(ctx, false)
|
||||||
|
return vers["edgeguard_available"]
|
||||||
|
}
|
||||||
|
|
||||||
// secondaryVersion holt best-effort die laufende Version des Peers via mTLS.
|
// secondaryVersion holt best-effort die laufende Version des Peers via mTLS.
|
||||||
func secondaryVersion(ctx context.Context, h *ClusterHandler, secondary *models.HANode) string {
|
func secondaryVersion(ctx context.Context, h *ClusterHandler, secondary *models.HANode) string {
|
||||||
results := h.Aggregator.FanOut(ctx, []models.HANode{*secondary}, "/agent/cluster/version", h.LocalID)
|
results := h.Aggregator.FanOut(ctx, []models.HANode{*secondary}, "/agent/cluster/version", h.LocalID)
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ var servicesToCheck = []struct{ Label, Unit string }{
|
|||||||
{"unbound", "unbound"},
|
{"unbound", "unbound"},
|
||||||
{"chrony", "chrony"},
|
{"chrony", "chrony"},
|
||||||
{"squid", "squid"},
|
{"squid", "squid"},
|
||||||
|
{"kea-dhcp4", "kea-dhcp4-server"},
|
||||||
|
{"freeradius", "freeradius"},
|
||||||
{"postgresql", "postgresql"},
|
{"postgresql", "postgresql"},
|
||||||
{"crowdsec", "crowdsec"},
|
{"crowdsec", "crowdsec"},
|
||||||
{"crowdsec-firewall-bouncer", "crowdsec-firewall-bouncer"},
|
{"crowdsec-firewall-bouncer", "crowdsec-firewall-bouncer"},
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ func Join(req Request) error {
|
|||||||
// synchronous on the primary side.
|
// synchronous on the primary side.
|
||||||
var autoRegErr error
|
var autoRegErr error
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
if err := autoRegister(primary, tlsDir, req.CommonName, req.Version, req.NodeID, ""); err == nil {
|
if err := autoRegister(primary, tlsDir, req.CommonName, req.Version, req.NodeID, "", "peer"); err == nil {
|
||||||
autoRegErr = nil
|
autoRegErr = nil
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
@@ -222,13 +222,21 @@ func issueCert(primary, token, csr string, insecure bool) (caCert, peerCert stri
|
|||||||
// goroutine so the primary's ha_nodes always reflects the secondary's actual
|
// goroutine so the primary's ha_nodes always reflects the secondary's actual
|
||||||
// config_hash (not the stale join-time value).
|
// config_hash (not the stale join-time value).
|
||||||
func PushSelfToPrimary(primaryURL, tlsDir, nodeID, fqdn, version, configHash string) error {
|
func PushSelfToPrimary(primaryURL, tlsDir, nodeID, fqdn, version, configHash string) error {
|
||||||
|
return PushSelfToPeer(primaryURL, tlsDir, nodeID, fqdn, version, configHash, "peer")
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushSelfToPeer sendet die eigene Identität an einen beliebigen Peer (mTLS,
|
||||||
|
// /agent/cluster/peers). role bestimmt, mit welcher Rolle sich dieser Node
|
||||||
|
// beim Empfänger einträgt: ein Secondary pusht "peer" an den Primary, der
|
||||||
|
// Primary pusht "primary" an jeden Secondary (bidirektionaler Heartbeat).
|
||||||
|
func PushSelfToPeer(peerURL, tlsDir, nodeID, fqdn, version, configHash, role string) error {
|
||||||
if tlsDir == "" {
|
if tlsDir == "" {
|
||||||
tlsDir = clustertls.DefaultDir
|
tlsDir = clustertls.DefaultDir
|
||||||
}
|
}
|
||||||
return autoRegister(primaryURL, tlsDir, fqdn, version, nodeID, configHash)
|
return autoRegister(peerURL, tlsDir, fqdn, version, nodeID, configHash, role)
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash string) error {
|
func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash, role string) error {
|
||||||
u, err := url.Parse(primary)
|
u, err := url.Parse(primary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -241,6 +249,9 @@ func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash strin
|
|||||||
nodeID = strings.TrimSpace(string(raw))
|
nodeID = strings.TrimSpace(string(raw))
|
||||||
}
|
}
|
||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
|
if role == "" {
|
||||||
|
role = "peer"
|
||||||
|
}
|
||||||
body, _ := json.Marshal(map[string]string{
|
body, _ := json.Marshal(map[string]string{
|
||||||
"id": nodeID,
|
"id": nodeID,
|
||||||
"name": hostname,
|
"name": hostname,
|
||||||
@@ -248,6 +259,7 @@ func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash strin
|
|||||||
"api_url": "https://" + commonName + ":3443",
|
"api_url": "https://" + commonName + ":3443",
|
||||||
"version": version,
|
"version": version,
|
||||||
"config_hash": configHash,
|
"config_hash": configHash,
|
||||||
|
"role": role,
|
||||||
})
|
})
|
||||||
|
|
||||||
pair, err := tls.LoadX509KeyPair(tlsDir+"/peer.crt", tlsDir+"/peer.key")
|
pair, err := tls.LoadX509KeyPair(tlsDir+"/peer.crt", tlsDir+"/peer.key")
|
||||||
|
|||||||
Reference in New Issue
Block a user