mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 06:43:01 +00:00
Updated installation process simplified it
This commit is contained in:
parent
749d5ed5e7
commit
ba4e2688e4
2
Makefile
2
Makefile
@ -94,6 +94,8 @@ build-linux: deps
|
|||||||
GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS_LINUX)" -trimpath -o bin-linux/orama-cli ./cmd/cli
|
GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS_LINUX)" -trimpath -o bin-linux/orama-cli ./cmd/cli
|
||||||
@echo "Building Olric for linux/amd64..."
|
@echo "Building Olric for linux/amd64..."
|
||||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o bin-linux/olric-server github.com/olric-data/olric/cmd/olric-server
|
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o bin-linux/olric-server github.com/olric-data/olric/cmd/olric-server
|
||||||
|
@echo "Building IPFS Cluster Service for linux/amd64..."
|
||||||
|
GOOS=linux GOARCH=amd64 GOBIN=$(CURDIR)/bin-linux go install -ldflags "-s -w" -trimpath github.com/ipfs-cluster/ipfs-cluster/cmd/ipfs-cluster-service@latest
|
||||||
@echo "✓ All Linux binaries built in bin-linux/"
|
@echo "✓ All Linux binaries built in bin-linux/"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Next steps:"
|
@echo "Next steps:"
|
||||||
|
|||||||
@ -14,7 +14,26 @@ func Handle(args []string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create orchestrator
|
// Resolve base domain interactively if not provided (before local/VPS branch)
|
||||||
|
if flags.BaseDomain == "" {
|
||||||
|
flags.BaseDomain = promptForBaseDomain()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local mode: not running as root → orchestrate install via SSH
|
||||||
|
if os.Geteuid() != 0 {
|
||||||
|
remote, err := NewRemoteOrchestrator(flags)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err := remote.Execute(); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// VPS mode: running as root on the VPS — existing behavior
|
||||||
orchestrator, err := NewOrchestrator(flags)
|
orchestrator, err := NewOrchestrator(flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
||||||
@ -27,12 +46,6 @@ func Handle(args []string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check root privileges
|
|
||||||
if err := orchestrator.validator.ValidateRootPrivileges(); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check port availability before proceeding
|
// Check port availability before proceeding
|
||||||
if err := orchestrator.validator.ValidatePorts(); err != nil {
|
if err := orchestrator.validator.ValidatePorts(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
fmt.Fprintf(os.Stderr, "❌ %v\n", err)
|
||||||
|
|||||||
@ -8,15 +8,12 @@ import (
|
|||||||
|
|
||||||
// Flags represents install command flags
|
// Flags represents install command flags
|
||||||
type Flags struct {
|
type Flags struct {
|
||||||
VpsIP string
|
VpsIP string
|
||||||
Domain string
|
Domain string
|
||||||
BaseDomain string // Base domain for deployment routing (e.g., "dbrs.space")
|
BaseDomain string // Base domain for deployment routing (e.g., "dbrs.space")
|
||||||
Branch string
|
Force bool
|
||||||
NoPull bool
|
DryRun bool
|
||||||
Force bool
|
SkipChecks bool
|
||||||
DryRun bool
|
|
||||||
SkipChecks bool
|
|
||||||
PreBuilt bool // Skip building binaries, use pre-built binaries already on disk
|
|
||||||
Nameserver bool // Make this node a nameserver (runs CoreDNS + Caddy)
|
Nameserver bool // Make this node a nameserver (runs CoreDNS + Caddy)
|
||||||
JoinAddress string // HTTPS URL of existing node (e.g., https://node1.dbrs.space)
|
JoinAddress string // HTTPS URL of existing node (e.g., https://node1.dbrs.space)
|
||||||
Token string // Invite token for joining (from orama invite)
|
Token string // Invite token for joining (from orama invite)
|
||||||
@ -57,12 +54,9 @@ func ParseFlags(args []string) (*Flags, error) {
|
|||||||
fs.StringVar(&flags.VpsIP, "vps-ip", "", "Public IP of this VPS (required)")
|
fs.StringVar(&flags.VpsIP, "vps-ip", "", "Public IP of this VPS (required)")
|
||||||
fs.StringVar(&flags.Domain, "domain", "", "Domain name for HTTPS (optional, e.g. gateway.example.com)")
|
fs.StringVar(&flags.Domain, "domain", "", "Domain name for HTTPS (optional, e.g. gateway.example.com)")
|
||||||
fs.StringVar(&flags.BaseDomain, "base-domain", "", "Base domain for deployment routing (e.g., dbrs.space)")
|
fs.StringVar(&flags.BaseDomain, "base-domain", "", "Base domain for deployment routing (e.g., dbrs.space)")
|
||||||
fs.StringVar(&flags.Branch, "branch", "main", "Git branch to use (main or nightly)")
|
|
||||||
fs.BoolVar(&flags.NoPull, "no-pull", false, "Skip git clone/pull, use existing repository in /home/debros/src")
|
|
||||||
fs.BoolVar(&flags.Force, "force", false, "Force reconfiguration even if already installed")
|
fs.BoolVar(&flags.Force, "force", false, "Force reconfiguration even if already installed")
|
||||||
fs.BoolVar(&flags.DryRun, "dry-run", false, "Show what would be done without making changes")
|
fs.BoolVar(&flags.DryRun, "dry-run", false, "Show what would be done without making changes")
|
||||||
fs.BoolVar(&flags.SkipChecks, "skip-checks", false, "Skip minimum resource checks (RAM/CPU)")
|
fs.BoolVar(&flags.SkipChecks, "skip-checks", false, "Skip minimum resource checks (RAM/CPU)")
|
||||||
fs.BoolVar(&flags.PreBuilt, "pre-built", false, "Skip building binaries on VPS, use pre-built binaries already in /home/debros/bin and /usr/local/bin")
|
|
||||||
fs.BoolVar(&flags.Nameserver, "nameserver", false, "Make this node a nameserver (runs CoreDNS + Caddy)")
|
fs.BoolVar(&flags.Nameserver, "nameserver", false, "Make this node a nameserver (runs CoreDNS + Caddy)")
|
||||||
|
|
||||||
// Cluster join flags
|
// Cluster join flags
|
||||||
|
|||||||
@ -33,18 +33,13 @@ func NewOrchestrator(flags *Flags) (*Orchestrator, error) {
|
|||||||
oramaHome := "/home/debros"
|
oramaHome := "/home/debros"
|
||||||
oramaDir := oramaHome + "/.orama"
|
oramaDir := oramaHome + "/.orama"
|
||||||
|
|
||||||
// Prompt for base domain if not provided via flag
|
|
||||||
if flags.BaseDomain == "" {
|
|
||||||
flags.BaseDomain = promptForBaseDomain()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize peers
|
// Normalize peers
|
||||||
peers, err := utils.NormalizePeers(flags.PeersStr)
|
peers, err := utils.NormalizePeers(flags.PeersStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid peers: %w", err)
|
return nil, fmt.Errorf("invalid peers: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, flags.Branch, flags.NoPull, flags.SkipChecks, flags.PreBuilt)
|
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, flags.SkipChecks)
|
||||||
setup.SetNameserver(flags.Nameserver)
|
setup.SetNameserver(flags.Nameserver)
|
||||||
|
|
||||||
// Configure Anyone mode
|
// Configure Anyone mode
|
||||||
@ -84,18 +79,6 @@ func NewOrchestrator(flags *Flags) (*Orchestrator, error) {
|
|||||||
func (o *Orchestrator) Execute() error {
|
func (o *Orchestrator) Execute() error {
|
||||||
fmt.Printf("🚀 Starting production installation...\n\n")
|
fmt.Printf("🚀 Starting production installation...\n\n")
|
||||||
|
|
||||||
// Inform user if skipping git pull
|
|
||||||
if o.flags.NoPull {
|
|
||||||
fmt.Printf(" ⚠️ --no-pull flag enabled: Skipping git clone/pull\n")
|
|
||||||
fmt.Printf(" Using existing repository at /home/debros/src\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inform user if using pre-built binaries
|
|
||||||
if o.flags.PreBuilt {
|
|
||||||
fmt.Printf(" ⚠️ --pre-built flag enabled: Skipping all Go compilation\n")
|
|
||||||
fmt.Printf(" Using pre-built binaries from /home/debros/bin and /usr/local/bin\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate DNS if domain is provided
|
// Validate DNS if domain is provided
|
||||||
o.validator.ValidateDNS()
|
o.validator.ValidateDNS()
|
||||||
|
|
||||||
@ -112,7 +95,7 @@ func (o *Orchestrator) Execute() error {
|
|||||||
ORPort: o.flags.AnyoneORPort,
|
ORPort: o.flags.AnyoneORPort,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
utils.ShowDryRunSummaryWithRelay(o.flags.VpsIP, o.flags.Domain, o.flags.Branch, o.peers, o.flags.JoinAddress, o.validator.IsFirstNode(), o.oramaDir, relayInfo)
|
utils.ShowDryRunSummaryWithRelay(o.flags.VpsIP, o.flags.Domain, "main", o.peers, o.flags.JoinAddress, o.validator.IsFirstNode(), o.oramaDir, relayInfo)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +114,7 @@ func (o *Orchestrator) Execute() error {
|
|||||||
anyoneORPort = 9001
|
anyoneORPort = 9001
|
||||||
}
|
}
|
||||||
prefs := &production.NodePreferences{
|
prefs := &production.NodePreferences{
|
||||||
Branch: o.flags.Branch,
|
Branch: "main",
|
||||||
Nameserver: o.flags.Nameserver,
|
Nameserver: o.flags.Nameserver,
|
||||||
AnyoneClient: o.flags.AnyoneClient,
|
AnyoneClient: o.flags.AnyoneClient,
|
||||||
AnyoneRelay: o.flags.AnyoneRelay,
|
AnyoneRelay: o.flags.AnyoneRelay,
|
||||||
|
|||||||
@ -10,10 +10,7 @@ import (
|
|||||||
type Flags struct {
|
type Flags struct {
|
||||||
Force bool
|
Force bool
|
||||||
RestartServices bool
|
RestartServices bool
|
||||||
NoPull bool
|
|
||||||
PreBuilt bool
|
|
||||||
SkipChecks bool
|
SkipChecks bool
|
||||||
Branch string
|
|
||||||
Nameserver *bool // Pointer so we can detect if explicitly set vs default
|
Nameserver *bool // Pointer so we can detect if explicitly set vs default
|
||||||
|
|
||||||
// Anyone flags
|
// Anyone flags
|
||||||
@ -39,10 +36,7 @@ func ParseFlags(args []string) (*Flags, error) {
|
|||||||
|
|
||||||
fs.BoolVar(&flags.Force, "force", false, "Reconfigure all settings")
|
fs.BoolVar(&flags.Force, "force", false, "Reconfigure all settings")
|
||||||
fs.BoolVar(&flags.RestartServices, "restart", false, "Automatically restart services after upgrade")
|
fs.BoolVar(&flags.RestartServices, "restart", false, "Automatically restart services after upgrade")
|
||||||
fs.BoolVar(&flags.NoPull, "no-pull", false, "Skip source download, use existing /home/debros/src")
|
|
||||||
fs.BoolVar(&flags.PreBuilt, "pre-built", false, "Skip building binaries on VPS, use pre-built binaries already in /home/debros/bin and /usr/local/bin")
|
|
||||||
fs.BoolVar(&flags.SkipChecks, "skip-checks", false, "Skip minimum resource checks (RAM/CPU)")
|
fs.BoolVar(&flags.SkipChecks, "skip-checks", false, "Skip minimum resource checks (RAM/CPU)")
|
||||||
fs.StringVar(&flags.Branch, "branch", "", "Git branch to use (uses saved preference if not specified)")
|
|
||||||
|
|
||||||
// Nameserver flag - use pointer to detect if explicitly set
|
// Nameserver flag - use pointer to detect if explicitly set
|
||||||
nameserver := fs.Bool("nameserver", false, "Make this node a nameserver (uses saved preference if not specified)")
|
nameserver := fs.Bool("nameserver", false, "Make this node a nameserver (uses saved preference if not specified)")
|
||||||
|
|||||||
@ -32,19 +32,13 @@ func NewOrchestrator(flags *Flags) *Orchestrator {
|
|||||||
// Load existing preferences
|
// Load existing preferences
|
||||||
prefs := production.LoadPreferences(oramaDir)
|
prefs := production.LoadPreferences(oramaDir)
|
||||||
|
|
||||||
// Use saved branch if not specified
|
|
||||||
branch := flags.Branch
|
|
||||||
if branch == "" {
|
|
||||||
branch = prefs.Branch
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use saved nameserver preference if not explicitly specified
|
// Use saved nameserver preference if not explicitly specified
|
||||||
isNameserver := prefs.Nameserver
|
isNameserver := prefs.Nameserver
|
||||||
if flags.Nameserver != nil {
|
if flags.Nameserver != nil {
|
||||||
isNameserver = *flags.Nameserver
|
isNameserver = *flags.Nameserver
|
||||||
}
|
}
|
||||||
|
|
||||||
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, branch, flags.NoPull, flags.SkipChecks, flags.PreBuilt)
|
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, flags.SkipChecks)
|
||||||
setup.SetNameserver(isNameserver)
|
setup.SetNameserver(isNameserver)
|
||||||
|
|
||||||
// Configure Anyone mode (flag > saved preference > auto-detect)
|
// Configure Anyone mode (flag > saved preference > auto-detect)
|
||||||
@ -103,18 +97,6 @@ func (o *Orchestrator) Execute() error {
|
|||||||
fmt.Printf(" This will preserve existing configurations and data\n")
|
fmt.Printf(" This will preserve existing configurations and data\n")
|
||||||
fmt.Printf(" Configurations will be updated to latest format\n\n")
|
fmt.Printf(" Configurations will be updated to latest format\n\n")
|
||||||
|
|
||||||
// Log if --no-pull is enabled
|
|
||||||
if o.flags.NoPull {
|
|
||||||
fmt.Printf(" ⚠️ --no-pull flag enabled: Skipping git clone/pull\n")
|
|
||||||
fmt.Printf(" Using existing repository at %s/src\n", o.oramaHome)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log if --pre-built is enabled
|
|
||||||
if o.flags.PreBuilt {
|
|
||||||
fmt.Printf(" ⚠️ --pre-built flag enabled: Skipping all Go compilation\n")
|
|
||||||
fmt.Printf(" Using pre-built binaries from %s/bin and /usr/local/bin\n", o.oramaHome)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle branch preferences
|
// Handle branch preferences
|
||||||
if err := o.handleBranchPreferences(); err != nil {
|
if err := o.handleBranchPreferences(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -216,15 +198,6 @@ func (o *Orchestrator) handleBranchPreferences() error {
|
|||||||
prefs := production.LoadPreferences(o.oramaDir)
|
prefs := production.LoadPreferences(o.oramaDir)
|
||||||
prefsChanged := false
|
prefsChanged := false
|
||||||
|
|
||||||
// If branch was explicitly provided, update it
|
|
||||||
if o.flags.Branch != "" {
|
|
||||||
prefs.Branch = o.flags.Branch
|
|
||||||
prefsChanged = true
|
|
||||||
fmt.Printf(" Using branch: %s (saved for future upgrades)\n", o.flags.Branch)
|
|
||||||
} else {
|
|
||||||
fmt.Printf(" Using branch: %s (from saved preference)\n", prefs.Branch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If nameserver was explicitly provided, update it
|
// If nameserver was explicitly provided, update it
|
||||||
if o.flags.Nameserver != nil {
|
if o.flags.Nameserver != nil {
|
||||||
prefs.Nameserver = *o.flags.Nameserver
|
prefs.Nameserver = *o.flags.Nameserver
|
||||||
|
|||||||
@ -116,66 +116,84 @@ func (ad *ArchitectureDetector) Detect() (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DependencyChecker validates external tool availability
|
// DependencyChecker validates external tool availability and auto-installs missing ones
|
||||||
type DependencyChecker struct {
|
type DependencyChecker struct{}
|
||||||
skipOptional bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDependencyChecker creates a new checker
|
// NewDependencyChecker creates a new checker
|
||||||
func NewDependencyChecker(skipOptional bool) *DependencyChecker {
|
func NewDependencyChecker(_ bool) *DependencyChecker {
|
||||||
return &DependencyChecker{
|
return &DependencyChecker{}
|
||||||
skipOptional: skipOptional,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dependency represents an external binary dependency
|
// Dependency represents an external binary dependency
|
||||||
type Dependency struct {
|
type Dependency struct {
|
||||||
Name string
|
Name string
|
||||||
Command string
|
Command string
|
||||||
Optional bool
|
AptPkg string // apt package name to install
|
||||||
InstallHint string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckAll validates all required dependencies
|
// CheckAll validates all required dependencies, auto-installing any that are missing.
|
||||||
func (dc *DependencyChecker) CheckAll() ([]Dependency, error) {
|
func (dc *DependencyChecker) CheckAll() ([]Dependency, error) {
|
||||||
dependencies := []Dependency{
|
dependencies := []Dependency{
|
||||||
{
|
{Name: "curl", Command: "curl", AptPkg: "curl"},
|
||||||
Name: "curl",
|
{Name: "git", Command: "git", AptPkg: "git"},
|
||||||
Command: "curl",
|
{Name: "make", Command: "make", AptPkg: "make"},
|
||||||
Optional: false,
|
{Name: "jq", Command: "jq", AptPkg: "jq"},
|
||||||
InstallHint: "Usually pre-installed; if missing: apt-get install curl",
|
{Name: "speedtest", Command: "speedtest-cli", AptPkg: "speedtest-cli"},
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "git",
|
|
||||||
Command: "git",
|
|
||||||
Optional: false,
|
|
||||||
InstallHint: "Install with: apt-get install git",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "make",
|
|
||||||
Command: "make",
|
|
||||||
Optional: false,
|
|
||||||
InstallHint: "Install with: apt-get install make",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var missing []Dependency
|
var missing []Dependency
|
||||||
for _, dep := range dependencies {
|
for _, dep := range dependencies {
|
||||||
if _, err := exec.LookPath(dep.Command); err != nil {
|
if _, err := exec.LookPath(dep.Command); err != nil {
|
||||||
if !dep.Optional || !dc.skipOptional {
|
missing = append(missing, dep)
|
||||||
missing = append(missing, dep)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(missing) > 0 {
|
if len(missing) == 0 {
|
||||||
errMsg := "missing required dependencies:\n"
|
return nil, nil
|
||||||
for _, dep := range missing {
|
|
||||||
errMsg += fmt.Sprintf(" - %s (%s): %s\n", dep.Name, dep.Command, dep.InstallHint)
|
|
||||||
}
|
|
||||||
return missing, fmt.Errorf("%s", errMsg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-install missing dependencies
|
||||||
|
var pkgs []string
|
||||||
|
var names []string
|
||||||
|
for _, dep := range missing {
|
||||||
|
pkgs = append(pkgs, dep.AptPkg)
|
||||||
|
names = append(names, dep.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, " Installing missing dependencies: %s\n", strings.Join(names, ", "))
|
||||||
|
|
||||||
|
// apt-get update first
|
||||||
|
update := exec.Command("apt-get", "update", "-qq")
|
||||||
|
update.Stdout = os.Stdout
|
||||||
|
update.Stderr = os.Stderr
|
||||||
|
update.Run() // best-effort, don't fail on update
|
||||||
|
|
||||||
|
// apt-get install
|
||||||
|
args := append([]string{"install", "-y", "-qq"}, pkgs...)
|
||||||
|
install := exec.Command("apt-get", args...)
|
||||||
|
install.Stdout = os.Stdout
|
||||||
|
install.Stderr = os.Stderr
|
||||||
|
if err := install.Run(); err != nil {
|
||||||
|
return missing, fmt.Errorf("failed to install dependencies (%s): %w", strings.Join(names, ", "), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify after install
|
||||||
|
var stillMissing []Dependency
|
||||||
|
for _, dep := range missing {
|
||||||
|
if _, err := exec.LookPath(dep.Command); err != nil {
|
||||||
|
stillMissing = append(stillMissing, dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(stillMissing) > 0 {
|
||||||
|
errMsg := "dependencies still missing after install attempt:\n"
|
||||||
|
for _, dep := range stillMissing {
|
||||||
|
errMsg += fmt.Sprintf(" - %s\n", dep.Name)
|
||||||
|
}
|
||||||
|
return stillMissing, fmt.Errorf("%s", errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, " ✓ Dependencies installed successfully\n")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -72,9 +72,9 @@ func (bi *BinaryInstaller) ResolveBinaryPath(binary string, extraPaths ...string
|
|||||||
return installers.ResolveBinaryPath(binary, extraPaths...)
|
return installers.ResolveBinaryPath(binary, extraPaths...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallDeBrosBinaries clones and builds DeBros binaries
|
// InstallDeBrosBinaries builds DeBros binaries from source
|
||||||
func (bi *BinaryInstaller) InstallDeBrosBinaries(branch string, oramaHome string, skipRepoUpdate bool) error {
|
func (bi *BinaryInstaller) InstallDeBrosBinaries(oramaHome string) error {
|
||||||
return bi.gateway.InstallDeBrosBinaries(branch, oramaHome, skipRepoUpdate)
|
return bi.gateway.InstallDeBrosBinaries(oramaHome)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallSystemDependencies installs system-level dependencies via apt
|
// InstallSystemDependencies installs system-level dependencies via apt
|
||||||
|
|||||||
@ -39,78 +39,9 @@ func (gi *GatewayInstaller) Configure() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadSourceZIP downloads source code as ZIP from GitHub
|
// InstallDeBrosBinaries builds DeBros binaries from source at /home/debros/src.
|
||||||
// This is simpler and more reliable than git clone with shallow clones
|
// Source must already be present (uploaded via SCP archive).
|
||||||
func (gi *GatewayInstaller) downloadSourceZIP(branch string, srcDir string) error {
|
func (gi *GatewayInstaller) InstallDeBrosBinaries(oramaHome string) error {
|
||||||
// GitHub archive URL format
|
|
||||||
zipURL := fmt.Sprintf("https://github.com/DeBrosOfficial/network/archive/refs/heads/%s.zip", branch)
|
|
||||||
zipPath := "/tmp/network-source.zip"
|
|
||||||
extractDir := "/tmp/network-extract"
|
|
||||||
|
|
||||||
// Clean up any previous download artifacts
|
|
||||||
os.RemoveAll(zipPath)
|
|
||||||
os.RemoveAll(extractDir)
|
|
||||||
|
|
||||||
// Download ZIP
|
|
||||||
fmt.Fprintf(gi.logWriter, " Downloading source (branch: %s)...\n", branch)
|
|
||||||
if err := DownloadFile(zipURL, zipPath); err != nil {
|
|
||||||
return fmt.Errorf("failed to download source from %s: %w", zipURL, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create extraction directory
|
|
||||||
if err := os.MkdirAll(extractDir, 0755); err != nil {
|
|
||||||
return fmt.Errorf("failed to create extraction directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract ZIP
|
|
||||||
fmt.Fprintf(gi.logWriter, " Extracting source...\n")
|
|
||||||
extractCmd := exec.Command("unzip", "-q", "-o", zipPath, "-d", extractDir)
|
|
||||||
if output, err := extractCmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("failed to extract source: %w\n%s", err, string(output))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GitHub extracts to network-{branch}/ directory
|
|
||||||
extractedDir := filepath.Join(extractDir, fmt.Sprintf("network-%s", branch))
|
|
||||||
|
|
||||||
// Verify extracted directory exists
|
|
||||||
if _, err := os.Stat(extractedDir); os.IsNotExist(err) {
|
|
||||||
// Try alternative naming (GitHub may sanitize branch names)
|
|
||||||
entries, _ := os.ReadDir(extractDir)
|
|
||||||
if len(entries) == 1 && entries[0].IsDir() {
|
|
||||||
extractedDir = filepath.Join(extractDir, entries[0].Name())
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("extracted directory not found at %s", extractedDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove existing source directory
|
|
||||||
os.RemoveAll(srcDir)
|
|
||||||
|
|
||||||
// Move extracted content to source directory
|
|
||||||
if err := os.Rename(extractedDir, srcDir); err != nil {
|
|
||||||
// Cross-filesystem fallback: copy instead of rename
|
|
||||||
fmt.Fprintf(gi.logWriter, " Moving source (cross-filesystem copy)...\n")
|
|
||||||
copyCmd := exec.Command("cp", "-r", extractedDir, srcDir)
|
|
||||||
if output, err := copyCmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("failed to move source: %w\n%s", err, string(output))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup temp files
|
|
||||||
os.RemoveAll(zipPath)
|
|
||||||
os.RemoveAll(extractDir)
|
|
||||||
|
|
||||||
// Fix ownership
|
|
||||||
if err := exec.Command("chown", "-R", "debros:debros", srcDir).Run(); err != nil {
|
|
||||||
fmt.Fprintf(gi.logWriter, " ⚠️ Warning: failed to chown source directory: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(gi.logWriter, " ✓ Source downloaded\n")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstallDeBrosBinaries downloads and builds DeBros binaries
|
|
||||||
func (gi *GatewayInstaller) InstallDeBrosBinaries(branch string, oramaHome string, skipRepoUpdate bool) error {
|
|
||||||
fmt.Fprintf(gi.logWriter, " Building DeBros binaries...\n")
|
fmt.Fprintf(gi.logWriter, " Building DeBros binaries...\n")
|
||||||
|
|
||||||
srcDir := filepath.Join(oramaHome, "src")
|
srcDir := filepath.Join(oramaHome, "src")
|
||||||
@ -124,24 +55,9 @@ func (gi *GatewayInstaller) InstallDeBrosBinaries(branch string, oramaHome strin
|
|||||||
return fmt.Errorf("failed to create bin directory %s: %w", binDir, err)
|
return fmt.Errorf("failed to create bin directory %s: %w", binDir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if source directory has content
|
// Verify source exists
|
||||||
hasSourceContent := false
|
if entries, err := os.ReadDir(srcDir); err != nil || len(entries) == 0 {
|
||||||
if entries, err := os.ReadDir(srcDir); err == nil && len(entries) > 0 {
|
return fmt.Errorf("source directory is empty at %s (upload source archive first)", srcDir)
|
||||||
hasSourceContent = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle repository update/download based on skipRepoUpdate flag
|
|
||||||
if skipRepoUpdate {
|
|
||||||
fmt.Fprintf(gi.logWriter, " Skipping source download (--no-pull flag)\n")
|
|
||||||
if !hasSourceContent {
|
|
||||||
return fmt.Errorf("cannot skip download: source directory is empty at %s (need to populate it first)", srcDir)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(gi.logWriter, " Using existing source at %s\n", srcDir)
|
|
||||||
} else {
|
|
||||||
// Download source as ZIP from GitHub (simpler than git, no shallow clone issues)
|
|
||||||
if err := gi.downloadSourceZIP(branch, srcDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build binaries
|
// Build binaries
|
||||||
|
|||||||
@ -52,9 +52,6 @@ type ProductionSetup struct {
|
|||||||
serviceGenerator *SystemdServiceGenerator
|
serviceGenerator *SystemdServiceGenerator
|
||||||
serviceController *SystemdController
|
serviceController *SystemdController
|
||||||
binaryInstaller *BinaryInstaller
|
binaryInstaller *BinaryInstaller
|
||||||
branch string
|
|
||||||
skipRepoUpdate bool
|
|
||||||
skipBuild bool // Skip all Go compilation (use pre-built binaries)
|
|
||||||
NodePeerID string // Captured during Phase3 for later display
|
NodePeerID string // Captured during Phase3 for later display
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,24 +83,16 @@ func SaveBranchPreference(oramaDir, branch string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewProductionSetup creates a new production setup orchestrator
|
// NewProductionSetup creates a new production setup orchestrator
|
||||||
func NewProductionSetup(oramaHome string, logWriter io.Writer, forceReconfigure bool, branch string, skipRepoUpdate bool, skipResourceChecks bool, skipBuild bool) *ProductionSetup {
|
func NewProductionSetup(oramaHome string, logWriter io.Writer, forceReconfigure bool, skipResourceChecks bool) *ProductionSetup {
|
||||||
oramaDir := filepath.Join(oramaHome, ".orama")
|
oramaDir := filepath.Join(oramaHome, ".orama")
|
||||||
arch, _ := (&ArchitectureDetector{}).Detect()
|
arch, _ := (&ArchitectureDetector{}).Detect()
|
||||||
|
|
||||||
// If branch is empty, try to read from stored preference, otherwise default to main
|
|
||||||
if branch == "" {
|
|
||||||
branch = ReadBranchPreference(oramaDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ProductionSetup{
|
return &ProductionSetup{
|
||||||
oramaHome: oramaHome,
|
oramaHome: oramaHome,
|
||||||
oramaDir: oramaDir,
|
oramaDir: oramaDir,
|
||||||
logWriter: logWriter,
|
logWriter: logWriter,
|
||||||
forceReconfigure: forceReconfigure,
|
forceReconfigure: forceReconfigure,
|
||||||
arch: arch,
|
arch: arch,
|
||||||
branch: branch,
|
|
||||||
skipRepoUpdate: skipRepoUpdate,
|
|
||||||
skipBuild: skipBuild,
|
|
||||||
skipResourceChecks: skipResourceChecks,
|
skipResourceChecks: skipResourceChecks,
|
||||||
privChecker: &PrivilegeChecker{},
|
privChecker: &PrivilegeChecker{},
|
||||||
osDetector: &OSDetector{},
|
osDetector: &OSDetector{},
|
||||||
@ -201,12 +190,12 @@ func (ps *ProductionSetup) Phase1CheckPrerequisites() error {
|
|||||||
ps.arch = arch
|
ps.arch = arch
|
||||||
ps.logf(" ✓ Detected architecture: %s", arch)
|
ps.logf(" ✓ Detected architecture: %s", arch)
|
||||||
|
|
||||||
// Check basic dependencies
|
// Check basic dependencies (auto-installs missing ones)
|
||||||
depChecker := NewDependencyChecker(ps.skipOptionalDeps)
|
depChecker := NewDependencyChecker(ps.skipOptionalDeps)
|
||||||
if missing, err := depChecker.CheckAll(); err != nil {
|
if missing, err := depChecker.CheckAll(); err != nil {
|
||||||
ps.logf(" ❌ Missing dependencies:")
|
ps.logf(" ❌ Failed to install dependencies:")
|
||||||
for _, dep := range missing {
|
for _, dep := range missing {
|
||||||
ps.logf(" - %s: %s", dep.Name, dep.InstallHint)
|
ps.logf(" - %s", dep.Name)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -307,86 +296,30 @@ func (ps *ProductionSetup) Phase2bInstallBinaries() error {
|
|||||||
ps.logf(" ⚠️ System dependencies warning: %v", err)
|
ps.logf(" ⚠️ System dependencies warning: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ps.skipBuild {
|
// Install Go toolchain (downloads from go.dev if needed)
|
||||||
// --pre-built mode: skip all Go compilation, verify binaries exist
|
if err := ps.binaryInstaller.InstallGo(); err != nil {
|
||||||
ps.logf(" ℹ️ --pre-built mode: skipping Go installation and all compilation")
|
return fmt.Errorf("failed to install Go: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Verify required DeBros binaries exist
|
if err := ps.binaryInstaller.InstallOlric(); err != nil {
|
||||||
binDir := filepath.Join(ps.oramaHome, "bin")
|
ps.logf(" ⚠️ Olric install warning: %v", err)
|
||||||
requiredBins := []string{"orama-node", "gateway", "orama", "identity"}
|
}
|
||||||
for _, bin := range requiredBins {
|
|
||||||
binPath := filepath.Join(binDir, bin)
|
// Install DeBros binaries (source must be at /home/debros/src via SCP)
|
||||||
if _, err := os.Stat(binPath); os.IsNotExist(err) {
|
if err := ps.binaryInstaller.InstallDeBrosBinaries(ps.oramaHome); err != nil {
|
||||||
return fmt.Errorf("--pre-built: required binary not found at %s (run 'make build-linux' locally and copy to VPS)", binPath)
|
return fmt.Errorf("failed to install DeBros binaries: %w", err)
|
||||||
}
|
}
|
||||||
ps.logf(" ✓ Found %s", binPath)
|
|
||||||
|
// Install CoreDNS only for nameserver nodes
|
||||||
|
if ps.isNameserver {
|
||||||
|
if err := ps.binaryInstaller.InstallCoreDNS(); err != nil {
|
||||||
|
ps.logf(" ⚠️ CoreDNS install warning: %v", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Grant CAP_NET_BIND_SERVICE to orama-node
|
// Install Caddy on ALL nodes (any node may host namespaces and need TLS)
|
||||||
nodeBinary := filepath.Join(binDir, "orama-node")
|
if err := ps.binaryInstaller.InstallCaddy(); err != nil {
|
||||||
if err := exec.Command("setcap", "cap_net_bind_service=+ep", nodeBinary).Run(); err != nil {
|
ps.logf(" ⚠️ Caddy install warning: %v", err)
|
||||||
ps.logf(" ⚠️ Warning: failed to setcap on orama-node: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify Olric
|
|
||||||
if _, err := exec.LookPath("olric-server"); err != nil {
|
|
||||||
// Check if it's in the bin dir
|
|
||||||
olricPath := filepath.Join(binDir, "olric-server")
|
|
||||||
if _, err := os.Stat(olricPath); os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("--pre-built: olric-server not found in PATH or %s", binDir)
|
|
||||||
}
|
|
||||||
// Copy to /usr/local/bin
|
|
||||||
if data, err := os.ReadFile(olricPath); err == nil {
|
|
||||||
os.WriteFile("/usr/local/bin/olric-server", data, 0755)
|
|
||||||
}
|
|
||||||
ps.logf(" ✓ Found %s", olricPath)
|
|
||||||
} else {
|
|
||||||
ps.logf(" ✓ olric-server already in PATH")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify CoreDNS and Caddy if nameserver
|
|
||||||
if ps.isNameserver {
|
|
||||||
if _, err := os.Stat("/usr/local/bin/coredns"); os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("--pre-built: coredns not found at /usr/local/bin/coredns")
|
|
||||||
}
|
|
||||||
ps.logf(" ✓ Found /usr/local/bin/coredns")
|
|
||||||
|
|
||||||
if _, err := os.Stat("/usr/bin/caddy"); os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("--pre-built: caddy not found at /usr/bin/caddy")
|
|
||||||
}
|
|
||||||
ps.logf(" ✓ Found /usr/bin/caddy")
|
|
||||||
|
|
||||||
// Grant CAP_NET_BIND_SERVICE to caddy
|
|
||||||
if err := exec.Command("setcap", "cap_net_bind_service=+ep", "/usr/bin/caddy").Run(); err != nil {
|
|
||||||
ps.logf(" ⚠️ Warning: failed to setcap on caddy: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Normal mode: install Go and build everything
|
|
||||||
if err := ps.binaryInstaller.InstallGo(); err != nil {
|
|
||||||
return fmt.Errorf("failed to install Go: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ps.binaryInstaller.InstallOlric(); err != nil {
|
|
||||||
ps.logf(" ⚠️ Olric install warning: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install DeBros binaries (must be done before CoreDNS since we need the RQLite plugin source)
|
|
||||||
if err := ps.binaryInstaller.InstallDeBrosBinaries(ps.branch, ps.oramaHome, ps.skipRepoUpdate); err != nil {
|
|
||||||
return fmt.Errorf("failed to install DeBros binaries: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install CoreDNS only for nameserver nodes
|
|
||||||
if ps.isNameserver {
|
|
||||||
if err := ps.binaryInstaller.InstallCoreDNS(); err != nil {
|
|
||||||
ps.logf(" ⚠️ CoreDNS install warning: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install Caddy on ALL nodes (any node may host namespaces and need TLS)
|
|
||||||
if err := ps.binaryInstaller.InstallCaddy(); err != nil {
|
|
||||||
ps.logf(" ⚠️ Caddy install warning: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are pre-built binary downloads (not Go compilation), always run them
|
// These are pre-built binary downloads (not Go compilation), always run them
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user