mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-11 10:18:50 +00:00
refactor: reorder production installation phases and enhance service initialization
- Adjusted the installation sequence to generate secrets before initializing services, ensuring necessary keys are in place. - Updated service initialization to account for both bootstrap and node variants, improving service status reporting. - Enhanced error handling during IPFS repo and cluster path initialization, providing clearer feedback on failures. - Captured the node peer ID for logging after secret generation, improving visibility during production setup.
This commit is contained in:
parent
6a86592cad
commit
17fc78975d
16
CHANGELOG.md
16
CHANGELOG.md
@ -13,6 +13,22 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant
|
||||
### Deprecated
|
||||
|
||||
### Fixed
|
||||
## [0.62.0] - 2025-11-10
|
||||
|
||||
### Added
|
||||
- The `prod status` command now correctly checks for both 'bootstrap' and 'node' service variants.
|
||||
|
||||
### Changed
|
||||
- The production installation process now generates secrets (like the cluster secret and peer ID) before initializing services. This ensures all necessary secrets are available when services start.
|
||||
- The `prod install` command now displays the actual Peer ID upon completion instead of a placeholder.
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
|
||||
### Fixed
|
||||
- Fixed an issue where IPFS Cluster initialization was using a hardcoded configuration file instead of relying on the standard `ipfs-cluster-service init` process.
|
||||
|
||||
## [0.61.0] - 2025-11-10
|
||||
|
||||
### Added
|
||||
|
||||
2
Makefile
2
Makefile
@ -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 install-hooks kill
|
||||
|
||||
VERSION := 0.61.0
|
||||
VERSION := 0.62.0
|
||||
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
||||
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)'
|
||||
|
||||
@ -128,24 +128,27 @@ func handleProdInstall(args []string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Phase 2c: Initialize services
|
||||
// Determine node type early
|
||||
nodeType := "node"
|
||||
if isBootstrap {
|
||||
nodeType = "bootstrap"
|
||||
}
|
||||
fmt.Printf("\nPhase 2c: Initializing services...\n")
|
||||
if err := setup.Phase2cInitializeServices(nodeType); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ Service initialization failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Phase 3: Generate secrets
|
||||
// Phase 3: Generate secrets FIRST (before service initialization)
|
||||
// This ensures cluster secret and swarm key exist before repos are seeded
|
||||
fmt.Printf("\n🔐 Phase 3: Generating secrets...\n")
|
||||
if err := setup.Phase3GenerateSecrets(isBootstrap); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ Secret generation failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Phase 2c: Initialize services (after secrets are in place)
|
||||
fmt.Printf("\nPhase 2c: Initializing services...\n")
|
||||
if err := setup.Phase2cInitializeServices(nodeType); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ Service initialization failed: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Phase 4: Generate configs
|
||||
fmt.Printf("\n⚙️ Phase 4: Generating configurations...\n")
|
||||
enableHTTPS := domain != ""
|
||||
@ -161,8 +164,8 @@ func handleProdInstall(args []string) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Log completion
|
||||
setup.LogSetupComplete("< peer ID from config >")
|
||||
// Log completion with actual peer ID
|
||||
setup.LogSetupComplete(setup.NodePeerID)
|
||||
fmt.Printf("✅ Production installation complete!\n\n")
|
||||
}
|
||||
|
||||
@ -205,27 +208,49 @@ func handleProdUpgrade(args []string) {
|
||||
func handleProdStatus() {
|
||||
fmt.Printf("Production Environment Status\n\n")
|
||||
|
||||
servicesList := []struct {
|
||||
name string
|
||||
desc string
|
||||
}{
|
||||
{"debros-ipfs-bootstrap", "IPFS Daemon (Bootstrap)"},
|
||||
{"debros-ipfs-cluster-bootstrap", "IPFS Cluster (Bootstrap)"},
|
||||
{"debros-rqlite-bootstrap", "RQLite Database (Bootstrap)"},
|
||||
{"debros-olric", "Olric Cache Server"},
|
||||
{"debros-node-bootstrap", "DeBros Node (Bootstrap)"},
|
||||
{"debros-gateway", "DeBros Gateway"},
|
||||
// Check for all possible service names (bootstrap and node variants)
|
||||
serviceNames := []string{
|
||||
"debros-ipfs-bootstrap",
|
||||
"debros-ipfs-node",
|
||||
"debros-ipfs-cluster-bootstrap",
|
||||
"debros-ipfs-cluster-node",
|
||||
"debros-rqlite-bootstrap",
|
||||
"debros-rqlite-node",
|
||||
"debros-olric",
|
||||
"debros-node-bootstrap",
|
||||
"debros-node-node",
|
||||
"debros-gateway",
|
||||
}
|
||||
|
||||
// Friendly descriptions
|
||||
descriptions := map[string]string{
|
||||
"debros-ipfs-bootstrap": "IPFS Daemon (Bootstrap)",
|
||||
"debros-ipfs-node": "IPFS Daemon (Node)",
|
||||
"debros-ipfs-cluster-bootstrap": "IPFS Cluster (Bootstrap)",
|
||||
"debros-ipfs-cluster-node": "IPFS Cluster (Node)",
|
||||
"debros-rqlite-bootstrap": "RQLite Database (Bootstrap)",
|
||||
"debros-rqlite-node": "RQLite Database (Node)",
|
||||
"debros-olric": "Olric Cache Server",
|
||||
"debros-node-bootstrap": "DeBros Node (Bootstrap)",
|
||||
"debros-node-node": "DeBros Node (Node)",
|
||||
"debros-gateway": "DeBros Gateway",
|
||||
}
|
||||
|
||||
fmt.Printf("Services:\n")
|
||||
for _, svc := range servicesList {
|
||||
cmd := "systemctl"
|
||||
err := exec.Command(cmd, "is-active", "--quiet", svc.name).Run()
|
||||
found := false
|
||||
for _, svc := range serviceNames {
|
||||
cmd := exec.Command("systemctl", "is-active", "--quiet", svc)
|
||||
err := cmd.Run()
|
||||
status := "❌ Inactive"
|
||||
if err == nil {
|
||||
status = "✅ Active"
|
||||
found = true
|
||||
}
|
||||
fmt.Printf(" %s: %s\n", status, svc.desc)
|
||||
fmt.Printf(" %s: %s\n", status, descriptions[svc])
|
||||
}
|
||||
|
||||
if !found {
|
||||
fmt.Printf(" (No services found - installation may be incomplete)\n")
|
||||
}
|
||||
|
||||
fmt.Printf("\nDirectories:\n")
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BinaryInstaller handles downloading and installing external binaries
|
||||
@ -227,9 +226,11 @@ func (bi *BinaryInstaller) InitializeIPFSRepo(nodeType, ipfsRepoPath string, swa
|
||||
|
||||
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Initializing IPFS repo for %s...\n", nodeType)
|
||||
|
||||
os.MkdirAll(ipfsRepoPath, 0755)
|
||||
if err := os.MkdirAll(ipfsRepoPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create IPFS repo directory: %w", err)
|
||||
}
|
||||
|
||||
// Initialize IPFS
|
||||
// Initialize IPFS with the correct repo path
|
||||
cmd := exec.Command("ipfs", "init", "--profile=server", "--repo-dir="+ipfsRepoPath)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to initialize IPFS: %v\n%s", err, string(output))
|
||||
@ -237,13 +238,20 @@ func (bi *BinaryInstaller) InitializeIPFSRepo(nodeType, ipfsRepoPath string, swa
|
||||
|
||||
// Copy swarm key if present
|
||||
if data, err := os.ReadFile(swarmKeyPath); err == nil {
|
||||
os.WriteFile(filepath.Join(ipfsRepoPath, "swarm.key"), data, 0600)
|
||||
if err := os.WriteFile(filepath.Join(ipfsRepoPath, "swarm.key"), data, 0600); err != nil {
|
||||
return fmt.Errorf("failed to copy swarm key: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Fix ownership
|
||||
exec.Command("chown", "-R", "debros:debros", ipfsRepoPath).Run()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeIPFSClusterConfig initializes IPFS Cluster configuration
|
||||
// Note: This is a placeholder config. The full initialization will occur via `ipfs-cluster-service init`
|
||||
// which is run during Phase2cInitializeServices with the IPFS_CLUSTER_PATH env var set.
|
||||
func (bi *BinaryInstaller) InitializeIPFSClusterConfig(nodeType, clusterPath, clusterSecret string, ipfsAPIPort int) error {
|
||||
serviceJSONPath := filepath.Join(clusterPath, "service.json")
|
||||
if _, err := os.Stat(serviceJSONPath); err == nil {
|
||||
@ -251,43 +259,10 @@ func (bi *BinaryInstaller) InitializeIPFSClusterConfig(nodeType, clusterPath, cl
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Initializing IPFS Cluster config for %s...\n", nodeType)
|
||||
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Preparing IPFS Cluster path for %s...\n", nodeType)
|
||||
|
||||
os.MkdirAll(clusterPath, 0755)
|
||||
|
||||
// For now, just create a minimal service.json
|
||||
// This will be properly configured during service startup
|
||||
cfgContent := fmt.Sprintf(`{
|
||||
"cluster": {
|
||||
"peername": "%s",
|
||||
"secret": "%s",
|
||||
"listen_multiaddress": ["/ip4/0.0.0.0/tcp/9096"],
|
||||
"leave_on_shutdown": false
|
||||
},
|
||||
"api": {
|
||||
"restapi": {
|
||||
"http_listen_multiaddress": "/ip4/0.0.0.0/tcp/9094"
|
||||
}
|
||||
},
|
||||
"ipfs_connector": {
|
||||
"ipfshttp": {
|
||||
"node_multiaddress": "/ip4/127.0.0.1/tcp/%d"
|
||||
}
|
||||
},
|
||||
"consensus": {
|
||||
"crdt": {
|
||||
"cluster_name": "debros",
|
||||
"trusted_peers": ["*"]
|
||||
}
|
||||
},
|
||||
"datastore": {
|
||||
"type": "badger",
|
||||
"path": "%s/badger"
|
||||
}
|
||||
}`, nodeType, strings.TrimSpace(clusterSecret), ipfsAPIPort, clusterPath)
|
||||
|
||||
if err := os.WriteFile(serviceJSONPath, []byte(cfgContent), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write cluster config: %w", err)
|
||||
if err := os.MkdirAll(clusterPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create IPFS Cluster directory: %w", err)
|
||||
}
|
||||
|
||||
exec.Command("chown", "-R", "debros:debros", clusterPath).Run()
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -29,6 +30,7 @@ type ProductionSetup struct {
|
||||
serviceController *SystemdController
|
||||
binaryInstaller *BinaryInstaller
|
||||
branch string
|
||||
NodePeerID string // Captured during Phase3 for later display
|
||||
}
|
||||
|
||||
// NewProductionSetup creates a new production setup orchestrator
|
||||
@ -199,27 +201,23 @@ func (ps *ProductionSetup) Phase2bInstallBinaries() error {
|
||||
func (ps *ProductionSetup) Phase2cInitializeServices(nodeType string) error {
|
||||
ps.logf("Phase 2c: Initializing services...")
|
||||
|
||||
// Get cluster secret for IPFS
|
||||
clusterSecret, err := os.ReadFile(ps.debrosDir + "/secrets/cluster-secret")
|
||||
if err != nil {
|
||||
clusterSecret = []byte("")
|
||||
}
|
||||
// Build paths with nodeType awareness to match systemd unit definitions
|
||||
dataDir := filepath.Join(ps.debrosDir, "data", nodeType)
|
||||
|
||||
// Initialize IPFS repo
|
||||
ipfsRepoPath := ps.debrosDir + "/data/ipfs"
|
||||
if err := ps.binaryInstaller.InitializeIPFSRepo(nodeType, ipfsRepoPath, ps.debrosDir+"/secrets/swarm.key"); err != nil {
|
||||
// Initialize IPFS repo with correct path structure
|
||||
ipfsRepoPath := filepath.Join(dataDir, "ipfs", "repo")
|
||||
if err := ps.binaryInstaller.InitializeIPFSRepo(nodeType, ipfsRepoPath, filepath.Join(ps.debrosDir, "secrets", "swarm.key")); err != nil {
|
||||
ps.logf(" ⚠️ IPFS initialization warning: %v", err)
|
||||
}
|
||||
|
||||
// Initialize IPFS Cluster config
|
||||
clusterPath := ps.debrosDir + "/data/ipfs-cluster"
|
||||
ipfsAPIPort := 4501
|
||||
if err := ps.binaryInstaller.InitializeIPFSClusterConfig(nodeType, clusterPath, string(clusterSecret), ipfsAPIPort); err != nil {
|
||||
// Initialize IPFS Cluster path (just ensure directory exists, actual init happens in daemon startup)
|
||||
clusterPath := filepath.Join(dataDir, "ipfs-cluster")
|
||||
if err := ps.binaryInstaller.InitializeIPFSClusterConfig(nodeType, clusterPath, "", 4501); err != nil {
|
||||
ps.logf(" ⚠️ IPFS Cluster initialization warning: %v", err)
|
||||
}
|
||||
|
||||
// Initialize RQLite data directory
|
||||
rqliteDataDir := ps.debrosDir + "/data/rqlite"
|
||||
rqliteDataDir := filepath.Join(dataDir, "rqlite")
|
||||
if err := ps.binaryInstaller.InitializeRQLiteDataDir(nodeType, rqliteDataDir); err != nil {
|
||||
ps.logf(" ⚠️ RQLite initialization warning: %v", err)
|
||||
}
|
||||
@ -254,7 +252,9 @@ func (ps *ProductionSetup) Phase3GenerateSecrets(isBootstrap bool) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to ensure node identity: %w", err)
|
||||
}
|
||||
ps.logf(" ✓ Node identity ensured (Peer ID: %s)", peerID.String())
|
||||
peerIDStr := peerID.String()
|
||||
ps.NodePeerID = peerIDStr // Capture for later display
|
||||
ps.logf(" ✓ Node identity ensured (Peer ID: %s)", peerIDStr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -81,8 +81,8 @@ User=debros
|
||||
Group=debros
|
||||
WorkingDirectory=%s
|
||||
Environment=HOME=%s
|
||||
Environment=CLUSTER_PATH=%s
|
||||
ExecStart=/usr/local/bin/ipfs-cluster-service daemon --config %s/service.json
|
||||
Environment=IPFS_CLUSTER_PATH=%s
|
||||
ExecStart=/usr/local/bin/ipfs-cluster-service daemon
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
@ -96,7 +96,7 @@ ReadWritePaths=%s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`, nodeType, nodeType, nodeType, nodeType, ssg.debrosHome, ssg.debrosHome, clusterPath, clusterPath, nodeType, ssg.debrosDir)
|
||||
`, nodeType, nodeType, nodeType, nodeType, ssg.debrosHome, ssg.debrosHome, clusterPath, nodeType, ssg.debrosDir)
|
||||
}
|
||||
|
||||
// GenerateRQLiteService generates the RQLite systemd unit
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user