anonpenguin23 c6998b6ac2 Remove legacy deployment and upgrade scripts
- Deleted redeploy.sh, which handled redeployment to nodes in devnet/testnet environments.
- Removed upgrade-nodes.sh, responsible for rolling upgrades of nodes.
- Eliminated upload-source-fanout.sh, which uploaded source archives to nodes in parallel.
- Removed upload-source.sh, used for uploading and extracting source archives to VPS nodes.
2026-02-24 14:24:25 +02:00

233 lines
7.6 KiB
Go

package production
import (
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
)
// PreBuiltManifest describes the contents of a pre-built binary archive.
type PreBuiltManifest struct {
Version string `json:"version"`
Commit string `json:"commit"`
Date string `json:"date"`
Arch string `json:"arch"`
Checksums map[string]string `json:"checksums"` // filename -> sha256
}
// HasPreBuiltArchive checks if a pre-built binary archive has been extracted
// at /opt/orama/ by looking for the manifest.json file.
func HasPreBuiltArchive() bool {
_, err := os.Stat(OramaManifest)
return err == nil
}
// LoadPreBuiltManifest loads and parses the pre-built manifest.
func LoadPreBuiltManifest() (*PreBuiltManifest, error) {
data, err := os.ReadFile(OramaManifest)
if err != nil {
return nil, fmt.Errorf("failed to read manifest: %w", err)
}
var manifest PreBuiltManifest
if err := json.Unmarshal(data, &manifest); err != nil {
return nil, fmt.Errorf("failed to parse manifest: %w", err)
}
return &manifest, nil
}
// installFromPreBuilt installs all binaries from a pre-built archive.
// The archive must already be extracted at /opt/orama/ with:
// - /opt/orama/bin/ — all pre-compiled binaries
// - /opt/orama/systemd/ — namespace service templates
// - /opt/orama/packages/ — optional .deb packages
// - /opt/orama/manifest.json — archive metadata
func (ps *ProductionSetup) installFromPreBuilt(manifest *PreBuiltManifest) error {
ps.logf(" Using pre-built binary archive v%s (%s) linux/%s", manifest.Version, manifest.Commit, manifest.Arch)
// Install minimal system dependencies (no build tools needed)
if err := ps.installMinimalSystemDeps(); err != nil {
ps.logf(" ⚠️ System dependencies warning: %v", err)
}
// Copy binaries to runtime locations
if err := ps.deployPreBuiltBinaries(manifest); err != nil {
return fmt.Errorf("failed to deploy pre-built binaries: %w", err)
}
// Set capabilities on binaries that need to bind privileged ports
if err := ps.setCapabilities(); err != nil {
return fmt.Errorf("failed to set capabilities: %w", err)
}
// Disable systemd-resolved stub listener for nameserver nodes
// (needed even in pre-built mode so CoreDNS can bind port 53)
if ps.isNameserver {
if err := ps.disableResolvedStub(); err != nil {
ps.logf(" ⚠️ Failed to disable systemd-resolved stub: %v", err)
}
}
// Install Anyone relay from .deb package if available
if ps.IsAnyoneRelay() || ps.IsAnyoneClient() {
if err := ps.installAnyonFromPreBuilt(); err != nil {
ps.logf(" ⚠️ Anyone install warning: %v", err)
}
}
ps.logf(" ✓ All pre-built binaries installed")
return nil
}
// installMinimalSystemDeps installs only runtime dependencies (no build tools).
func (ps *ProductionSetup) installMinimalSystemDeps() error {
ps.logf(" Installing minimal system dependencies...")
cmd := exec.Command("apt-get", "update")
if err := cmd.Run(); err != nil {
ps.logf(" Warning: apt update failed")
}
// Only install runtime deps — no build-essential, make, nodejs, npm needed
cmd = exec.Command("apt-get", "install", "-y", "curl", "wget", "unzip")
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to install minimal dependencies: %w", err)
}
ps.logf(" ✓ Minimal system dependencies installed (no build tools needed)")
return nil
}
// deployPreBuiltBinaries copies pre-built binaries to their runtime locations.
func (ps *ProductionSetup) deployPreBuiltBinaries(manifest *PreBuiltManifest) error {
ps.logf(" Deploying pre-built binaries...")
// Binary → destination mapping
// Most go to /usr/local/bin/, caddy goes to /usr/bin/
type binaryDest struct {
name string
dest string
}
binaries := []binaryDest{
{name: "orama", dest: "/usr/local/bin/orama"},
{name: "orama-node", dest: "/usr/local/bin/orama-node"},
{name: "gateway", dest: "/usr/local/bin/gateway"},
{name: "identity", dest: "/usr/local/bin/identity"},
{name: "sfu", dest: "/usr/local/bin/sfu"},
{name: "turn", dest: "/usr/local/bin/turn"},
{name: "olric-server", dest: "/usr/local/bin/olric-server"},
{name: "ipfs", dest: "/usr/local/bin/ipfs"},
{name: "ipfs-cluster-service", dest: "/usr/local/bin/ipfs-cluster-service"},
{name: "rqlited", dest: "/usr/local/bin/rqlited"},
{name: "coredns", dest: "/usr/local/bin/coredns"},
{name: "caddy", dest: "/usr/bin/caddy"},
}
for _, bin := range binaries {
srcPath := filepath.Join(OramaArchiveBin, bin.name)
// Skip optional binaries (e.g., coredns on non-nameserver nodes)
if _, ok := manifest.Checksums[bin.name]; !ok {
continue
}
if _, err := os.Stat(srcPath); os.IsNotExist(err) {
ps.logf(" ⚠️ Binary %s not found in archive, skipping", bin.name)
continue
}
if err := copyBinary(srcPath, bin.dest); err != nil {
return fmt.Errorf("failed to copy %s: %w", bin.name, err)
}
ps.logf(" ✓ %s → %s", bin.name, bin.dest)
}
return nil
}
// setCapabilities sets cap_net_bind_service on binaries that need to bind privileged ports.
// Both the /opt/orama/bin/ originals (used by systemd) and /usr/local/bin/ copies need caps.
func (ps *ProductionSetup) setCapabilities() error {
caps := []string{
filepath.Join(OramaArchiveBin, "orama-node"), // systemd uses this path
"/usr/local/bin/orama-node", // PATH copy
"/usr/bin/caddy", // caddy's standard location
}
for _, binary := range caps {
if _, err := os.Stat(binary); os.IsNotExist(err) {
continue
}
cmd := exec.Command("setcap", "cap_net_bind_service=+ep", binary)
if err := cmd.Run(); err != nil {
return fmt.Errorf("setcap failed on %s: %w (node won't be able to bind port 443)", binary, err)
}
ps.logf(" ✓ setcap on %s", binary)
}
return nil
}
// disableResolvedStub disables systemd-resolved's stub listener so CoreDNS can bind port 53.
func (ps *ProductionSetup) disableResolvedStub() error {
// Delegate to the coredns installer's method
return ps.binaryInstaller.coredns.DisableResolvedStubListener()
}
// installAnyonFromPreBuilt installs the Anyone relay .deb from the packages dir,
// falling back to apt install if the .deb is not bundled.
func (ps *ProductionSetup) installAnyonFromPreBuilt() error {
debPath := filepath.Join(OramaPackagesDir, "anon.deb")
if _, err := os.Stat(debPath); err == nil {
ps.logf(" Installing Anyone from bundled .deb...")
cmd := exec.Command("dpkg", "-i", debPath)
if err := cmd.Run(); err != nil {
ps.logf(" ⚠️ dpkg -i failed, falling back to apt...")
cmd = exec.Command("apt-get", "install", "-y", "anon")
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to install anon: %w", err)
}
}
ps.logf(" ✓ Anyone installed from .deb")
return nil
}
// No .deb bundled — fall back to apt (the existing path in source mode)
ps.logf(" Installing Anyone via apt (not bundled in archive)...")
cmd := exec.Command("apt-get", "install", "-y", "anon")
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to install anon via apt: %w", err)
}
ps.logf(" ✓ Anyone installed via apt")
return nil
}
// copyBinary copies a file from src to dest, preserving executable permissions.
func copyBinary(src, dest string) error {
// Ensure parent directory exists
if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
return err
}
srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()
destFile, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
if err != nil {
return err
}
defer destFile.Close()
if _, err := io.Copy(destFile, srcFile); err != nil {
return err
}
return nil
}