A Go-based CLI tool for recovering servers from backups to new cloud VMs. Features: - Multi-cloud support: Exoscale, Cloudscale, Hetzner Cloud - Backup sources: Local filesystem, Hetzner Storage Box - 6-stage restore pipeline with /etc whitelist protection - DNS migration with safety checks and auto-rollback - Dry-run by default, requires --yes to execute - Cloud-init for SSH key injection Packages: - cmd/recover-server: CLI commands (recover, migrate-dns, list, cleanup) - internal/providers: Cloud provider implementations - internal/backup: Backup source implementations - internal/restore: 6-stage restore pipeline - internal/dns: Exoscale DNS management - internal/ui: Prompts, progress, dry-run display - internal/config: Environment and host configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
package restore
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// runServices starts restored services
|
|
func (p *Pipeline) runServices(ctx context.Context) error {
|
|
// Start WireGuard interfaces
|
|
if err := p.startWireGuard(ctx); err != nil {
|
|
// WireGuard is optional, log but don't fail
|
|
if p.Verbose {
|
|
fmt.Printf(" WireGuard: %v\n", err)
|
|
}
|
|
}
|
|
|
|
// Start Docker
|
|
if err := p.startDocker(ctx); err != nil {
|
|
return fmt.Errorf("failed to start Docker: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// startWireGuard enables and starts WireGuard interfaces
|
|
func (p *Pipeline) startWireGuard(ctx context.Context) error {
|
|
// Check if WireGuard configs exist
|
|
checkCmd := "ls /etc/wireguard/*.conf 2>/dev/null | head -5"
|
|
output, err := p.remoteCmdOutput(ctx, checkCmd)
|
|
if err != nil || strings.TrimSpace(output) == "" {
|
|
return fmt.Errorf("no WireGuard configs found")
|
|
}
|
|
|
|
// Get interface names
|
|
configs := strings.Split(strings.TrimSpace(output), "\n")
|
|
for _, conf := range configs {
|
|
if conf == "" {
|
|
continue
|
|
}
|
|
|
|
// Extract interface name from path (e.g., /etc/wireguard/wg0.conf -> wg0)
|
|
parts := strings.Split(conf, "/")
|
|
filename := parts[len(parts)-1]
|
|
iface := strings.TrimSuffix(filename, ".conf")
|
|
|
|
if p.Verbose {
|
|
fmt.Printf(" Starting WireGuard interface: %s\n", iface)
|
|
}
|
|
|
|
// Enable and start
|
|
enableCmd := fmt.Sprintf("systemctl enable wg-quick@%s", iface)
|
|
startCmd := fmt.Sprintf("systemctl start wg-quick@%s", iface)
|
|
|
|
p.remoteCmd(ctx, enableCmd)
|
|
if err := p.remoteCmd(ctx, startCmd); err != nil {
|
|
return fmt.Errorf("failed to start %s: %w", iface, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|