Initial commit: Disaster recovery CLI tool
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>
This commit is contained in:
63
internal/restore/wireguard.go
Normal file
63
internal/restore/wireguard.go
Normal file
@@ -0,0 +1,63 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user