From 203ef2d1adb19682ea7ce2e3ad3b8aba6f6e79d1 Mon Sep 17 00:00:00 2001 From: anhthii Date: Mon, 2 Mar 2026 09:24:19 +0700 Subject: [PATCH] Add --peers flag to sync peers from JSON file to Consul on startup Introduces a --peers CLI flag that loads peer definitions from a JSON file and registers any new peers into Consul before the node starts. Existing peers are skipped. Also extracts PeersPrefix constant to avoid hardcoded strings. --- cmd/mpcium/main.go | 19 ++++++++++++++- pkg/config/peers.go | 56 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/cmd/mpcium/main.go b/cmd/mpcium/main.go index 3c2c1a0..ad801ef 100644 --- a/cmd/mpcium/main.go +++ b/cmd/mpcium/main.go @@ -88,6 +88,10 @@ func main() { Aliases: []string{"k"}, Usage: "Path to file containing password for decrypting .age encrypted node private key", }, + &cli.StringFlag{ + Name: "peers", + Usage: "Path to peers.json file (syncs new peers to Consul on startup)", + }, &cli.BoolFlag{ Name: "debug", Usage: "Enable debug logging", @@ -146,6 +150,19 @@ func runNode(ctx context.Context, c *cli.Command) error { consulClient := infra.GetConsulClient(environment) keyinfoStore := keyinfo.NewStore(consulClient.KV()) + + // If --peers flag is provided, sync new peers from file to Consul + peersFile := c.String("peers") + if peersFile != "" { + filePeers, err := config.LoadPeersFromFile(peersFile) + if err != nil { + logger.Fatal("Failed to load peers from file", err) + } + if err := config.SyncPeersToConsul(consulClient.KV(), filePeers); err != nil { + logger.Fatal("Failed to sync peers to Consul", err) + } + } + peers := LoadPeersFromConsul(consulClient) nodeID := GetIDFromName(nodeName, peers) @@ -474,7 +491,7 @@ func NewConsulClient(addr string) *api.Client { func LoadPeersFromConsul(consulClient *api.Client) []config.Peer { // Create a Consul Key-Value store client kv := consulClient.KV() - peers, err := config.LoadPeersFromConsul(kv, "mpc_peers/") + peers, err := config.LoadPeersFromConsul(kv, config.PeersPrefix) if err != nil { logger.Fatal("Failed to load peers from Consul", err) } diff --git a/pkg/config/peers.go b/pkg/config/peers.go index 34b87db..cec2290 100644 --- a/pkg/config/peers.go +++ b/pkg/config/peers.go @@ -1,7 +1,9 @@ package config import ( + "encoding/json" "fmt" + "os" "github.com/hashicorp/consul/api" ) @@ -33,6 +35,60 @@ func LoadPeersFromConsul(kv *api.KV, prefix string) ([]Peer, error) { return peers, nil } +// LoadPeersFromFile loads peers from a JSON file (map[string]string: name -> ID) +func LoadPeersFromFile(path string) ([]Peer, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to read peers file: %w", err) + } + + var peersMap map[string]string + if err := json.Unmarshal(data, &peersMap); err != nil { + return nil, fmt.Errorf("failed to parse peers JSON: %w", err) + } + + if len(peersMap) == 0 { + return nil, fmt.Errorf("no peers found in file %s", path) + } + + peers := make([]Peer, 0, len(peersMap)) + for name, id := range peersMap { + peers = append(peers, Peer{ + ID: id, + Name: name, + }) + } + + return peers, nil +} + +const PeersPrefix = "mpc_peers/" + +// SyncPeersToConsul registers new peers from a file into Consul. +// Existing peers are skipped. New peers are registered and logged. +func SyncPeersToConsul(kv *api.KV, peers []Peer) error { + for _, peer := range peers { + key := PeersPrefix + peer.Name + + existing, _, err := kv.Get(key, nil) + if err != nil { + return fmt.Errorf("failed to check existing key %s: %w", key, err) + } + + if existing != nil { + continue + } + + p := &api.KVPair{Key: key, Value: []byte(peer.ID)} + if _, err := kv.Put(p, nil); err != nil { + return fmt.Errorf("failed to register peer %s in Consul: %w", peer.Name, err) + } + fmt.Printf("New peer registered: %s with ID %s\n", peer.Name, peer.ID) + } + + return nil +} + func GetNodeID(nodeName string, peers []Peer) string { for _, peer := range peers { if peer.Name == nodeName {