mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-12 23:18:49 +00:00
feat: add port checking and anyone-client installation to production setup
- Introduced a new `PortChecker` type to verify port availability, enhancing service management during startup. - Updated the `BinaryInstaller` to install the `anyone-client` npm package globally, ensuring its availability for SOCKS5 proxy functionality. - Enhanced the `ProductionSetup` to include checks for port usage before starting the `anyone-client` service, improving conflict resolution. - Added logging for the installation and service creation of `anyone-client`, providing clearer feedback during the setup process.
This commit is contained in:
parent
4c1f842939
commit
90a26295a4
17
CHANGELOG.md
17
CHANGELOG.md
@ -13,6 +13,23 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant
|
|||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
## [0.69.18] - 2025-11-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Integrated `anyone-client` (SOCKS5 proxy) installation and systemd service (`debros-anyone-client.service`).
|
||||||
|
- Added port availability checking logic to prevent conflicts when starting services (e.g., `anyone-client` on port 9050).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Updated system dependencies installation to include `nodejs` and `npm` required for `anyone-client`.
|
||||||
|
- Modified Olric configuration generation to bind to the specific VPS IP if provided, otherwise defaults to 0.0.0.0.
|
||||||
|
- Improved IPFS Cluster initialization by passing `CLUSTER_SECRET` directly as an environment variable.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
\n
|
||||||
## [0.69.17] - 2025-11-21
|
## [0.69.17] - 2025-11-21
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
2
Makefile
2
Makefile
@ -19,7 +19,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
|
.PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports install-hooks kill
|
||||||
|
|
||||||
VERSION := 0.69.17
|
VERSION := 0.69.18
|
||||||
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)'
|
||||||
|
|||||||
@ -74,6 +74,8 @@ Install the CLI tool first:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://install.debros.network | sudo bash
|
curl -fsSL https://install.debros.network | sudo bash
|
||||||
|
|
||||||
|
./install-debros-network.sh --prerelease --nightly
|
||||||
```
|
```
|
||||||
|
|
||||||
Or download manually from [GitHub Releases](https://github.com/DeBrosOfficial/network/releases).
|
Or download manually from [GitHub Releases](https://github.com/DeBrosOfficial/network/releases).
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package production
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -297,3 +298,35 @@ func (rc *ResourceChecker) CheckCPU() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PortChecker checks if ports are available or in use
|
||||||
|
type PortChecker struct{}
|
||||||
|
|
||||||
|
// NewPortChecker creates a new port checker
|
||||||
|
func NewPortChecker() *PortChecker {
|
||||||
|
return &PortChecker{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPortInUse checks if a specific port is already in use
|
||||||
|
func (pc *PortChecker) IsPortInUse(port int) bool {
|
||||||
|
addr := fmt.Sprintf("localhost:%d", port)
|
||||||
|
conn, err := net.Dial("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
// Port is not in use
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
// Port is in use
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPortInUseOnHost checks if a port is in use on a specific host
|
||||||
|
func (pc *PortChecker) IsPortInUseOnHost(host string, port int) bool {
|
||||||
|
addr := net.JoinHostPort(host, fmt.Sprintf("%d", port))
|
||||||
|
conn, err := net.Dial("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@ -391,8 +391,8 @@ func (bi *BinaryInstaller) InstallSystemDependencies() error {
|
|||||||
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Warning: apt update failed\n")
|
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Warning: apt update failed\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install dependencies
|
// Install dependencies including Node.js for anyone-client
|
||||||
cmd = exec.Command("apt-get", "install", "-y", "curl", "git", "make", "build-essential", "wget")
|
cmd = exec.Command("apt-get", "install", "-y", "curl", "git", "make", "build-essential", "wget", "nodejs", "npm")
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return fmt.Errorf("failed to install dependencies: %w", err)
|
return fmt.Errorf("failed to install dependencies: %w", err)
|
||||||
}
|
}
|
||||||
@ -567,6 +567,10 @@ func (bi *BinaryInstaller) InitializeIPFSClusterConfig(nodeType, clusterPath, cl
|
|||||||
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Initializing IPFS Cluster config...\n")
|
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Initializing IPFS Cluster config...\n")
|
||||||
cmd := exec.Command(clusterBinary, "init", "--force")
|
cmd := exec.Command(clusterBinary, "init", "--force")
|
||||||
cmd.Env = append(os.Environ(), "IPFS_CLUSTER_PATH="+clusterPath)
|
cmd.Env = append(os.Environ(), "IPFS_CLUSTER_PATH="+clusterPath)
|
||||||
|
// Pass CLUSTER_SECRET to init so it writes the correct secret to service.json directly
|
||||||
|
if clusterSecret != "" {
|
||||||
|
cmd.Env = append(cmd.Env, "CLUSTER_SECRET="+clusterSecret)
|
||||||
|
}
|
||||||
if output, err := cmd.CombinedOutput(); err != nil {
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
return fmt.Errorf("failed to initialize IPFS Cluster config: %v\n%s", err, string(output))
|
return fmt.Errorf("failed to initialize IPFS Cluster config: %v\n%s", err, string(output))
|
||||||
}
|
}
|
||||||
@ -689,3 +693,28 @@ func (bi *BinaryInstaller) InitializeRQLiteDataDir(nodeType, dataDir string) err
|
|||||||
exec.Command("chown", "-R", "debros:debros", dataDir).Run()
|
exec.Command("chown", "-R", "debros:debros", dataDir).Run()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InstallAnyoneClient installs the anyone-client npm package globally
|
||||||
|
func (bi *BinaryInstaller) InstallAnyoneClient() error {
|
||||||
|
// Check if anyone-client is already available
|
||||||
|
if _, err := exec.LookPath("anyone-client"); err == nil {
|
||||||
|
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " ✓ anyone-client already installed\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " Installing anyone-client...\n")
|
||||||
|
|
||||||
|
// Install anyone-client globally via npm
|
||||||
|
cmd := exec.Command("npm", "install", "-g", "anyone-client")
|
||||||
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("failed to install anyone-client: %w\n%s", err, string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify installation
|
||||||
|
if _, err := exec.LookPath("anyone-client"); err != nil {
|
||||||
|
return fmt.Errorf("anyone-client installation failed - not found in PATH")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(bi.logWriter.(interface{ Write([]byte) (int, error) }), " ✓ anyone-client installed\n")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ type ProductionSetup struct {
|
|||||||
osDetector *OSDetector
|
osDetector *OSDetector
|
||||||
archDetector *ArchitectureDetector
|
archDetector *ArchitectureDetector
|
||||||
resourceChecker *ResourceChecker
|
resourceChecker *ResourceChecker
|
||||||
|
portChecker *PortChecker
|
||||||
fsProvisioner *FilesystemProvisioner
|
fsProvisioner *FilesystemProvisioner
|
||||||
userProvisioner *UserProvisioner
|
userProvisioner *UserProvisioner
|
||||||
stateDetector *StateDetector
|
stateDetector *StateDetector
|
||||||
@ -90,6 +91,7 @@ func NewProductionSetup(debrosHome string, logWriter io.Writer, forceReconfigure
|
|||||||
osDetector: &OSDetector{},
|
osDetector: &OSDetector{},
|
||||||
archDetector: &ArchitectureDetector{},
|
archDetector: &ArchitectureDetector{},
|
||||||
resourceChecker: NewResourceChecker(),
|
resourceChecker: NewResourceChecker(),
|
||||||
|
portChecker: NewPortChecker(),
|
||||||
fsProvisioner: NewFilesystemProvisioner(debrosHome),
|
fsProvisioner: NewFilesystemProvisioner(debrosHome),
|
||||||
userProvisioner: NewUserProvisioner("debros", debrosHome, "/bin/bash"),
|
userProvisioner: NewUserProvisioner("debros", debrosHome, "/bin/bash"),
|
||||||
stateDetector: NewStateDetector(debrosDir),
|
stateDetector: NewStateDetector(debrosDir),
|
||||||
@ -258,6 +260,11 @@ func (ps *ProductionSetup) Phase2bInstallBinaries() error {
|
|||||||
ps.logf(" ⚠️ Olric install warning: %v", err)
|
ps.logf(" ⚠️ Olric install warning: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Install anyone-client for SOCKS5 proxy
|
||||||
|
if err := ps.binaryInstaller.InstallAnyoneClient(); err != nil {
|
||||||
|
ps.logf(" ⚠️ anyone-client install warning: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Install DeBros binaries
|
// Install DeBros binaries
|
||||||
if err := ps.binaryInstaller.InstallDeBrosBinaries(ps.branch, ps.debrosHome, ps.skipRepoUpdate); err != nil {
|
if err := ps.binaryInstaller.InstallDeBrosBinaries(ps.branch, ps.debrosHome, ps.skipRepoUpdate); err != nil {
|
||||||
return fmt.Errorf("failed to install DeBros binaries: %w", err)
|
return fmt.Errorf("failed to install DeBros binaries: %w", err)
|
||||||
@ -439,9 +446,13 @@ func (ps *ProductionSetup) Phase4GenerateConfigs(isBootstrap bool, bootstrapPeer
|
|||||||
}
|
}
|
||||||
ps.logf(" ✓ Gateway config generated")
|
ps.logf(" ✓ Gateway config generated")
|
||||||
|
|
||||||
// Olric config - bind to 0.0.0.0 to listen on all interfaces
|
// Olric config - bind to vpsIP if provided, otherwise all interfaces
|
||||||
// Gateway will connect using the specific address from olricServers list above
|
// Gateway will connect using the specific address from olricServers list above
|
||||||
olricConfig, err := ps.configGenerator.GenerateOlricConfig("0.0.0.0", 3320, 3322)
|
olricBindAddr := vpsIP
|
||||||
|
if olricBindAddr == "" {
|
||||||
|
olricBindAddr = "0.0.0.0"
|
||||||
|
}
|
||||||
|
olricConfig, err := ps.configGenerator.GenerateOlricConfig(olricBindAddr, 3320, 3322)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to generate olric config: %w", err)
|
return fmt.Errorf("failed to generate olric config: %w", err)
|
||||||
}
|
}
|
||||||
@ -522,6 +533,13 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(nodeType string, vpsIP st
|
|||||||
}
|
}
|
||||||
ps.logf(" ✓ Gateway service created")
|
ps.logf(" ✓ Gateway service created")
|
||||||
|
|
||||||
|
// Anyone Client service (SOCKS5 proxy)
|
||||||
|
anyoneUnit := ps.serviceGenerator.GenerateAnyoneClientService()
|
||||||
|
if err := ps.serviceController.WriteServiceUnit("debros-anyone-client.service", anyoneUnit); err != nil {
|
||||||
|
return fmt.Errorf("failed to write Anyone Client service: %w", err)
|
||||||
|
}
|
||||||
|
ps.logf(" ✓ Anyone Client service created")
|
||||||
|
|
||||||
// Reload systemd daemon
|
// Reload systemd daemon
|
||||||
if err := ps.serviceController.DaemonReload(); err != nil {
|
if err := ps.serviceController.DaemonReload(); err != nil {
|
||||||
return fmt.Errorf("failed to reload systemd: %w", err)
|
return fmt.Errorf("failed to reload systemd: %w", err)
|
||||||
@ -529,7 +547,7 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(nodeType string, vpsIP st
|
|||||||
ps.logf(" ✓ Systemd daemon reloaded")
|
ps.logf(" ✓ Systemd daemon reloaded")
|
||||||
|
|
||||||
// Enable services (RQLite is managed by node, not as separate service)
|
// Enable services (RQLite is managed by node, not as separate service)
|
||||||
services := []string{unitName, clusterUnitName, "debros-olric.service", nodeUnitName, "debros-gateway.service"}
|
services := []string{unitName, clusterUnitName, "debros-olric.service", nodeUnitName, "debros-gateway.service", "debros-anyone-client.service"}
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
if err := ps.serviceController.EnableService(svc); err != nil {
|
if err := ps.serviceController.EnableService(svc); err != nil {
|
||||||
ps.logf(" ⚠️ Failed to enable %s: %v", svc, err)
|
ps.logf(" ⚠️ Failed to enable %s: %v", svc, err)
|
||||||
@ -541,8 +559,17 @@ func (ps *ProductionSetup) Phase5CreateSystemdServices(nodeType string, vpsIP st
|
|||||||
// Start services in dependency order
|
// Start services in dependency order
|
||||||
ps.logf(" Starting services...")
|
ps.logf(" Starting services...")
|
||||||
|
|
||||||
// Start infrastructure first (IPFS, Olric) - RQLite is managed by node
|
// Start infrastructure first (IPFS, Olric, Anyone Client) - RQLite is managed by node
|
||||||
infraServices := []string{unitName, "debros-olric.service"}
|
infraServices := []string{unitName, "debros-olric.service"}
|
||||||
|
|
||||||
|
// Check if port 9050 is already in use (e.g., another anyone-client or similar service)
|
||||||
|
if ps.portChecker.IsPortInUse(9050) {
|
||||||
|
ps.logf(" ℹ️ Port 9050 is already in use (anyone-client or similar service running)")
|
||||||
|
ps.logf(" ℹ️ Skipping debros-anyone-client startup - using existing service")
|
||||||
|
} else {
|
||||||
|
infraServices = append(infraServices, "debros-anyone-client.service")
|
||||||
|
}
|
||||||
|
|
||||||
for _, svc := range infraServices {
|
for _, svc := range infraServices {
|
||||||
if err := ps.serviceController.StartService(svc); err != nil {
|
if err := ps.serviceController.StartService(svc); err != nil {
|
||||||
ps.logf(" ⚠️ Failed to start %s: %v", svc, err)
|
ps.logf(" ⚠️ Failed to start %s: %v", svc, err)
|
||||||
@ -592,9 +619,11 @@ func (ps *ProductionSetup) LogSetupComplete(peerID string) {
|
|||||||
ps.logf(" %s/logs/olric.log", ps.debrosDir)
|
ps.logf(" %s/logs/olric.log", ps.debrosDir)
|
||||||
ps.logf(" %s/logs/node-bootstrap.log", ps.debrosDir)
|
ps.logf(" %s/logs/node-bootstrap.log", ps.debrosDir)
|
||||||
ps.logf(" %s/logs/gateway.log", ps.debrosDir)
|
ps.logf(" %s/logs/gateway.log", ps.debrosDir)
|
||||||
|
ps.logf(" %s/logs/anyone-client.log", ps.debrosDir)
|
||||||
ps.logf("\nStart All Services:")
|
ps.logf("\nStart All Services:")
|
||||||
ps.logf(" systemctl start debros-ipfs-bootstrap debros-ipfs-cluster-bootstrap debros-olric debros-node-bootstrap debros-gateway")
|
ps.logf(" systemctl start debros-ipfs-bootstrap debros-ipfs-cluster-bootstrap debros-olric debros-anyone-client debros-node-bootstrap debros-gateway")
|
||||||
ps.logf("\nVerify Installation:")
|
ps.logf("\nVerify Installation:")
|
||||||
ps.logf(" curl http://localhost:6001/health")
|
ps.logf(" curl http://localhost:6001/health")
|
||||||
ps.logf(" curl http://localhost:5001/status\n")
|
ps.logf(" curl http://localhost:5001/status")
|
||||||
|
ps.logf(" # Anyone Client SOCKS5 proxy on localhost:9050\n")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -266,6 +266,37 @@ WantedBy=multi-user.target
|
|||||||
`, nodeService, olricService, nodeService, olricService, ssg.debrosHome, ssg.debrosHome, ssg.debrosHome, ssg.debrosDir, logFile, logFile, ssg.debrosDir)
|
`, nodeService, olricService, nodeService, olricService, ssg.debrosHome, ssg.debrosHome, ssg.debrosHome, ssg.debrosDir, logFile, logFile, ssg.debrosDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateAnyoneClientService generates the Anyone Client SOCKS5 proxy systemd unit
|
||||||
|
func (ssg *SystemdServiceGenerator) GenerateAnyoneClientService() string {
|
||||||
|
logFile := filepath.Join(ssg.debrosDir, "logs", "anyone-client.log")
|
||||||
|
|
||||||
|
return fmt.Sprintf(`[Unit]
|
||||||
|
Description=Anyone Client SOCKS5 Proxy
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=debros
|
||||||
|
Group=debros
|
||||||
|
Environment=HOME=%[1]s
|
||||||
|
ExecStart=/usr/bin/env anyone-client
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
StandardOutput=file:%[2]s
|
||||||
|
StandardError=file:%[2]s
|
||||||
|
SyslogIdentifier=anyone-client
|
||||||
|
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
PrivateTmp=yes
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=%[3]s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
`, ssg.debrosHome, logFile, ssg.debrosDir)
|
||||||
|
}
|
||||||
|
|
||||||
// SystemdController manages systemd service operations
|
// SystemdController manages systemd service operations
|
||||||
type SystemdController struct {
|
type SystemdController struct {
|
||||||
systemdDir string
|
systemdDir string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user