mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-11 10:18:50 +00:00
- Added a new ResourceChecker type to validate system resources including disk space, RAM, and CPU cores. - Implemented CheckDiskSpace, CheckRAM, and CheckCPU methods to ensure minimum requirements are met for production deployment. - Integrated resource checks into the ProductionSetup's Phase1CheckPrerequisites method to enhance deployment reliability. - Updated systemd service generation to log output to specific log files instead of the journal for better log management.
344 lines
9.2 KiB
Go
344 lines
9.2 KiB
Go
package production
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// SystemdServiceGenerator generates systemd unit files
|
|
type SystemdServiceGenerator struct {
|
|
debrosHome string
|
|
debrosDir string
|
|
}
|
|
|
|
// NewSystemdServiceGenerator creates a new service generator
|
|
func NewSystemdServiceGenerator(debrosHome, debrosDir string) *SystemdServiceGenerator {
|
|
return &SystemdServiceGenerator{
|
|
debrosHome: debrosHome,
|
|
debrosDir: debrosDir,
|
|
}
|
|
}
|
|
|
|
// GenerateIPFSService generates the IPFS daemon systemd unit
|
|
func (ssg *SystemdServiceGenerator) GenerateIPFSService(nodeType string) string {
|
|
var ipfsRepoPath string
|
|
if nodeType == "bootstrap" {
|
|
ipfsRepoPath = filepath.Join(ssg.debrosDir, "data", "bootstrap", "ipfs", "repo")
|
|
} else {
|
|
ipfsRepoPath = filepath.Join(ssg.debrosDir, "data", "node", "ipfs", "repo")
|
|
}
|
|
|
|
logFile := filepath.Join(ssg.debrosDir, "logs", fmt.Sprintf("ipfs-%s.log", nodeType))
|
|
|
|
return fmt.Sprintf(`[Unit]
|
|
Description=IPFS Daemon (%s)
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=debros
|
|
Group=debros
|
|
Environment=HOME=%s
|
|
Environment=IPFS_PATH=%s
|
|
ExecStartPre=/bin/bash -c 'if [ -f %s/secrets/swarm.key ] && [ ! -f %s/swarm.key ]; then cp %s/secrets/swarm.key %s/swarm.key && chmod 600 %s/swarm.key; fi'
|
|
ExecStart=/usr/bin/ipfs daemon --enable-pubsub-experiment --repo-dir=%s
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=file:%s
|
|
StandardError=file:%s
|
|
SyslogIdentifier=ipfs-%s
|
|
|
|
NoNewPrivileges=yes
|
|
PrivateTmp=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths=%s
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`, nodeType, ssg.debrosHome, ipfsRepoPath, ssg.debrosDir, ipfsRepoPath, ssg.debrosDir, ipfsRepoPath, ipfsRepoPath, ipfsRepoPath, logFile, logFile, nodeType, ssg.debrosDir)
|
|
}
|
|
|
|
// GenerateIPFSClusterService generates the IPFS Cluster systemd unit
|
|
func (ssg *SystemdServiceGenerator) GenerateIPFSClusterService(nodeType string) string {
|
|
var clusterPath string
|
|
if nodeType == "bootstrap" {
|
|
clusterPath = filepath.Join(ssg.debrosDir, "data", "bootstrap", "ipfs-cluster")
|
|
} else {
|
|
clusterPath = filepath.Join(ssg.debrosDir, "data", "node", "ipfs-cluster")
|
|
}
|
|
|
|
logFile := filepath.Join(ssg.debrosDir, "logs", fmt.Sprintf("ipfs-cluster-%s.log", nodeType))
|
|
|
|
return fmt.Sprintf(`[Unit]
|
|
Description=IPFS Cluster Service (%s)
|
|
After=debros-ipfs-%s.service
|
|
Wants=debros-ipfs-%s.service
|
|
Requires=debros-ipfs-%s.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=debros
|
|
Group=debros
|
|
WorkingDirectory=%s
|
|
Environment=HOME=%s
|
|
Environment=IPFS_CLUSTER_PATH=%s
|
|
ExecStart=/usr/local/bin/ipfs-cluster-service daemon
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=file:%s
|
|
StandardError=file:%s
|
|
SyslogIdentifier=ipfs-cluster-%s
|
|
|
|
NoNewPrivileges=yes
|
|
PrivateTmp=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths=%s
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`, nodeType, nodeType, nodeType, nodeType, ssg.debrosHome, ssg.debrosHome, clusterPath, logFile, logFile, nodeType, ssg.debrosDir)
|
|
}
|
|
|
|
// GenerateRQLiteService generates the RQLite systemd unit
|
|
func (ssg *SystemdServiceGenerator) GenerateRQLiteService(nodeType string, httpPort, raftPort int, joinAddr string) string {
|
|
var dataDir string
|
|
if nodeType == "bootstrap" {
|
|
dataDir = filepath.Join(ssg.debrosDir, "data", "bootstrap", "rqlite")
|
|
} else {
|
|
dataDir = filepath.Join(ssg.debrosDir, "data", "node", "rqlite")
|
|
}
|
|
|
|
args := fmt.Sprintf(
|
|
`-http-addr 0.0.0.0:%d -http-adv-addr 127.0.0.1:%d -raft-adv-addr 127.0.0.1:%d -raft-addr 0.0.0.0:%d`,
|
|
httpPort, httpPort, raftPort, raftPort,
|
|
)
|
|
|
|
if joinAddr != "" {
|
|
args += fmt.Sprintf(` -join %s -join-attempts 30 -join-interval 10s`, joinAddr)
|
|
}
|
|
|
|
args += fmt.Sprintf(` %s`, dataDir)
|
|
|
|
logFile := filepath.Join(ssg.debrosDir, "logs", fmt.Sprintf("rqlite-%s.log", nodeType))
|
|
|
|
return fmt.Sprintf(`[Unit]
|
|
Description=RQLite Database (%s)
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=debros
|
|
Group=debros
|
|
Environment=HOME=%s
|
|
ExecStart=/usr/local/bin/rqlited %s
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=file:%s
|
|
StandardError=file:%s
|
|
SyslogIdentifier=rqlite-%s
|
|
|
|
NoNewPrivileges=yes
|
|
PrivateTmp=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths=%s
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`, nodeType, ssg.debrosHome, args, logFile, logFile, nodeType, ssg.debrosDir)
|
|
}
|
|
|
|
// GenerateOlricService generates the Olric systemd unit
|
|
func (ssg *SystemdServiceGenerator) GenerateOlricService() string {
|
|
olricConfigPath := filepath.Join(ssg.debrosDir, "configs", "olric", "config.yaml")
|
|
logFile := filepath.Join(ssg.debrosDir, "logs", "olric.log")
|
|
|
|
return fmt.Sprintf(`[Unit]
|
|
Description=Olric Cache Server
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=debros
|
|
Group=debros
|
|
Environment=HOME=%s
|
|
Environment=OLRIC_SERVER_CONFIG=%s
|
|
ExecStart=/usr/local/bin/olric-server
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=file:%s
|
|
StandardError=file:%s
|
|
SyslogIdentifier=olric
|
|
|
|
NoNewPrivileges=yes
|
|
PrivateTmp=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths=%s
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`, ssg.debrosHome, olricConfigPath, logFile, logFile, ssg.debrosDir)
|
|
}
|
|
|
|
// GenerateNodeService generates the DeBros Node systemd unit
|
|
func (ssg *SystemdServiceGenerator) GenerateNodeService(nodeType string) string {
|
|
var configFile string
|
|
if nodeType == "bootstrap" {
|
|
configFile = "bootstrap.yaml"
|
|
} else {
|
|
configFile = "node.yaml"
|
|
}
|
|
|
|
logFile := filepath.Join(ssg.debrosDir, "logs", fmt.Sprintf("node-%s.log", nodeType))
|
|
|
|
return fmt.Sprintf(`[Unit]
|
|
Description=DeBros Network Node (%s)
|
|
After=debros-ipfs-cluster-%s.service
|
|
Wants=debros-ipfs-cluster-%s.service
|
|
Requires=debros-ipfs-cluster-%s.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=debros
|
|
Group=debros
|
|
WorkingDirectory=%s
|
|
Environment=HOME=%s
|
|
ExecStart=%s/bin/node --config %s/configs/%s
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=file:%s
|
|
StandardError=file:%s
|
|
SyslogIdentifier=debros-node-%s
|
|
|
|
NoNewPrivileges=yes
|
|
PrivateTmp=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths=%s
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`, nodeType, nodeType, nodeType, nodeType, ssg.debrosHome, ssg.debrosHome, ssg.debrosHome, ssg.debrosDir, configFile, logFile, logFile, nodeType, ssg.debrosDir)
|
|
}
|
|
|
|
// GenerateGatewayService generates the DeBros Gateway systemd unit
|
|
func (ssg *SystemdServiceGenerator) GenerateGatewayService(nodeType string) string {
|
|
nodeService := fmt.Sprintf("debros-node-%s.service", nodeType)
|
|
logFile := filepath.Join(ssg.debrosDir, "logs", "gateway.log")
|
|
return fmt.Sprintf(`[Unit]
|
|
Description=DeBros Gateway
|
|
After=%s
|
|
Wants=%s
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=debros
|
|
Group=debros
|
|
WorkingDirectory=%s
|
|
Environment=HOME=%s
|
|
ExecStart=%s/bin/gateway --config %s/configs/gateway.yaml
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=file:%s
|
|
StandardError=file:%s
|
|
SyslogIdentifier=debros-gateway
|
|
|
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
|
|
|
NoNewPrivileges=yes
|
|
PrivateTmp=yes
|
|
ProtectSystem=strict
|
|
ReadWritePaths=%s
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`, nodeService, nodeService, ssg.debrosHome, ssg.debrosHome, ssg.debrosHome, ssg.debrosDir, logFile, logFile, ssg.debrosDir)
|
|
}
|
|
|
|
// SystemdController manages systemd service operations
|
|
type SystemdController struct {
|
|
systemdDir string
|
|
}
|
|
|
|
// NewSystemdController creates a new controller
|
|
func NewSystemdController() *SystemdController {
|
|
return &SystemdController{
|
|
systemdDir: "/etc/systemd/system",
|
|
}
|
|
}
|
|
|
|
// WriteServiceUnit writes a systemd unit file
|
|
func (sc *SystemdController) WriteServiceUnit(name string, content string) error {
|
|
unitPath := filepath.Join(sc.systemdDir, name)
|
|
if err := os.WriteFile(unitPath, []byte(content), 0644); err != nil {
|
|
return fmt.Errorf("failed to write unit file %s: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DaemonReload reloads the systemd daemon
|
|
func (sc *SystemdController) DaemonReload() error {
|
|
cmd := exec.Command("systemctl", "daemon-reload")
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("failed to reload systemd daemon: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// EnableService enables a service to start on boot
|
|
func (sc *SystemdController) EnableService(name string) error {
|
|
cmd := exec.Command("systemctl", "enable", name)
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("failed to enable service %s: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StartService starts a service immediately
|
|
func (sc *SystemdController) StartService(name string) error {
|
|
cmd := exec.Command("systemctl", "start", name)
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("failed to start service %s: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RestartService restarts a service
|
|
func (sc *SystemdController) RestartService(name string) error {
|
|
cmd := exec.Command("systemctl", "restart", name)
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("failed to restart service %s: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StopService stops a service
|
|
func (sc *SystemdController) StopService(name string) error {
|
|
cmd := exec.Command("systemctl", "stop", name)
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("failed to stop service %s: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// StatusService gets the status of a service
|
|
func (sc *SystemdController) StatusService(name string) (bool, error) {
|
|
cmd := exec.Command("systemctl", "is-active", "--quiet", name)
|
|
err := cmd.Run()
|
|
if err == nil {
|
|
return true, nil
|
|
}
|
|
|
|
// Check for "inactive" vs actual error
|
|
if strings.Contains(err.Error(), "exit status 3") {
|
|
return false, nil // Service is inactive
|
|
}
|
|
|
|
return false, fmt.Errorf("failed to check service status %s: %w", name, err)
|
|
}
|