chore: update version to 0.53.5 in Makefile and enhance setup command with peer ID retrieval and VPS IPv4 detection

This commit is contained in:
anonpenguin23 2025-10-31 14:50:20 +02:00
parent 168808b007
commit 042e516b8c
2 changed files with 294 additions and 86 deletions

View File

@ -21,7 +21,7 @@ test-e2e:
.PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports .PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports
VERSION := 0.53.3 VERSION := 0.53.5
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)' LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)'

View File

@ -3,12 +3,16 @@ package cli
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"net"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/DeBrosOfficial/network/pkg/config"
) )
// HandleSetupCommand handles the interactive 'setup' command for VPS installation // HandleSetupCommand handles the interactive 'setup' command for VPS installation
@ -108,6 +112,13 @@ func HandleSetupCommand(args []string) {
fmt.Printf("✅ Setup Complete!\n") fmt.Printf("✅ Setup Complete!\n")
fmt.Printf(strings.Repeat("=", 70) + "\n\n") fmt.Printf(strings.Repeat("=", 70) + "\n\n")
fmt.Printf("DeBros Network is now running!\n\n") fmt.Printf("DeBros Network is now running!\n\n")
// Try to get and display peer ID
peerID := getPeerID()
if peerID != "" {
fmt.Printf("🆔 Node Peer ID: %s\n\n", peerID)
}
fmt.Printf("Service Management:\n") fmt.Printf("Service Management:\n")
fmt.Printf(" network-cli service status all\n") fmt.Printf(" network-cli service status all\n")
fmt.Printf(" network-cli service logs node --follow\n") fmt.Printf(" network-cli service logs node --follow\n")
@ -123,6 +134,84 @@ func HandleSetupCommand(args []string) {
fmt.Printf(" Proxy endpoint: POST http://localhost:6001/v1/proxy/anon\n\n") fmt.Printf(" Proxy endpoint: POST http://localhost:6001/v1/proxy/anon\n\n")
} }
// getVPSIPv4Address gets the primary IPv4 address of the VPS
func getVPSIPv4Address() (string, error) {
interfaces, err := net.Interfaces()
if err != nil {
return "", err
}
for _, iface := range interfaces {
// Skip loopback and down interfaces
if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok {
continue
}
ip := ipNet.IP
// Check if it's IPv4 and not a loopback address
if ip.To4() != nil && !ip.IsLoopback() {
return ip.String(), nil
}
}
}
return "", fmt.Errorf("could not find a non-loopback IPv4 address")
}
// getPeerID attempts to retrieve the peer ID from peer.info based on node type
func getPeerID() string {
debrosDir := "/home/debros/.debros"
nodeConfigPath := filepath.Join(debrosDir, "node.yaml")
// Determine node type from config
var nodeType string
if file, err := os.Open(nodeConfigPath); err == nil {
defer file.Close()
var cfg config.Config
if err := config.DecodeStrict(file, &cfg); err == nil {
nodeType = cfg.Node.Type
}
}
// Determine the peer.info path based on node type
var peerInfoPath string
if nodeType == "bootstrap" {
peerInfoPath = filepath.Join(debrosDir, "bootstrap", "peer.info")
} else {
// Default to "node" directory for regular nodes
peerInfoPath = filepath.Join(debrosDir, "node", "peer.info")
}
// Try to read from peer.info file
if data, err := os.ReadFile(peerInfoPath); err == nil {
peerInfo := strings.TrimSpace(string(data))
// Extract peer ID from multiaddr format: /ip4/.../p2p/<peer-id>
if strings.Contains(peerInfo, "/p2p/") {
parts := strings.Split(peerInfo, "/p2p/")
if len(parts) == 2 {
return strings.TrimSpace(parts[1])
}
}
// If it's just the peer ID, return it
if len(peerInfo) > 0 && !strings.Contains(peerInfo, "/") {
return peerInfo
}
}
return ""
}
func detectLinuxDistro() string { func detectLinuxDistro() string {
if data, err := os.ReadFile("/etc/os-release"); err == nil { if data, err := os.ReadFile("/etc/os-release"); err == nil {
lines := strings.Split(string(data), "\n") lines := strings.Split(string(data), "\n")
@ -763,17 +852,40 @@ func cloneAndBuild() {
} }
func generateConfigsInteractive(force bool) { func generateConfigsInteractive(force bool) {
fmt.Printf("⚙️ Generating configurations...\n") fmt.Printf("⚙️ Generating configurations...\n\n")
// For single-node VPS setup, use sensible defaults // Get VPS IPv4 address
// This creates a bootstrap node that acts as the cluster leader fmt.Printf("Detecting VPS IPv4 address...\n")
fmt.Printf("\n") vpsIP, err := getVPSIPv4Address()
fmt.Printf("Setting up single-node configuration...\n") if err != nil {
fmt.Printf(" • Bootstrap node (cluster leader)\n") fmt.Fprintf(os.Stderr, "⚠️ Failed to detect IPv4 address: %v\n", err)
fmt.Printf(" • No external peers required\n") fmt.Fprintf(os.Stderr, " Using 0.0.0.0 as fallback. You may need to edit config files manually.\n")
fmt.Printf(" • Gateway connected to local node\n\n") vpsIP = "0.0.0.0"
} else {
fmt.Printf(" ✓ Detected IPv4 address: %s\n\n", vpsIP)
}
// Ask about node type
fmt.Printf("What type of node is this?\n")
fmt.Printf(" 1. Bootstrap node (cluster leader)\n")
fmt.Printf(" 2. Regular node (joins existing cluster)\n")
fmt.Printf("Enter choice (1 or 2): ")
reader := bufio.NewReader(os.Stdin)
choice, _ := reader.ReadString('\n')
choice = strings.ToLower(strings.TrimSpace(choice))
isBootstrap := choice == "1" || choice == "bootstrap" || choice == "b"
var bootstrapPeers string
if !isBootstrap {
// Ask for bootstrap peer multiaddr
fmt.Printf("\nEnter bootstrap peer multiaddr(s) (comma-separated if multiple):\n")
fmt.Printf("Example: /ip4/192.168.1.100/tcp/4001/p2p/12D3KooW...\n")
fmt.Printf("Bootstrap peer(s): ")
bootstrapPeers, _ = reader.ReadString('\n')
bootstrapPeers = strings.TrimSpace(bootstrapPeers)
}
bootstrapPath := "/home/debros/.debros/bootstrap.yaml"
nodeConfigPath := "/home/debros/.debros/node.yaml" nodeConfigPath := "/home/debros/.debros/node.yaml"
gatewayPath := "/home/debros/.debros/gateway.yaml" gatewayPath := "/home/debros/.debros/gateway.yaml"
@ -781,65 +893,31 @@ func generateConfigsInteractive(force bool) {
nodeExists := false nodeExists := false
if _, err := os.Stat(nodeConfigPath); err == nil { if _, err := os.Stat(nodeConfigPath); err == nil {
nodeExists = true nodeExists = true
fmt.Printf(" node.yaml already exists, will not overwrite\n") if !force {
fmt.Printf("\n node.yaml already exists, will not overwrite\n")
}
} }
// Generate bootstrap node config with explicit parameters // Generate node config
// Pass empty bootstrap-peers and no join address for bootstrap node if !nodeExists || force {
bootstrapArgs := []string{ var nodeConfig string
"-u", "debros", if isBootstrap {
"/home/debros/bin/network-cli", "config", "init", nodeConfig = generateBootstrapConfigWithIP("bootstrap", "", 4001, 5001, 7001, vpsIP)
"--type", "bootstrap",
"--bootstrap-peers", "",
}
if force {
bootstrapArgs = append(bootstrapArgs, "--force")
}
cmd := exec.Command("sudo", bootstrapArgs...)
cmd.Stdin = nil // Explicitly close stdin to prevent interactive prompts
output, err := cmd.CombinedOutput()
bootstrapCreated := (err == nil)
if err != nil {
// Check if bootstrap.yaml already exists (config init failed because it exists)
if _, statErr := os.Stat(bootstrapPath); statErr == nil {
fmt.Printf(" bootstrap.yaml already exists, skipping creation\n")
bootstrapCreated = true
} else { } else {
fmt.Fprintf(os.Stderr, "⚠️ Failed to generate bootstrap config: %v\n", err) nodeConfig = generateNodeConfigWithIP("node", "", 4001, 5001, 7001, "", bootstrapPeers, vpsIP)
if len(output) > 0 {
fmt.Fprintf(os.Stderr, " Output: %s\n", string(output))
}
} }
} else {
fmt.Printf(" ✓ Bootstrap node config created\n") // Write node config
if err := os.WriteFile(nodeConfigPath, []byte(nodeConfig), 0644); err != nil {
fmt.Fprintf(os.Stderr, "❌ Failed to write node config: %v\n", err)
os.Exit(1)
}
// Fix ownership
exec.Command("chown", "debros:debros", nodeConfigPath).Run()
fmt.Printf(" ✓ Node config created: %s\n", nodeConfigPath)
} }
// Rename bootstrap.yaml to node.yaml only if node.yaml doesn't exist // Generate gateway config
if !nodeExists && bootstrapCreated {
// Check if bootstrap.yaml exists before renaming
if _, err := os.Stat(bootstrapPath); err == nil {
renameCmd := exec.Command("sudo", "-u", "debros", "mv", bootstrapPath, nodeConfigPath)
if err := renameCmd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "⚠️ Failed to rename config: %v\n", err)
} else {
fmt.Printf(" ✓ Renamed bootstrap.yaml to node.yaml\n")
}
}
} else if nodeExists {
// If node.yaml exists, we can optionally remove bootstrap.yaml if it was just created
if bootstrapCreated && !force {
// Clean up bootstrap.yaml if it was just created but node.yaml already exists
if _, err := os.Stat(bootstrapPath); err == nil {
exec.Command("sudo", "-u", "debros", "rm", "-f", bootstrapPath).Run()
}
}
fmt.Printf(" Using existing node.yaml\n")
}
// Generate gateway config with explicit empty bootstrap peers
// Check if gateway.yaml already exists
gatewayExists := false gatewayExists := false
if _, err := os.Stat(gatewayPath); err == nil { if _, err := os.Stat(gatewayPath); err == nil {
gatewayExists = true gatewayExists = true
@ -849,35 +927,165 @@ func generateConfigsInteractive(force bool) {
} }
if !gatewayExists || force { if !gatewayExists || force {
gatewayArgs := []string{ // Gateway config should include bootstrap peers if this is a regular node
"-u", "debros", // (bootstrap nodes don't need bootstrap peers since they are the bootstrap)
"/home/debros/bin/network-cli", "config", "init", gatewayConfig := generateGatewayConfigDirect(bootstrapPeers)
"--type", "gateway", if err := os.WriteFile(gatewayPath, []byte(gatewayConfig), 0644); err != nil {
"--bootstrap-peers", "", fmt.Fprintf(os.Stderr, "❌ Failed to write gateway config: %v\n", err)
} os.Exit(1)
if force {
gatewayArgs = append(gatewayArgs, "--force")
} }
// Fix ownership
exec.Command("chown", "debros:debros", gatewayPath).Run()
fmt.Printf(" ✓ Gateway config created: %s\n", gatewayPath)
}
cmd = exec.Command("sudo", gatewayArgs...) fmt.Printf("\n ✓ Configurations ready\n")
cmd.Stdin = nil // Explicitly close stdin to prevent interactive prompts }
output, err = cmd.CombinedOutput()
if err != nil { // generateBootstrapConfigWithIP generates a bootstrap config with actual IP address
// Check if gateway.yaml already exists (config init failed because it exists) func generateBootstrapConfigWithIP(name, id string, listenPort, rqliteHTTPPort, rqliteRaftPort int, ipAddr string) string {
if _, statErr := os.Stat(gatewayPath); statErr == nil { nodeID := id
fmt.Printf(" gateway.yaml already exists, skipping creation\n") if nodeID == "" {
} else { nodeID = "bootstrap"
fmt.Fprintf(os.Stderr, "⚠️ Failed to generate gateway config: %v\n", err) }
if len(output) > 0 {
fmt.Fprintf(os.Stderr, " Output: %s\n", string(output)) dataDir := "/home/debros/.debros/bootstrap"
}
return fmt.Sprintf(`node:
id: "%s"
type: "bootstrap"
listen_addresses:
- "/ip4/%s/tcp/%d"
data_dir: "%s"
max_connections: 50
database:
data_dir: "%s/rqlite"
replication_factor: 3
shard_count: 16
max_database_size: 1073741824
backup_interval: "24h"
rqlite_port: %d
rqlite_raft_port: %d
rqlite_join_address: ""
cluster_sync_interval: "30s"
peer_inactivity_limit: "24h"
min_cluster_size: 1
discovery:
bootstrap_peers: []
discovery_interval: "15s"
bootstrap_port: %d
http_adv_address: "%s:%d"
raft_adv_address: "%s:%d"
node_namespace: "default"
security:
enable_tls: false
logging:
level: "info"
format: "console"
`, nodeID, ipAddr, listenPort, dataDir, dataDir, rqliteHTTPPort, rqliteRaftPort, 4001, ipAddr, rqliteHTTPPort, ipAddr, rqliteRaftPort)
}
// generateNodeConfigWithIP generates a node config with actual IP address
func generateNodeConfigWithIP(name, id string, listenPort, rqliteHTTPPort, rqliteRaftPort int, joinAddr, bootstrapPeers, ipAddr string) string {
nodeID := id
if nodeID == "" {
nodeID = fmt.Sprintf("node-%d", time.Now().Unix())
}
dataDir := "/home/debros/.debros/node"
// Parse bootstrap peers
var peers []string
if bootstrapPeers != "" {
for _, p := range strings.Split(bootstrapPeers, ",") {
if p = strings.TrimSpace(p); p != "" {
peers = append(peers, p)
} }
} else {
fmt.Printf(" ✓ Gateway config created\n")
} }
} }
fmt.Printf(" ✓ Configurations ready\n") var peersYAML strings.Builder
if len(peers) == 0 {
peersYAML.WriteString(" bootstrap_peers: []")
} else {
peersYAML.WriteString(" bootstrap_peers:\n")
for _, p := range peers {
fmt.Fprintf(&peersYAML, " - \"%s\"\n", p)
}
}
if joinAddr == "" {
joinAddr = "localhost:5001"
}
return fmt.Sprintf(`node:
id: "%s"
type: "node"
listen_addresses:
- "/ip4/%s/tcp/%d"
data_dir: "%s"
max_connections: 50
database:
data_dir: "%s/rqlite"
replication_factor: 3
shard_count: 16
max_database_size: 1073741824
backup_interval: "24h"
rqlite_port: %d
rqlite_raft_port: %d
rqlite_join_address: "%s"
cluster_sync_interval: "30s"
peer_inactivity_limit: "24h"
min_cluster_size: 1
discovery:
%s
discovery_interval: "15s"
bootstrap_port: %d
http_adv_address: "%s:%d"
raft_adv_address: "%s:%d"
node_namespace: "default"
security:
enable_tls: false
logging:
level: "info"
format: "console"
`, nodeID, ipAddr, listenPort, dataDir, dataDir, rqliteHTTPPort, rqliteRaftPort, joinAddr, peersYAML.String(), 4001, ipAddr, rqliteHTTPPort, ipAddr, rqliteRaftPort)
}
// generateGatewayConfigDirect generates gateway config directly
func generateGatewayConfigDirect(bootstrapPeers string) string {
var peers []string
if bootstrapPeers != "" {
for _, p := range strings.Split(bootstrapPeers, ",") {
if p = strings.TrimSpace(p); p != "" {
peers = append(peers, p)
}
}
}
var peersYAML strings.Builder
if len(peers) == 0 {
peersYAML.WriteString("bootstrap_peers: []")
} else {
peersYAML.WriteString("bootstrap_peers:\n")
for _, p := range peers {
fmt.Fprintf(&peersYAML, " - \"%s\"\n", p)
}
}
return fmt.Sprintf(`listen_addr: ":6001"
client_namespace: "default"
rqlite_dsn: ""
%s
`, peersYAML.String())
} }
func createSystemdServices() { func createSystemdServices() {