feat(sandbox): add --anyone-client flag to rollout

- propagate `--anyone-client` to `orama node upgrade` on all nodes
- prioritize explicit `--anyone-client` over prefs/auto-detect in production
- ensure mutual exclusivity between relay/client modes in prefs
This commit is contained in:
anonpenguin23 2026-03-09 10:59:15 +02:00
parent 78d876e71b
commit 733b059681
3 changed files with 44 additions and 14 deletions

View File

@ -76,7 +76,10 @@ var rolloutCmd = &cobra.Command{
Short: "Build + push + rolling upgrade to sandbox cluster",
RunE: func(cmd *cobra.Command, args []string) error {
name, _ := cmd.Flags().GetString("name")
return sandbox.Rollout(name)
anyoneClient, _ := cmd.Flags().GetBool("anyone-client")
return sandbox.Rollout(name, sandbox.RolloutFlags{
AnyoneClient: anyoneClient,
})
},
}
@ -121,6 +124,7 @@ func init() {
// rollout flags
rolloutCmd.Flags().String("name", "", "Sandbox name (uses active if not specified)")
rolloutCmd.Flags().Bool("anyone-client", false, "Enable Anyone client (SOCKS5 proxy) on all nodes")
// ssh flags
sshCmd.Flags().String("name", "", "Sandbox name (uses active if not specified)")

View File

@ -41,7 +41,8 @@ func NewOrchestrator(flags *Flags) *Orchestrator {
setup := production.NewProductionSetup(oramaHome, os.Stdout, flags.Force, flags.SkipChecks)
setup.SetNameserver(isNameserver)
// Configure Anyone mode (flag > saved preference > auto-detect)
// Configure Anyone mode (explicit flags > saved preferences > auto-detect)
// Explicit flags always win — they represent the user's current intent.
if flags.AnyoneRelay {
setup.SetAnyoneRelayConfig(&production.AnyoneRelayConfig{
Enabled: true,
@ -55,6 +56,9 @@ func NewOrchestrator(flags *Flags) *Orchestrator {
BandwidthPct: flags.AnyoneBandwidth,
AccountingMax: flags.AnyoneAccounting,
})
} else if flags.AnyoneClient {
// Explicit --anyone-client flag overrides saved relay prefs and auto-detect.
setup.SetAnyoneClient(true)
} else if prefs.AnyoneRelay {
// Restore relay config from saved preferences (for firewall rules)
orPort := prefs.AnyoneORPort
@ -65,6 +69,8 @@ func NewOrchestrator(flags *Flags) *Orchestrator {
Enabled: true,
ORPort: orPort,
})
} else if prefs.AnyoneClient {
setup.SetAnyoneClient(true)
} else if detectAnyoneRelay(oramaDir) {
// Auto-detect: relay is installed but preferences weren't saved.
// This happens when upgrading from older versions that didn't persist
@ -79,8 +85,6 @@ func NewOrchestrator(flags *Flags) *Orchestrator {
prefs.AnyoneORPort = orPort
_ = production.SavePreferences(oramaDir, prefs)
fmt.Printf(" Auto-detected Anyone relay (ORPort: %d), saved to preferences\n", orPort)
} else if flags.AnyoneClient || prefs.AnyoneClient {
setup.SetAnyoneClient(true)
}
return &Orchestrator{
@ -207,15 +211,15 @@ func (o *Orchestrator) handleBranchPreferences() error {
fmt.Printf(" Nameserver mode: enabled (CoreDNS + Caddy)\n")
}
// If anyone-client was explicitly provided, update it
// Anyone client and relay are mutually exclusive — setting one clears the other.
if o.flags.AnyoneClient {
prefs.AnyoneClient = true
prefs.AnyoneRelay = false
prefs.AnyoneORPort = 0
prefsChanged = true
}
// If anyone-relay was explicitly provided, update it
if o.flags.AnyoneRelay {
} else if o.flags.AnyoneRelay {
prefs.AnyoneRelay = true
prefs.AnyoneClient = false
prefs.AnyoneORPort = o.flags.AnyoneORPort
if prefs.AnyoneORPort == 0 {
prefs.AnyoneORPort = 9001

View File

@ -4,14 +4,20 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/DeBrosOfficial/network/pkg/cli/remotessh"
"github.com/DeBrosOfficial/network/pkg/inspector"
)
// RolloutFlags holds optional flags passed through to `orama node upgrade`.
type RolloutFlags struct {
AnyoneClient bool
}
// Rollout builds, pushes, and performs a rolling upgrade on a sandbox cluster.
func Rollout(name string) error {
func Rollout(name string, flags RolloutFlags) error {
cfg, err := LoadConfig()
if err != nil {
return err
@ -34,6 +40,9 @@ func Rollout(name string) error {
info, _ := os.Stat(archivePath)
fmt.Printf("Archive: %s (%s)\n\n", filepath.Base(archivePath), formatBytes(info.Size()))
// Build extra flags string for upgrade command
extraFlags := flags.upgradeFlags()
// Step 2: Push archive to all nodes (upload to first, fan out server-to-server)
fmt.Println("Pushing archive to all nodes...")
if err := fanoutArchive(state.Servers, sshKeyPath, archivePath); err != nil {
@ -54,7 +63,7 @@ func Rollout(name string) error {
if i == leaderIdx {
continue // skip leader, do it last
}
if err := upgradeNode(srv, sshKeyPath, i+1, len(state.Servers)); err != nil {
if err := upgradeNode(srv, sshKeyPath, i+1, len(state.Servers), extraFlags); err != nil {
return err
}
// Wait between nodes
@ -67,7 +76,7 @@ func Rollout(name string) error {
// Upgrade leader last
if leaderIdx >= 0 {
srv := state.Servers[leaderIdx]
if err := upgradeNode(srv, sshKeyPath, len(state.Servers), len(state.Servers)); err != nil {
if err := upgradeNode(srv, sshKeyPath, len(state.Servers), len(state.Servers), extraFlags); err != nil {
return err
}
}
@ -76,6 +85,15 @@ func Rollout(name string) error {
return nil
}
// upgradeFlags builds the extra CLI flags string for `orama node upgrade`.
func (f RolloutFlags) upgradeFlags() string {
var parts []string
if f.AnyoneClient {
parts = append(parts, "--anyone-client")
}
return strings.Join(parts, " ")
}
// findLeaderIndex returns the index of the RQLite leader node, or -1 if unknown.
func findLeaderIndex(state *SandboxState, sshKeyPath string) int {
for i, srv := range state.Servers {
@ -92,7 +110,7 @@ func findLeaderIndex(state *SandboxState, sshKeyPath string) int {
// It pre-replaces the orama CLI binary before running the upgrade command
// to avoid ETXTBSY ("text file busy") errors when the old binary doesn't
// have the os.Remove fix in copyBinary().
func upgradeNode(srv ServerState, sshKeyPath string, current, total int) error {
func upgradeNode(srv ServerState, sshKeyPath string, current, total int, extraFlags string) error {
node := inspector.Node{User: "root", Host: srv.IP, SSHKey: sshKeyPath}
fmt.Printf(" [%d/%d] Upgrading %s (%s)...\n", current, total, srv.Name, srv.IP)
@ -105,7 +123,11 @@ func upgradeNode(srv ServerState, sshKeyPath string, current, total int) error {
return fmt.Errorf("pre-replace orama binary on %s: %w", srv.Name, err)
}
if err := remotessh.RunSSHStreaming(node, "orama node upgrade --restart", remotessh.WithNoHostKeyCheck()); err != nil {
upgradeCmd := "orama node upgrade --restart"
if extraFlags != "" {
upgradeCmd += " " + extraFlags
}
if err := remotessh.RunSSHStreaming(node, upgradeCmd, remotessh.WithNoHostKeyCheck()); err != nil {
return fmt.Errorf("upgrade %s: %w", srv.Name, err)
}