mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-12 22:38:50 +00:00
Merge branch 'main' into nightly
This commit is contained in:
commit
5939cf413e
2
.gitignore
vendored
2
.gitignore
vendored
@ -73,3 +73,5 @@ data/bootstrap/rqlite/
|
||||
.env.*
|
||||
|
||||
configs/
|
||||
|
||||
.dev/
|
||||
24
CHANGELOG.md
24
CHANGELOG.md
@ -8,14 +8,38 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant
|
||||
|
||||
### Added
|
||||
|
||||
- One-command `make dev` target to start full development stack (bootstrap + node2 + node3 + gateway in background)
|
||||
- New `network-cli config init` (no --type) generates complete development stack with all configs and identities
|
||||
- Full stack initialization with auto-generated peer identities for bootstrap and all nodes
|
||||
- Explicit control over LibP2P listen addresses for better localhost/development support
|
||||
- Production/development mode detection for NAT services (disabled for localhost, enabled for production)
|
||||
- Process management with .dev/pids directory for background process tracking
|
||||
- Centralized logging to ~/.debros/logs/ for all network services
|
||||
|
||||
### Changed
|
||||
|
||||
- Simplified Makefile: removed legacy dev commands, replaced with unified `make dev` target
|
||||
- Updated README with clearer getting started instructions (single `make dev` command)
|
||||
- Simplified `network-cli config init` behavior: defaults to generating full stack instead of single node
|
||||
- `network-cli config init` now handles bootstrap peer discovery and join addresses automatically
|
||||
- LibP2P configuration: removed always-on NAT services for development environments
|
||||
- Code formatting in pkg/node/node.go (indentation fixes in bootstrapPeerSource)
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed legacy Makefile targets: run-example, show-bootstrap, run-cli, cli-health, cli-peers, cli-status, cli-storage-test, cli-pubsub-test
|
||||
- Removed verbose dev-setup, dev-cluster, and old dev workflow targets
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed indentation in bootstrapPeerSource function for consistency
|
||||
- Fixed gateway.yaml generation with correct YAML indentation for bootstrap_peers
|
||||
- Fixed script for running and added gateway running as well
|
||||
|
||||
### Security
|
||||
|
||||
## [0.51.6] - 2025-10-24
|
||||
|
||||
### Added
|
||||
|
||||
145
Makefile
145
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
|
||||
|
||||
VERSION := 0.51.6-beta
|
||||
VERSION := 0.51.7-beta
|
||||
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)'
|
||||
@ -77,110 +77,45 @@ run-gateway:
|
||||
@echo "Generate it with: network-cli config init --type gateway"
|
||||
go run ./cmd/gateway
|
||||
|
||||
# Run basic usage example
|
||||
run-example:
|
||||
@echo "Running basic usage example..."
|
||||
go run examples/basic_usage.go
|
||||
|
||||
# Show how to run with flags
|
||||
show-bootstrap:
|
||||
@echo "Provide join address via flags, e.g.:"
|
||||
@echo " make run-node2 JOINADDR=/ip4/127.0.0.1/tcp/5001 HTTP=5002 RAFT=7002 P2P=4002"
|
||||
|
||||
# Run network CLI
|
||||
run-cli:
|
||||
@echo "Running network CLI help..."
|
||||
./bin/network-cli help
|
||||
|
||||
# Network CLI helper commands
|
||||
cli-health:
|
||||
@echo "Checking network health..."
|
||||
./bin/network-cli health
|
||||
|
||||
cli-peers:
|
||||
@echo "Listing network peers..."
|
||||
./bin/network-cli peers
|
||||
|
||||
cli-status:
|
||||
@echo "Getting network status..."
|
||||
./bin/network-cli status
|
||||
|
||||
cli-storage-test:
|
||||
@echo "Testing storage operations..."
|
||||
@./bin/network-cli storage put test-key "Hello Network" || echo "Storage test requires running network"
|
||||
@./bin/network-cli storage get test-key || echo "Storage test requires running network"
|
||||
@./bin/network-cli storage list || echo "Storage test requires running network"
|
||||
|
||||
cli-pubsub-test:
|
||||
@echo "Testing pub/sub operations..."
|
||||
@./bin/network-cli pubsub publish test-topic "Hello World" || echo "PubSub test requires running network"
|
||||
@./bin/network-cli pubsub topics || echo "PubSub test requires running network"
|
||||
|
||||
# Download dependencies
|
||||
deps:
|
||||
@echo "Downloading dependencies..."
|
||||
go mod download
|
||||
|
||||
# Tidy dependencies
|
||||
tidy:
|
||||
@echo "Tidying dependencies..."
|
||||
go mod tidy
|
||||
|
||||
# Format code
|
||||
fmt:
|
||||
@echo "Formatting code..."
|
||||
go fmt ./...
|
||||
|
||||
# Vet code
|
||||
vet:
|
||||
@echo "Vetting code..."
|
||||
go vet ./...
|
||||
|
||||
# Lint alias (lightweight for now)
|
||||
lint: fmt vet
|
||||
@echo "Linting complete (fmt + vet)"
|
||||
|
||||
# Clear common development ports
|
||||
clear-ports:
|
||||
@echo "Clearing common dev ports (4001/4002, 5001/5002, 7001/7002)..."
|
||||
@chmod +x scripts/clear-ports.sh || true
|
||||
@scripts/clear-ports.sh
|
||||
|
||||
# Development setup
|
||||
dev-setup: deps
|
||||
@echo "Setting up development environment..."
|
||||
@mkdir -p data/bootstrap data/node data/node2 data/node3
|
||||
@mkdir -p data/test-bootstrap data/test-node1 data/test-node2
|
||||
@echo "Development setup complete!"
|
||||
|
||||
# Start development cluster (requires multiple terminals)
|
||||
dev-cluster:
|
||||
@echo "To start a development cluster with 3 nodes:"
|
||||
# One-command dev: Start bootstrap, node2, node3, and gateway in background
|
||||
# Requires: configs already exist in ~/.debros
|
||||
dev: build
|
||||
@echo "🚀 Starting development network stack..."
|
||||
@mkdir -p .dev/pids
|
||||
@mkdir -p $$HOME/.debros/logs
|
||||
@echo "Starting bootstrap node..."
|
||||
@nohup ./bin/node --config bootstrap.yaml > $$HOME/.debros/logs/bootstrap.log 2>&1 & echo $$! > .dev/pids/bootstrap.pid
|
||||
@sleep 2
|
||||
@echo "Starting node2..."
|
||||
@nohup ./bin/node --config node2.yaml > $$HOME/.debros/logs/node2.log 2>&1 & echo $$! > .dev/pids/node2.pid
|
||||
@sleep 1
|
||||
@echo "Starting node3..."
|
||||
@nohup ./bin/node --config node3.yaml > $$HOME/.debros/logs/node3.log 2>&1 & echo $$! > .dev/pids/node3.pid
|
||||
@sleep 1
|
||||
@echo "Starting gateway..."
|
||||
@nohup ./bin/gateway --config gateway.yaml > $$HOME/.debros/logs/gateway.log 2>&1 & echo $$! > .dev/pids/gateway.pid
|
||||
@echo ""
|
||||
@echo "1. Generate config files in ~/.debros:"
|
||||
@echo " make build"
|
||||
@echo " ./bin/network-cli config init --type bootstrap"
|
||||
@echo " ./bin/network-cli config init --type node --name node.yaml --bootstrap-peers '<bootstrap_peer_multiaddr>'"
|
||||
@echo " ./bin/network-cli config init --type node --name node2.yaml --bootstrap-peers '<bootstrap_peer_multiaddr>'"
|
||||
@echo "============================================================"
|
||||
@echo "✅ Development stack started!"
|
||||
@echo "============================================================"
|
||||
@echo ""
|
||||
@echo "2. Run in separate terminals:"
|
||||
@echo " Terminal 1: make run-node # Start bootstrap node (bootstrap.yaml)"
|
||||
@echo " Terminal 2: make run-node2 # Start node 1 (node.yaml)"
|
||||
@echo " Terminal 3: make run-node3 # Start node 2 (node2.yaml)"
|
||||
@echo " Terminal 4: make run-gateway # Start gateway"
|
||||
@echo "Processes:"
|
||||
@echo " Bootstrap: PID=$$(cat .dev/pids/bootstrap.pid)"
|
||||
@echo " Node2: PID=$$(cat .dev/pids/node2.pid)"
|
||||
@echo " Node3: PID=$$(cat .dev/pids/node3.pid)"
|
||||
@echo " Gateway: PID=$$(cat .dev/pids/gateway.pid)"
|
||||
@echo ""
|
||||
@echo "3. Or run custom node with any config file:"
|
||||
@echo " go run ./cmd/node --config custom-node.yaml"
|
||||
@echo "Ports:"
|
||||
@echo " Bootstrap P2P: 4001, HTTP: 5001, Raft: 7001"
|
||||
@echo " Node2 P2P: 4002, HTTP: 5002, Raft: 7002"
|
||||
@echo " Node3 P2P: 4003, HTTP: 5003, Raft: 7003"
|
||||
@echo " Gateway: 6001"
|
||||
@echo ""
|
||||
@echo "4. Test:"
|
||||
@echo " make cli-health # Check network health"
|
||||
@echo " make cli-peers # List peers"
|
||||
@echo " make cli-storage-test # Test storage"
|
||||
@echo " make cli-pubsub-test # Test messaging"
|
||||
|
||||
# Full development workflow
|
||||
dev: clean build test
|
||||
@echo "Development workflow complete!"
|
||||
@echo "Press Ctrl+C to stop all processes"
|
||||
@echo "============================================================"
|
||||
@echo ""
|
||||
@trap 'echo "Stopping all processes..."; kill $$(cat .dev/pids/*.pid) 2>/dev/null; rm -f .dev/pids/*.pid; exit 0' INT; \
|
||||
tail -f $$HOME/.debros/logs/bootstrap.log $$HOME/.debros/logs/node2.log $$HOME/.debros/logs/node3.log $$HOME/.debros/logs/gateway.log
|
||||
|
||||
# Help
|
||||
help:
|
||||
@ -189,12 +124,14 @@ help:
|
||||
@echo " clean - Clean build artifacts"
|
||||
@echo " test - Run tests"
|
||||
@echo ""
|
||||
@echo "Development:"
|
||||
@echo " dev - Start full dev stack (bootstrap + 2 nodes + gateway)"
|
||||
@echo " Requires: configs in ~/.debros (run 'network-cli config init' first)"
|
||||
@echo ""
|
||||
@echo "Configuration (NEW):"
|
||||
@echo " First, generate config files in ~/.debros with:"
|
||||
@echo " make build # Build CLI first"
|
||||
@echo " ./bin/network-cli config init --type bootstrap # Generate bootstrap config"
|
||||
@echo " ./bin/network-cli config init --type node --bootstrap-peers '<peer_multiaddr>'"
|
||||
@echo " ./bin/network-cli config init --type gateway"
|
||||
@echo " ./bin/network-cli config init # Generate full stack"
|
||||
@echo ""
|
||||
@echo "Network Targets (requires config files in ~/.debros):"
|
||||
@echo " run-node - Start bootstrap node"
|
||||
|
||||
126
README.md
126
README.md
@ -174,23 +174,36 @@ cd network
|
||||
make build
|
||||
```
|
||||
|
||||
### 3. Start a Bootstrap Node
|
||||
### 3. Generate Configuration Files
|
||||
|
||||
```bash
|
||||
make run-node
|
||||
# Or manually:
|
||||
go run ./cmd/node --config configs/node.yaml
|
||||
# Generate all configs (bootstrap, node2, node3, gateway) with one command
|
||||
./bin/network-cli config init
|
||||
```
|
||||
|
||||
### 4. Start Additional Nodes
|
||||
This creates:
|
||||
- `~/.debros/bootstrap.yaml` - Bootstrap node
|
||||
- `~/.debros/node2.yaml` - Regular node 2
|
||||
- `~/.debros/node3.yaml` - Regular node 3
|
||||
- `~/.debros/gateway.yaml` - HTTP Gateway
|
||||
|
||||
Plus auto-generated identities for each node.
|
||||
|
||||
### 4. Start the Complete Network Stack
|
||||
|
||||
```bash
|
||||
make run-node2
|
||||
# Or manually:
|
||||
go run ./cmd/node --config configs/node.yaml
|
||||
make dev
|
||||
```
|
||||
|
||||
### 5. Test with CLI
|
||||
This starts:
|
||||
- Bootstrap node (P2P: 4001, RQLite HTTP: 5001, Raft: 7001)
|
||||
- Node 2 (P2P: 4002, RQLite HTTP: 5002, Raft: 7002)
|
||||
- Node 3 (P2P: 4003, RQLite HTTP: 5003, Raft: 7003)
|
||||
- Gateway (HTTP: 6001)
|
||||
|
||||
Logs stream to terminal. Press **Ctrl+C** to stop all processes.
|
||||
|
||||
### 5. Test with CLI (in another terminal)
|
||||
|
||||
```bash
|
||||
./bin/network-cli health
|
||||
@ -261,100 +274,103 @@ The system will **only** load config from `~/.debros/` and will error if require
|
||||
|
||||
Use the `network-cli config init` command to generate configuration files:
|
||||
|
||||
#### Generate a Node Config
|
||||
### Generate Complete Stack (Recommended)
|
||||
|
||||
```bash
|
||||
# Generate bootstrap, node2, node3, and gateway configs in one command
|
||||
./bin/network-cli config init
|
||||
|
||||
# Force regenerate (overwrites existing configs)
|
||||
./bin/network-cli config init --force
|
||||
```
|
||||
|
||||
This is the **recommended way** to get started with a local development network.
|
||||
|
||||
### Generate Individual Configs (Advanced)
|
||||
|
||||
For custom setups or production deployments, you can generate individual configs:
|
||||
|
||||
#### Generate a Single Node Config
|
||||
|
||||
```bash
|
||||
# Generate basic node config with bootstrap peers
|
||||
network-cli config init --type node --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx,/ip4/127.0.0.1/tcp/4002/p2p/QmYyy"
|
||||
./bin/network-cli config init --type node --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
|
||||
# With custom ports
|
||||
network-cli config init --type node --name node2.yaml --listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 --join localhost:5001 --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
./bin/network-cli config init --type node --name node2.yaml \
|
||||
--listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 \
|
||||
--join localhost:5001 --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
|
||||
# Force overwrite existing config
|
||||
network-cli config init --type node --force
|
||||
./bin/network-cli config init --type node --force
|
||||
```
|
||||
|
||||
#### Generate a Bootstrap Node Config
|
||||
|
||||
```bash
|
||||
# Generate bootstrap node (no join address required)
|
||||
network-cli config init --type bootstrap
|
||||
./bin/network-cli config init --type bootstrap
|
||||
|
||||
# With custom ports
|
||||
network-cli config init --type bootstrap --listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001
|
||||
./bin/network-cli config init --type bootstrap --listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001
|
||||
```
|
||||
|
||||
#### Generate a Gateway Config
|
||||
|
||||
```bash
|
||||
# Generate gateway config
|
||||
network-cli config init --type gateway
|
||||
./bin/network-cli config init --type gateway
|
||||
|
||||
# With bootstrap peers
|
||||
network-cli config init --type gateway --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
./bin/network-cli config init --type gateway --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
```
|
||||
|
||||
### Running Multiple Nodes on the Same Machine
|
||||
### Running the Network
|
||||
|
||||
You can run multiple nodes on a single machine by creating separate configuration files and using the `--config` flag:
|
||||
|
||||
#### Create Multiple Node Configs
|
||||
Once configs are generated, start the complete stack with:
|
||||
|
||||
```bash
|
||||
# Node 1
|
||||
./bin/network-cli config init --type node --name node1.yaml \
|
||||
--listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
|
||||
# Node 2
|
||||
./bin/network-cli config init --type node --name node2.yaml \
|
||||
--listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 \
|
||||
--join localhost:5001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
|
||||
# Node 3
|
||||
./bin/network-cli config init --type node --name node3.yaml \
|
||||
--listen-port 4003 --rqlite-http-port 5003 --rqlite-raft-port 7003 \
|
||||
--join localhost:5001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
make dev
|
||||
```
|
||||
|
||||
#### Run Multiple Nodes in Separate Terminals
|
||||
Or start individual components (in separate terminals):
|
||||
|
||||
```bash
|
||||
# Terminal 1 - Bootstrap node
|
||||
go run ./cmd/node --config bootstrap.yaml
|
||||
|
||||
# Terminal 2 - Node 1
|
||||
go run ./cmd/node --config node1.yaml
|
||||
|
||||
# Terminal 3 - Node 2
|
||||
# Terminal 2 - Node 2
|
||||
go run ./cmd/node --config node2.yaml
|
||||
|
||||
# Terminal 4 - Node 3
|
||||
# Terminal 3 - Node 3
|
||||
go run ./cmd/node --config node3.yaml
|
||||
|
||||
# Terminal 4 - Gateway
|
||||
go run ./cmd/gateway --config gateway.yaml
|
||||
```
|
||||
|
||||
#### Or Use Makefile Targets
|
||||
### Running Multiple Nodes on the Same Machine
|
||||
|
||||
The default `make dev` creates a 3-node setup. For additional nodes, generate individual configs:
|
||||
|
||||
```bash
|
||||
# Terminal 1
|
||||
make run-node # Runs: go run ./cmd/node --config bootstrap.yaml
|
||||
# Generate additional node configs with unique ports
|
||||
./bin/network-cli config init --type node --name node4.yaml \
|
||||
--listen-port 4004 --rqlite-http-port 5004 --rqlite-raft-port 7004 \
|
||||
--join localhost:5001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
|
||||
# Terminal 2
|
||||
make run-node2 # Runs: go run ./cmd/node --config node.yaml
|
||||
|
||||
# Terminal 3
|
||||
make run-node3 # Runs: go run ./cmd/node --config node2.yaml
|
||||
# Start the additional node
|
||||
go run ./cmd/node --config node4.yaml
|
||||
```
|
||||
|
||||
#### Key Points for Multiple Nodes
|
||||
|
||||
- **Each node needs unique ports**: P2P port, RQLite HTTP port, and RQLite Raft port must all be different
|
||||
- **Join address**: Non-bootstrap nodes need `rqlite_join_address` pointing to the bootstrap or an existing node
|
||||
- **Join address**: Non-bootstrap nodes need `rqlite_join_address` pointing to the bootstrap or an existing node (use Raft port)
|
||||
- **Bootstrap peers**: All nodes need the bootstrap node's multiaddr in `discovery.bootstrap_peers`
|
||||
- **Config files**: Store all configs in `~/.debros/` with different filenames
|
||||
- **--config flag**: Specify which config file to load (defaults to `node.yaml`)
|
||||
- **--config flag**: Specify which config file to load
|
||||
|
||||
⚠️ **Common Mistake - Same Ports:**
|
||||
If all nodes use the same ports (e.g., 5001, 7001), they will try to bind to the same addresses and fail to communicate. Verify each node has unique ports:
|
||||
@ -365,11 +381,11 @@ grep "rqlite_port\|rqlite_raft_port" ~/.debros/bootstrap.yaml
|
||||
# Should show: rqlite_port: 5001, rqlite_raft_port: 7001
|
||||
|
||||
# Node 2
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node.yaml
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node2.yaml
|
||||
# Should show: rqlite_port: 5002, rqlite_raft_port: 7002
|
||||
|
||||
# Node 3
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node2.yaml
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node3.yaml
|
||||
# Should show: rqlite_port: 5003, rqlite_raft_port: 7003
|
||||
```
|
||||
|
||||
|
||||
225
cmd/cli/main.go
225
cmd/cli/main.go
@ -15,6 +15,7 @@ import (
|
||||
"github.com/DeBrosOfficial/network/pkg/auth"
|
||||
"github.com/DeBrosOfficial/network/pkg/client"
|
||||
"github.com/DeBrosOfficial/network/pkg/config"
|
||||
"github.com/DeBrosOfficial/network/pkg/encryption"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
@ -607,30 +608,35 @@ func showConfigHelp() {
|
||||
fmt.Printf("Config Management Commands\n\n")
|
||||
fmt.Printf("Usage: network-cli config <subcommand> [options]\n\n")
|
||||
fmt.Printf("Subcommands:\n")
|
||||
fmt.Printf(" init - Generate configuration files in ~/.debros\n")
|
||||
fmt.Printf(" init - Generate full network stack in ~/.debros (bootstrap + 2 nodes + gateway)\n")
|
||||
fmt.Printf(" validate --name <file> - Validate a config file\n\n")
|
||||
fmt.Printf("Init Default Behavior (no --type):\n")
|
||||
fmt.Printf(" Generates bootstrap.yaml, node2.yaml, node3.yaml, gateway.yaml with:\n")
|
||||
fmt.Printf(" - Auto-generated identities for bootstrap, node2, node3\n")
|
||||
fmt.Printf(" - Correct bootstrap_peers and join addresses\n")
|
||||
fmt.Printf(" - Default ports: P2P 4001-4003, HTTP 5001-5003, Raft 7001-7003\n\n")
|
||||
fmt.Printf("Init Options:\n")
|
||||
fmt.Printf(" --type <type> - Config type: node, bootstrap, gateway (default: node)\n")
|
||||
fmt.Printf(" --name <file> - Output filename (default: node.yaml)\n")
|
||||
fmt.Printf(" --type <type> - Single config type: node, bootstrap, gateway (skips stack generation)\n")
|
||||
fmt.Printf(" --name <file> - Output filename (default: depends on --type or 'stack' for full stack)\n")
|
||||
fmt.Printf(" --force - Overwrite existing config/stack files\n\n")
|
||||
fmt.Printf("Single Config Options (with --type):\n")
|
||||
fmt.Printf(" --id <id> - Node ID for bootstrap peers\n")
|
||||
fmt.Printf(" --listen-port <port> - LibP2P listen port (default: 4001)\n")
|
||||
fmt.Printf(" --rqlite-http-port <port> - RQLite HTTP port (default: 5001)\n")
|
||||
fmt.Printf(" --rqlite-raft-port <port> - RQLite Raft port (default: 7001)\n")
|
||||
fmt.Printf(" --join <host:port> - RQLite address to join (required for non-bootstrap)\n")
|
||||
fmt.Printf(" --bootstrap-peers <peers> - Comma-separated bootstrap peer multiaddrs\n")
|
||||
fmt.Printf(" --force - Overwrite existing config\n\n")
|
||||
fmt.Printf(" --bootstrap-peers <peers> - Comma-separated bootstrap peer multiaddrs\n\n")
|
||||
fmt.Printf("Examples:\n")
|
||||
fmt.Printf(" network-cli config init\n")
|
||||
fmt.Printf(" network-cli config init --type node --bootstrap-peers /ip4/127.0.0.1/tcp/4001/p2p/QmXxx,/ip4/127.0.0.1/tcp/4002/p2p/QmYyy\n")
|
||||
fmt.Printf(" network-cli config init --type bootstrap\n")
|
||||
fmt.Printf(" network-cli config init --type gateway\n")
|
||||
fmt.Printf(" network-cli config init # Generate full stack\n")
|
||||
fmt.Printf(" network-cli config init --force # Overwrite existing stack\n")
|
||||
fmt.Printf(" network-cli config init --type bootstrap # Single bootstrap config (legacy)\n")
|
||||
fmt.Printf(" network-cli config validate --name node.yaml\n")
|
||||
}
|
||||
|
||||
func handleConfigInit(args []string) {
|
||||
// Parse flags
|
||||
var (
|
||||
cfgType = "node"
|
||||
cfgType = ""
|
||||
name = "" // Will be set based on type if not provided
|
||||
id string
|
||||
listenPort = 4001
|
||||
@ -694,6 +700,13 @@ func handleConfigInit(args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// If --type is not specified, generate full stack
|
||||
if cfgType == "" {
|
||||
initFullStack(force)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, continue with single-file generation
|
||||
// Validate type
|
||||
if cfgType != "node" && cfgType != "bootstrap" && cfgType != "gateway" {
|
||||
fmt.Fprintf(os.Stderr, "Invalid --type: %s (expected: node, bootstrap, or gateway)\n", cfgType)
|
||||
@ -799,6 +812,192 @@ func handleConfigValidate(args []string) {
|
||||
fmt.Printf("✅ Config is valid: %s\n", configPath)
|
||||
}
|
||||
|
||||
func initFullStack(force bool) {
|
||||
fmt.Printf("🚀 Initializing full network stack...\n")
|
||||
|
||||
// Ensure ~/.debros directory exists
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to get home directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
debrosDir := filepath.Join(homeDir, ".debros")
|
||||
if err := os.MkdirAll(debrosDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create ~/.debros directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Step 1: Generate bootstrap identity
|
||||
bootstrapIdentityDir := filepath.Join(debrosDir, "bootstrap")
|
||||
bootstrapIdentityPath := filepath.Join(bootstrapIdentityDir, "identity.key")
|
||||
|
||||
if !force {
|
||||
if _, err := os.Stat(bootstrapIdentityPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Bootstrap identity already exists at %s (use --force to overwrite)\n", bootstrapIdentityPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
bootstrapInfo, err := encryption.GenerateIdentity()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to generate bootstrap identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := os.MkdirAll(bootstrapIdentityDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create bootstrap data directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := encryption.SaveIdentity(bootstrapInfo, bootstrapIdentityPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to save bootstrap identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated bootstrap identity: %s (Peer ID: %s)\n", bootstrapIdentityPath, bootstrapInfo.PeerID.String())
|
||||
|
||||
// Construct bootstrap multiaddr
|
||||
bootstrapMultiaddr := fmt.Sprintf("/ip4/127.0.0.1/tcp/4001/p2p/%s", bootstrapInfo.PeerID.String())
|
||||
fmt.Printf(" Bootstrap multiaddr: %s\n", bootstrapMultiaddr)
|
||||
|
||||
// Step 2: Generate bootstrap.yaml
|
||||
bootstrapName := "bootstrap.yaml"
|
||||
bootstrapPath := filepath.Join(debrosDir, bootstrapName)
|
||||
if !force {
|
||||
if _, err := os.Stat(bootstrapPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Bootstrap config already exists at %s (use --force to overwrite)\n", bootstrapPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
bootstrapContent := generateBootstrapConfig(bootstrapName, "", 4001, 5001, 7001)
|
||||
if err := os.WriteFile(bootstrapPath, []byte(bootstrapContent), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write bootstrap config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated bootstrap config: %s\n", bootstrapPath)
|
||||
|
||||
// Step 3: Generate node2 identity and config
|
||||
node2IdentityDir := filepath.Join(debrosDir, "node2")
|
||||
node2IdentityPath := filepath.Join(node2IdentityDir, "identity.key")
|
||||
|
||||
if !force {
|
||||
if _, err := os.Stat(node2IdentityPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node2 identity already exists at %s (use --force to overwrite)\n", node2IdentityPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
node2Info, err := encryption.GenerateIdentity()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to generate node2 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := os.MkdirAll(node2IdentityDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create node2 data directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := encryption.SaveIdentity(node2Info, node2IdentityPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to save node2 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node2 identity: %s (Peer ID: %s)\n", node2IdentityPath, node2Info.PeerID.String())
|
||||
|
||||
node2Name := "node2.yaml"
|
||||
node2Path := filepath.Join(debrosDir, node2Name)
|
||||
if !force {
|
||||
if _, err := os.Stat(node2Path); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node2 config already exists at %s (use --force to overwrite)\n", node2Path)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
node2Content := generateNodeConfig(node2Name, "", 4002, 5002, 7002, "127.0.0.1:7001", bootstrapMultiaddr)
|
||||
if err := os.WriteFile(node2Path, []byte(node2Content), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write node2 config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node2 config: %s\n", node2Path)
|
||||
|
||||
// Step 4: Generate node3 identity and config
|
||||
node3IdentityDir := filepath.Join(debrosDir, "node3")
|
||||
node3IdentityPath := filepath.Join(node3IdentityDir, "identity.key")
|
||||
|
||||
if !force {
|
||||
if _, err := os.Stat(node3IdentityPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node3 identity already exists at %s (use --force to overwrite)\n", node3IdentityPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
node3Info, err := encryption.GenerateIdentity()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to generate node3 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := os.MkdirAll(node3IdentityDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create node3 data directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := encryption.SaveIdentity(node3Info, node3IdentityPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to save node3 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node3 identity: %s (Peer ID: %s)\n", node3IdentityPath, node3Info.PeerID.String())
|
||||
|
||||
node3Name := "node3.yaml"
|
||||
node3Path := filepath.Join(debrosDir, node3Name)
|
||||
if !force {
|
||||
if _, err := os.Stat(node3Path); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node3 config already exists at %s (use --force to overwrite)\n", node3Path)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
node3Content := generateNodeConfig(node3Name, "", 4003, 5003, 7003, "127.0.0.1:7001", bootstrapMultiaddr)
|
||||
if err := os.WriteFile(node3Path, []byte(node3Content), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write node3 config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node3 config: %s\n", node3Path)
|
||||
|
||||
// Step 5: Generate gateway.yaml
|
||||
gatewayName := "gateway.yaml"
|
||||
gatewayPath := filepath.Join(debrosDir, gatewayName)
|
||||
if !force {
|
||||
if _, err := os.Stat(gatewayPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Gateway config already exists at %s (use --force to overwrite)\n", gatewayPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
gatewayContent := generateGatewayConfig(bootstrapMultiaddr)
|
||||
if err := os.WriteFile(gatewayPath, []byte(gatewayContent), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write gateway config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated gateway config: %s\n", gatewayPath)
|
||||
|
||||
// Print summary
|
||||
fmt.Printf("\n" + strings.Repeat("=", 60) + "\n")
|
||||
fmt.Printf("✅ Full network stack initialized successfully!\n")
|
||||
fmt.Printf(strings.Repeat("=", 60) + "\n\n")
|
||||
fmt.Printf("Configuration files created in: %s\n\n", debrosDir)
|
||||
fmt.Printf("Bootstrap Node:\n")
|
||||
fmt.Printf(" Config: %s\n", bootstrapPath)
|
||||
fmt.Printf(" Peer ID: %s\n", bootstrapInfo.PeerID.String())
|
||||
fmt.Printf(" Ports: P2P=4001, HTTP=5001, Raft=7001\n\n")
|
||||
fmt.Printf("Node2:\n")
|
||||
fmt.Printf(" Config: %s\n", node2Path)
|
||||
fmt.Printf(" Ports: P2P=4002, HTTP=5002, Raft=7002\n")
|
||||
fmt.Printf(" Join: 127.0.0.1:7001\n\n")
|
||||
fmt.Printf("Node3:\n")
|
||||
fmt.Printf(" Config: %s\n", node3Path)
|
||||
fmt.Printf(" Ports: P2P=4003, HTTP=5003, Raft=7003\n")
|
||||
fmt.Printf(" Join: 127.0.0.1:7001\n\n")
|
||||
fmt.Printf("Gateway:\n")
|
||||
fmt.Printf(" Config: %s\n\n", gatewayPath)
|
||||
fmt.Printf("To start the network:\n")
|
||||
fmt.Printf(" Terminal 1: ./bin/node --config bootstrap.yaml\n")
|
||||
fmt.Printf(" Terminal 2: ./bin/node --config node2.yaml\n")
|
||||
fmt.Printf(" Terminal 3: ./bin/node --config node3.yaml\n")
|
||||
fmt.Printf(" Terminal 4: ./bin/gateway --config gateway.yaml\n")
|
||||
fmt.Printf("\n" + strings.Repeat("=", 60) + "\n")
|
||||
}
|
||||
|
||||
func generateNodeConfig(name, id string, listenPort, rqliteHTTPPort, rqliteRaftPort int, joinAddr, bootstrapPeers string) string {
|
||||
nodeID := id
|
||||
if nodeID == "" {
|
||||
@ -923,11 +1122,11 @@ func generateGatewayConfig(bootstrapPeers string) string {
|
||||
|
||||
var peersYAML strings.Builder
|
||||
if len(peers) == 0 {
|
||||
peersYAML.WriteString(" bootstrap_peers: []")
|
||||
peersYAML.WriteString("bootstrap_peers: []")
|
||||
} else {
|
||||
peersYAML.WriteString(" bootstrap_peers:\n")
|
||||
peersYAML.WriteString("bootstrap_peers:\n")
|
||||
for _, p := range peers {
|
||||
fmt.Fprintf(&peersYAML, " - \"%s\"\n", p)
|
||||
fmt.Fprintf(&peersYAML, " - \"%s\"\n", p)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
105
pkg/node/node.go
105
pkg/node/node.go
@ -84,35 +84,35 @@ func (n *Node) startRQLite(ctx context.Context) error {
|
||||
|
||||
// bootstrapPeerSource returns a PeerSource that yields peers from BootstrapPeers.
|
||||
func bootstrapPeerSource(bootstrapAddrs []string, logger *zap.Logger) func(context.Context, int) <-chan peer.AddrInfo {
|
||||
return func(ctx context.Context, num int) <-chan peer.AddrInfo {
|
||||
out := make(chan peer.AddrInfo, num)
|
||||
go func() {
|
||||
defer close(out)
|
||||
count := 0
|
||||
for _, s := range bootstrapAddrs {
|
||||
if count >= num {
|
||||
return
|
||||
}
|
||||
ma, err := multiaddr.NewMultiaddr(s)
|
||||
if err != nil {
|
||||
logger.Debug("invalid bootstrap multiaddr", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
ai, err := peer.AddrInfoFromP2pAddr(ma)
|
||||
if err != nil {
|
||||
logger.Debug("failed to parse bootstrap peer", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case out <- *ai:
|
||||
count++
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
return func(ctx context.Context, num int) <-chan peer.AddrInfo {
|
||||
out := make(chan peer.AddrInfo, num)
|
||||
go func() {
|
||||
defer close(out)
|
||||
count := 0
|
||||
for _, s := range bootstrapAddrs {
|
||||
if count >= num {
|
||||
return
|
||||
}
|
||||
ma, err := multiaddr.NewMultiaddr(s)
|
||||
if err != nil {
|
||||
logger.Debug("invalid bootstrap multiaddr", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
ai, err := peer.AddrInfoFromP2pAddr(ma)
|
||||
if err != nil {
|
||||
logger.Debug("failed to parse bootstrap peer", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case out <- *ai:
|
||||
count++
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
// hasBootstrapConnections checks if we're connected to any bootstrap peers
|
||||
@ -250,21 +250,52 @@ func (n *Node) startLibP2P() error {
|
||||
return fmt.Errorf("failed to load identity: %w", err)
|
||||
}
|
||||
|
||||
// Create LibP2P host with NAT traversal support
|
||||
// Create LibP2P host with explicit listen addresses
|
||||
var opts []libp2p.Option
|
||||
opts = append(opts,
|
||||
libp2p.Identity(identity),
|
||||
libp2p.Security(noise.ID, noise.New),
|
||||
libp2p.DefaultMuxers,
|
||||
libp2p.EnableNATService(),
|
||||
libp2p.EnableAutoNATv2(),
|
||||
libp2p.EnableRelay(),
|
||||
libp2p.NATPortMap(),
|
||||
libp2p.EnableAutoRelayWithPeerSource(
|
||||
bootstrapPeerSource(n.config.Discovery.BootstrapPeers, n.logger.Logger),
|
||||
),
|
||||
)
|
||||
|
||||
// Add explicit listen addresses from config
|
||||
if len(n.config.Node.ListenAddresses) > 0 {
|
||||
listenAddrs := make([]multiaddr.Multiaddr, 0, len(n.config.Node.ListenAddresses))
|
||||
for _, addr := range n.config.Node.ListenAddresses {
|
||||
ma, err := multiaddr.NewMultiaddr(addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid listen address %s: %w", addr, err)
|
||||
}
|
||||
listenAddrs = append(listenAddrs, ma)
|
||||
}
|
||||
opts = append(opts, libp2p.ListenAddrs(listenAddrs...))
|
||||
n.logger.ComponentInfo(logging.ComponentLibP2P, "Configured listen addresses",
|
||||
zap.Strings("addrs", n.config.Node.ListenAddresses))
|
||||
}
|
||||
|
||||
// For localhost/development, disable NAT services
|
||||
// For production, these would be enabled
|
||||
isLocalhost := len(n.config.Node.ListenAddresses) > 0 &&
|
||||
(strings.Contains(n.config.Node.ListenAddresses[0], "127.0.0.1") ||
|
||||
strings.Contains(n.config.Node.ListenAddresses[0], "localhost"))
|
||||
|
||||
if isLocalhost {
|
||||
n.logger.ComponentInfo(logging.ComponentLibP2P, "Localhost detected - disabling NAT services for local development")
|
||||
// Don't add NAT/AutoRelay options for localhost
|
||||
} else {
|
||||
// Production: enable NAT traversal
|
||||
n.logger.ComponentInfo(logging.ComponentLibP2P, "Production mode - enabling NAT services")
|
||||
opts = append(opts,
|
||||
libp2p.EnableNATService(),
|
||||
libp2p.EnableAutoNATv2(),
|
||||
libp2p.EnableRelay(),
|
||||
libp2p.NATPortMap(),
|
||||
libp2p.EnableAutoRelayWithPeerSource(
|
||||
bootstrapPeerSource(n.config.Discovery.BootstrapPeers, n.logger.Logger),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
h, err := libp2p.New(opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# DeBros Network Node Installation Script (Modern Node-Only Setup)
|
||||
# Installs, configures, and manages a DeBros network node with secure defaults.
|
||||
# Supports update-in-place, systemd service, and CLI management.
|
||||
# DeBros Network Production Installation Script
|
||||
# Installs and configures a complete DeBros network node (bootstrap) with gateway.
|
||||
# Supports idempotent updates and secure systemd service management.
|
||||
|
||||
set -e
|
||||
trap 'echo -e "${RED}An error occurred. Installation aborted.${NOCOLOR}"; exit 1' ERR
|
||||
@ -25,6 +25,7 @@ GATEWAY_PORT="6001"
|
||||
RAFT_PORT="7001"
|
||||
UPDATE_MODE=false
|
||||
NON_INTERACTIVE=false
|
||||
DEBROS_USER="debros"
|
||||
|
||||
log() { echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NOCOLOR} $1"; }
|
||||
error() { echo -e "${RED}[ERROR]${NOCOLOR} $1"; }
|
||||
@ -115,7 +116,7 @@ check_existing_installation() {
|
||||
|
||||
remove_existing_installation() {
|
||||
log "Removing existing installation..."
|
||||
for service in debros-node; do
|
||||
for service in debros-node debros-gateway; do
|
||||
if systemctl list-unit-files | grep -q "$service.service"; then
|
||||
log "Stopping $service service..."
|
||||
sudo systemctl stop $service.service 2>/dev/null || true
|
||||
@ -128,8 +129,8 @@ remove_existing_installation() {
|
||||
sudo rm -rf "$INSTALL_DIR"
|
||||
log "Removed installation directory"
|
||||
fi
|
||||
if id "debros" &>/dev/null; then
|
||||
sudo userdel debros 2>/dev/null || true
|
||||
if id "$DEBROS_USER" &>/dev/null; then
|
||||
sudo userdel "$DEBROS_USER" 2>/dev/null || true
|
||||
log "Removed debros user"
|
||||
fi
|
||||
success "Existing installation removed"
|
||||
@ -260,50 +261,24 @@ check_ports() {
|
||||
success "All required ports are available"
|
||||
}
|
||||
|
||||
configuration_wizard() {
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
log "${GREEN} DeBros Network Configuration Wizard ${NOCOLOR}"
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
if [ "$NON_INTERACTIVE" = true ]; then
|
||||
log "Non-interactive mode: using default configuration"
|
||||
SOLANA_WALLET="11111111111111111111111111111111"
|
||||
CONFIGURE_FIREWALL="yes"
|
||||
log "Installation Directory: $INSTALL_DIR"
|
||||
log "Firewall Configuration: $CONFIGURE_FIREWALL"
|
||||
success "Configuration completed with defaults"
|
||||
return 0
|
||||
fi
|
||||
log "${GREEN}Enter your Solana wallet address for node operator rewards:${NOCOLOR}"
|
||||
while true; do
|
||||
read -rp "Solana Wallet Address: " SOLANA_WALLET
|
||||
if [[ -n "$SOLANA_WALLET" && ${#SOLANA_WALLET} -ge 32 ]]; then break; else error "Please enter a valid Solana wallet address"; fi
|
||||
done
|
||||
read -rp "Installation directory [default: $INSTALL_DIR]: " CUSTOM_INSTALL_DIR
|
||||
if [[ -n "$CUSTOM_INSTALL_DIR" ]]; then INSTALL_DIR="$CUSTOM_INSTALL_DIR"; fi
|
||||
read -rp "Configure firewall automatically? (yes/no) [default: yes]: " CONFIGURE_FIREWALL
|
||||
CONFIGURE_FIREWALL="${CONFIGURE_FIREWALL:-yes}"
|
||||
success "Configuration completed"
|
||||
}
|
||||
|
||||
setup_directories() {
|
||||
log "Setting up directories and permissions..."
|
||||
if ! id "debros" &>/dev/null; then
|
||||
sudo useradd -r -s /bin/false -d "$INSTALL_DIR" debros
|
||||
if ! id "$DEBROS_USER" &>/dev/null; then
|
||||
sudo useradd -r -s /usr/sbin/nologin -d "$INSTALL_DIR" "$DEBROS_USER"
|
||||
log "Created debros user"
|
||||
else
|
||||
log "User 'debros' already exists"
|
||||
fi
|
||||
sudo mkdir -p "$INSTALL_DIR"/{bin,configs,keys,data,logs,src}
|
||||
sudo mkdir -p "$INSTALL_DIR/keys/node"
|
||||
sudo mkdir -p "$INSTALL_DIR/data/node"/{rqlite,storage}
|
||||
sudo chown -R debros:debros "$INSTALL_DIR"
|
||||
sudo mkdir -p "$INSTALL_DIR"/{bin,src}
|
||||
sudo chown -R "$DEBROS_USER:$DEBROS_USER" "$INSTALL_DIR"
|
||||
sudo chmod 755 "$INSTALL_DIR"
|
||||
sudo chmod 700 "$INSTALL_DIR/keys"
|
||||
sudo chmod 700 "$INSTALL_DIR/keys/node"
|
||||
sudo chmod 755 "$INSTALL_DIR/data"
|
||||
sudo chmod 755 "$INSTALL_DIR/logs"
|
||||
sudo chmod 755 "$INSTALL_DIR/configs"
|
||||
sudo chmod 755 "$INSTALL_DIR/bin"
|
||||
|
||||
# Create ~/.debros for the debros user
|
||||
DEBROS_HOME=$(sudo -u "$DEBROS_USER" sh -c 'echo ~')
|
||||
sudo -u "$DEBROS_USER" mkdir -p "$DEBROS_HOME/.debros"
|
||||
sudo chmod 0700 "$DEBROS_HOME/.debros"
|
||||
|
||||
success "Directory structure ready"
|
||||
}
|
||||
|
||||
@ -312,39 +287,20 @@ setup_source_code() {
|
||||
if [ -d "$INSTALL_DIR/src/.git" ]; then
|
||||
log "Updating existing repository..."
|
||||
cd "$INSTALL_DIR/src"
|
||||
sudo -u debros git pull
|
||||
sudo -u "$DEBROS_USER" git pull
|
||||
else
|
||||
log "Cloning repository..."
|
||||
sudo -u debros git clone "$REPO_URL" "$INSTALL_DIR/src"
|
||||
sudo -u "$DEBROS_USER" git clone "$REPO_URL" "$INSTALL_DIR/src"
|
||||
cd "$INSTALL_DIR/src"
|
||||
fi
|
||||
success "Source code ready"
|
||||
}
|
||||
|
||||
generate_identity() {
|
||||
local identity_file="$INSTALL_DIR/keys/node/identity.key"
|
||||
if [ -f "$identity_file" ]; then
|
||||
if [ "$UPDATE_MODE" = true ]; then
|
||||
log "Identity key already exists, keeping existing key"
|
||||
success "Using existing node identity"
|
||||
return 0
|
||||
else
|
||||
log "Identity key already exists, regenerating..."
|
||||
sudo rm -f "$identity_file"
|
||||
fi
|
||||
fi
|
||||
log "Generating node identity..."
|
||||
cd "$INSTALL_DIR/src"
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
sudo -u debros env "PATH=$PATH:/usr/local/go/bin" go run ./cmd/identity -output "$identity_file"
|
||||
success "Node identity generated"
|
||||
}
|
||||
|
||||
build_binaries() {
|
||||
log "Building DeBros Network binaries..."
|
||||
cd "$INSTALL_DIR/src"
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
sudo -u debros env "PATH=$PATH:/usr/local/go/bin" make build
|
||||
|
||||
local services_were_running=()
|
||||
if [ "$UPDATE_MODE" = true ]; then
|
||||
log "Update mode: checking for running services before binary update..."
|
||||
@ -353,13 +309,22 @@ build_binaries() {
|
||||
sudo systemctl stop debros-node.service
|
||||
services_were_running+=("debros-node")
|
||||
fi
|
||||
if systemctl is-active --quiet debros-gateway.service 2>/dev/null; then
|
||||
log "Stopping debros-gateway service to update binaries..."
|
||||
sudo systemctl stop debros-gateway.service
|
||||
services_were_running+=("debros-gateway")
|
||||
fi
|
||||
if [ ${#services_were_running[@]} -gt 0 ]; then
|
||||
log "Waiting for services to stop completely..."
|
||||
sleep 3
|
||||
fi
|
||||
fi
|
||||
|
||||
sudo -u "$DEBROS_USER" env "PATH=$PATH:/usr/local/go/bin" make build
|
||||
sudo cp bin/* "$INSTALL_DIR/bin/"
|
||||
sudo chown debros:debros "$INSTALL_DIR/bin/"*
|
||||
sudo chown "$DEBROS_USER:$DEBROS_USER" "$INSTALL_DIR/bin/"*
|
||||
sudo chmod 755 "$INSTALL_DIR/bin/"*
|
||||
|
||||
if [ "$UPDATE_MODE" = true ] && [ ${#services_were_running[@]} -gt 0 ]; then
|
||||
log "Restarting previously running services..."
|
||||
for service in "${services_were_running[@]}"; do
|
||||
@ -371,81 +336,76 @@ build_binaries() {
|
||||
}
|
||||
|
||||
generate_configs() {
|
||||
log "Generating configuration files..."
|
||||
cat > /tmp/node.yaml << EOF
|
||||
node:
|
||||
data_dir: "$INSTALL_DIR/data/node"
|
||||
key_file: "$INSTALL_DIR/keys/node/identity.key"
|
||||
listen_addresses:
|
||||
- "/ip4/0.0.0.0/tcp/$NODE_PORT"
|
||||
solana_wallet: "$SOLANA_WALLET"
|
||||
database:
|
||||
rqlite_port: $RQLITE_PORT
|
||||
rqlite_raft_port: $RAFT_PORT
|
||||
logging:
|
||||
level: "info"
|
||||
file: "$INSTALL_DIR/logs/node.log"
|
||||
EOF
|
||||
sudo mv /tmp/node.yaml "$INSTALL_DIR/configs/node.yaml"
|
||||
sudo chown debros:debros "$INSTALL_DIR/configs/node.yaml"
|
||||
log "Generating configuration files via network-cli..."
|
||||
DEBROS_HOME=$(sudo -u "$DEBROS_USER" sh -c 'echo ~')
|
||||
|
||||
# Generate bootstrap config
|
||||
log "Generating bootstrap.yaml..."
|
||||
sudo -u "$DEBROS_USER" "$INSTALL_DIR/bin/network-cli" config init --type bootstrap --force
|
||||
|
||||
# Generate gateway config
|
||||
log "Generating gateway.yaml..."
|
||||
sudo -u "$DEBROS_USER" "$INSTALL_DIR/bin/network-cli" config init --type gateway --force
|
||||
|
||||
success "Configuration files generated"
|
||||
}
|
||||
|
||||
configure_firewall() {
|
||||
if [[ "$CONFIGURE_FIREWALL" == "yes" ]]; then
|
||||
log "Configuring firewall rules..."
|
||||
if command -v ufw &> /dev/null; then
|
||||
log "Adding UFW rules for DeBros Network ports..."
|
||||
for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT; do
|
||||
if ! sudo ufw allow $port; then
|
||||
error "Failed to allow port $port"
|
||||
exit 1
|
||||
fi
|
||||
log "Added UFW rule: allow port $port"
|
||||
done
|
||||
UFW_STATUS=$(sudo ufw status | grep -o "Status: [a-z]\+" | awk '{print $2}' || echo "inactive")
|
||||
if [[ "$UFW_STATUS" == "active" ]]; then
|
||||
success "Firewall rules added and active"
|
||||
else
|
||||
success "Firewall rules added (UFW is inactive - rules will take effect when UFW is enabled)"
|
||||
log "To enable UFW with current rules: sudo ufw enable"
|
||||
log "Configuring firewall rules..."
|
||||
if command -v ufw &> /dev/null; then
|
||||
log "Adding UFW rules for DeBros Network ports..."
|
||||
for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT $GATEWAY_PORT; do
|
||||
if ! sudo ufw allow $port 2>/dev/null; then
|
||||
error "Failed to allow port $port"
|
||||
exit 1
|
||||
fi
|
||||
log "Added UFW rule: allow port $port"
|
||||
done
|
||||
UFW_STATUS=$(sudo ufw status | grep -o "Status: [a-z]\+" | awk '{print $2}' || echo "inactive")
|
||||
if [[ "$UFW_STATUS" == "active" ]]; then
|
||||
success "Firewall rules added and active"
|
||||
else
|
||||
warning "UFW not found. Please configure firewall manually."
|
||||
log "Required ports to allow:"
|
||||
log " - Port $NODE_PORT (Node)"
|
||||
log " - Port $RQLITE_PORT (RQLite)"
|
||||
log " - Port $RAFT_PORT (Raft)"
|
||||
success "Firewall rules added (UFW is inactive - rules will take effect when UFW is enabled)"
|
||||
log "To enable UFW with current rules: sudo ufw enable"
|
||||
fi
|
||||
else
|
||||
warning "UFW not found. Please configure firewall manually."
|
||||
log "Required ports to allow:"
|
||||
log " - Port $NODE_PORT (Node P2P)"
|
||||
log " - Port $RQLITE_PORT (RQLite HTTP)"
|
||||
log " - Port $RAFT_PORT (RQLite Raft)"
|
||||
log " - Port $GATEWAY_PORT (Gateway)"
|
||||
fi
|
||||
}
|
||||
|
||||
create_systemd_service() {
|
||||
local service_file="/etc/systemd/system/debros-node.service"
|
||||
if [ -f "$service_file" ]; then
|
||||
create_systemd_services() {
|
||||
log "Creating systemd service units..."
|
||||
|
||||
# Node service
|
||||
local node_service_file="/etc/systemd/system/debros-node.service"
|
||||
if [ -f "$node_service_file" ]; then
|
||||
log "Cleaning up existing node service..."
|
||||
sudo systemctl stop debros-node.service 2>/dev/null || true
|
||||
sudo systemctl disable debros-node.service 2>/dev/null || true
|
||||
sudo rm -f "$service_file"
|
||||
sudo rm -f "$node_service_file"
|
||||
fi
|
||||
sudo systemctl daemon-reload
|
||||
log "Creating new systemd service..."
|
||||
local exec_start="$INSTALL_DIR/bin/node --config $INSTALL_DIR/configs/node.yaml"
|
||||
cat > /tmp/debros-node.service << EOF
|
||||
[Unit]
|
||||
Description=DeBros Network Node
|
||||
After=network.target
|
||||
Description=DeBros Network Node (Bootstrap)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=debros
|
||||
Group=debros
|
||||
WorkingDirectory=$INSTALL_DIR
|
||||
Environment=ENVIRONMENT=production
|
||||
ExecStart=$exec_start
|
||||
WorkingDirectory=/opt/debros/src
|
||||
ExecStart=/opt/debros/bin/node --config bootstrap.yaml
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=debros-node
|
||||
@ -454,26 +414,78 @@ NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ReadWritePaths=$INSTALL_DIR
|
||||
ReadWritePaths=/opt/debros
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
sudo mv /tmp/debros-node.service "$service_file"
|
||||
sudo mv /tmp/debros-node.service "$node_service_file"
|
||||
|
||||
# Gateway service
|
||||
local gateway_service_file="/etc/systemd/system/debros-gateway.service"
|
||||
if [ -f "$gateway_service_file" ]; then
|
||||
log "Cleaning up existing gateway service..."
|
||||
sudo systemctl stop debros-gateway.service 2>/dev/null || true
|
||||
sudo systemctl disable debros-gateway.service 2>/dev/null || true
|
||||
sudo rm -f "$gateway_service_file"
|
||||
fi
|
||||
|
||||
log "Creating debros-gateway.service..."
|
||||
cat > /tmp/debros-gateway.service << 'EOF'
|
||||
[Unit]
|
||||
Description=DeBros Gateway (HTTP/WebSocket)
|
||||
After=debros-node.service
|
||||
Wants=debros-node.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=debros
|
||||
Group=debros
|
||||
WorkingDirectory=/opt/debros/src
|
||||
ExecStart=/opt/debros/bin/gateway
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=debros-gateway
|
||||
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ReadWritePaths=/opt/debros
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
sudo mv /tmp/debros-gateway.service "$gateway_service_file"
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable debros-node.service
|
||||
success "Systemd service ready"
|
||||
sudo systemctl enable debros-gateway.service
|
||||
success "Systemd services ready"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
log "Starting DeBros Network service..."
|
||||
start_services() {
|
||||
log "Starting DeBros Network services..."
|
||||
sudo systemctl start debros-node.service
|
||||
sleep 3
|
||||
if systemctl is-active --quiet debros-node.service; then
|
||||
success "DeBros Network service started successfully"
|
||||
success "DeBros Node service started successfully"
|
||||
else
|
||||
error "Failed to start DeBros Network service"
|
||||
log "Check logs with: sudo journalctl -u debros-node.service"
|
||||
error "Failed to start DeBros Node service"
|
||||
log "Check logs with: sudo journalctl -u debros-node.service -f"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 2
|
||||
sudo systemctl start debros-gateway.service
|
||||
sleep 2
|
||||
if systemctl is-active --quiet debros-gateway.service; then
|
||||
success "DeBros Gateway service started successfully"
|
||||
else
|
||||
error "Failed to start DeBros Gateway service"
|
||||
log "Check logs with: sudo journalctl -u debros-gateway.service -f"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@ -501,14 +513,8 @@ main() {
|
||||
if ! check_go_installation; then install_go; fi
|
||||
install_dependencies
|
||||
install_rqlite
|
||||
if [ "$UPDATE_MODE" != true ]; then configuration_wizard; else
|
||||
log "Update mode: skipping configuration wizard"
|
||||
SOLANA_WALLET="11111111111111111111111111111111"
|
||||
CONFIGURE_FIREWALL="yes"
|
||||
fi
|
||||
setup_directories
|
||||
setup_source_code
|
||||
generate_identity
|
||||
build_binaries
|
||||
if [ "$UPDATE_MODE" != true ]; then
|
||||
generate_configs
|
||||
@ -516,8 +522,11 @@ main() {
|
||||
else
|
||||
log "Update mode: keeping existing configuration"
|
||||
fi
|
||||
create_systemd_service
|
||||
start_service
|
||||
create_systemd_services
|
||||
start_services
|
||||
|
||||
DEBROS_HOME=$(sudo -u "$DEBROS_USER" sh -c 'echo ~')
|
||||
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
if [ "$UPDATE_MODE" = true ]; then
|
||||
log "${GREEN} Update Complete! ${NOCOLOR}"
|
||||
@ -526,21 +535,28 @@ main() {
|
||||
fi
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
log "${GREEN}Installation Directory:${NOCOLOR} ${CYAN}$INSTALL_DIR${NOCOLOR}"
|
||||
log "${GREEN}Configuration:${NOCOLOR} ${CYAN}$INSTALL_DIR/configs/node.yaml${NOCOLOR}"
|
||||
log "${GREEN}Logs:${NOCOLOR} ${CYAN}$INSTALL_DIR/logs/node.log${NOCOLOR}"
|
||||
log "${GREEN}Config Directory:${NOCOLOR} ${CYAN}$DEBROS_HOME/.debros${NOCOLOR}"
|
||||
log "${GREEN}LibP2P Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}"
|
||||
log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_PORT${NOCOLOR}"
|
||||
log "${GREEN}Gateway Port:${NOCOLOR} ${CYAN}$GATEWAY_PORT${NOCOLOR}"
|
||||
log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_PORT${NOCOLOR}"
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
log "${GREEN}Management Commands:${NOCOLOR}"
|
||||
log "${CYAN} - sudo systemctl status debros-node${NOCOLOR} (Check status)"
|
||||
log "${CYAN} - sudo systemctl restart debros-node${NOCOLOR} (Restart service)"
|
||||
log "${CYAN} - sudo systemctl stop debros-node${NOCOLOR} (Stop service)"
|
||||
log "${CYAN} - sudo systemctl start debros-node${NOCOLOR} (Start service)"
|
||||
log "${CYAN} - sudo journalctl -u debros-node.service -f${NOCOLOR} (View logs)"
|
||||
log "${CYAN} - $INSTALL_DIR/bin/network-cli${NOCOLOR} (Use CLI tools)"
|
||||
log "${GREEN}Service Management:${NOCOLOR}"
|
||||
log "${CYAN} - sudo systemctl status debros-node${NOCOLOR} (Check node status)"
|
||||
log "${CYAN} - sudo systemctl status debros-gateway${NOCOLOR} (Check gateway status)"
|
||||
log "${CYAN} - sudo systemctl restart debros-node${NOCOLOR} (Restart node)"
|
||||
log "${CYAN} - sudo systemctl restart debros-gateway${NOCOLOR} (Restart gateway)"
|
||||
log "${CYAN} - sudo systemctl stop debros-node${NOCOLOR} (Stop node)"
|
||||
log "${CYAN} - sudo systemctl stop debros-gateway${NOCOLOR} (Stop gateway)"
|
||||
log "${CYAN} - sudo journalctl -u debros-node.service -f${NOCOLOR} (View node logs)"
|
||||
log "${CYAN} - sudo journalctl -u debros-gateway.service -f${NOCOLOR} (View gateway logs)"
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
log "${GREEN}Verify Installation:${NOCOLOR}"
|
||||
log "${CYAN} - Node health: curl http://127.0.0.1:5001/status${NOCOLOR}"
|
||||
log "${CYAN} - Gateway health: curl http://127.0.0.1:6001/health${NOCOLOR}"
|
||||
log "${CYAN} - Show bootstrap peer: cat $DEBROS_HOME/.debros/bootstrap/peer.info${NOCOLOR}"
|
||||
log "${BLUE}==================================================${NOCOLOR}"
|
||||
|
||||
if [ "$UPDATE_MODE" = true ]; then
|
||||
success "DeBros Network has been updated and is running!"
|
||||
else
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user