fix(setup): CompleteAsNode idempotent — konvertiert Standalone zu Cluster-Node
Wenn setup bereits abgeschlossen war (z.B. zuvor als Standalone eingerichtet), wird der Node jetzt ohne Fehler auf is_cluster_node=true umgestellt statt mit "setup already completed" zu fehlschlagen. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -60,7 +60,7 @@ import (
|
|||||||
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
|
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.151"
|
var version = "1.1.152"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
addr := os.Getenv("EDGEGUARD_API_ADDR")
|
addr := os.Getenv("EDGEGUARD_API_ADDR")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.151"
|
var version = "1.1.152"
|
||||||
|
|
||||||
const usage = `edgeguard-ctl — EdgeGuard CLI
|
const usage = `edgeguard-ctl — EdgeGuard CLI
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import (
|
|||||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.1.151"
|
var version = "1.1.152"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// renewTickInterval — how often we re-evaluate expiring certs.
|
// renewTickInterval — how often we re-evaluate expiring certs.
|
||||||
|
|||||||
@@ -168,6 +168,10 @@ func (s *Store) Complete(req Request) (*State, error) {
|
|||||||
// CompleteAsNode configures this node as a secondary cluster member.
|
// CompleteAsNode configures this node as a secondary cluster member.
|
||||||
// No admin credentials are created; login becomes available after PG
|
// No admin credentials are created; login becomes available after PG
|
||||||
// replication brings users from the primary.
|
// replication brings users from the primary.
|
||||||
|
//
|
||||||
|
// Idempotent: if setup was already completed (e.g. the node was
|
||||||
|
// previously configured as standalone), it is converted to cluster-node
|
||||||
|
// mode. Calling again after a successful join is a no-op.
|
||||||
func (s *Store) CompleteAsNode(req NodeRequest) (*State, error) {
|
func (s *Store) CompleteAsNode(req NodeRequest) (*State, error) {
|
||||||
if !looksLikeFQDN(req.FQDN) {
|
if !looksLikeFQDN(req.FQDN) {
|
||||||
return nil, fmt.Errorf("fqdn %q does not look like a fully-qualified hostname", req.FQDN)
|
return nil, fmt.Errorf("fqdn %q does not look like a fully-qualified hostname", req.FQDN)
|
||||||
@@ -179,16 +183,22 @@ func (s *Store) CompleteAsNode(req NodeRequest) (*State, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if prev.Completed {
|
|
||||||
return nil, errors.New("setup already completed")
|
|
||||||
}
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
|
completedAt := &now
|
||||||
|
if prev.CompletedAt != nil {
|
||||||
|
completedAt = prev.CompletedAt
|
||||||
|
}
|
||||||
st := &State{
|
st := &State{
|
||||||
FQDN: strings.TrimSpace(req.FQDN),
|
FQDN: strings.TrimSpace(req.FQDN),
|
||||||
ACMEEmail: strings.ToLower(strings.TrimSpace(req.ACMEEmail)),
|
ACMEEmail: strings.ToLower(strings.TrimSpace(req.ACMEEmail)),
|
||||||
IsClusterNode: true,
|
IsClusterNode: true,
|
||||||
Completed: true,
|
Completed: true,
|
||||||
CompletedAt: &now,
|
CompletedAt: completedAt,
|
||||||
|
// Carry over non-auth fields from previous state.
|
||||||
|
LicenseKey: prev.LicenseKey,
|
||||||
|
IPv6Enabled: prev.IPv6Enabled,
|
||||||
|
BackupRetentionKeep: prev.BackupRetentionKeep,
|
||||||
|
AuditRetentionDays: prev.AuditRetentionDays,
|
||||||
}
|
}
|
||||||
if err := s.Save(st); err != nil {
|
if err := s.Save(st); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Reference in New Issue
Block a user