This commit is contained in:
2026-02-15 13:13:11 +01:00
parent 8b592db3dd
commit 35c9060451
2 changed files with 59 additions and 7 deletions

View File

@@ -103,6 +103,34 @@ func main() {
os.Exit(1) os.Exit(1)
} }
case "mount":
// Mount a restored dataset to access files
if len(os.Args) < 3 {
fmt.Println("Usage: zfs-restore mount <dataset> [mountpoint]")
fmt.Println("\nExamples:")
fmt.Println(" zfs-restore mount tank/restored /mnt/recover")
fmt.Println(" zfs-restore mount tank/restored # interactive")
os.Exit(1)
}
dataset := os.Args[2]
mountpoint := ""
if len(os.Args) > 3 {
mountpoint = os.Args[3]
} else {
fmt.Printf("Mountpoint [/mnt/recover]: ")
fmt.Scanln(&mountpoint)
if mountpoint == "" {
mountpoint = "/mnt/recover"
}
}
if err := client.MountDataset(dataset, mountpoint); err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
case "help", "-h", "--help": case "help", "-h", "--help":
printUsage() printUsage()
@@ -119,11 +147,13 @@ func printUsage() {
fmt.Println("\nCommands:") fmt.Println("\nCommands:")
fmt.Println(" list - List available snapshots") fmt.Println(" list - List available snapshots")
fmt.Println(" restore <#|latest> <dataset> [--force] - Restore snapshot to ZFS") fmt.Println(" restore <#|latest> <dataset> [--force] - Restore snapshot to ZFS")
fmt.Println(" mount <dataset> [mountpoint] - Mount dataset to recover files")
fmt.Println(" help - Show this help message") fmt.Println(" help - Show this help message")
fmt.Println("\nQuick Examples:") fmt.Println("\nQuick Examples:")
fmt.Println(" zfs-restore list - See available backups") fmt.Println(" zfs-restore list - See available backups")
fmt.Println(" zfs-restore restore latest tank/data - Restore most recent backup") fmt.Println(" zfs-restore restore latest tank/data - Restore most recent backup")
fmt.Println(" zfs-restore restore 1 tank/restored - Restore snapshot #1") fmt.Println(" zfs-restore restore 1 tank/restored - Restore snapshot #1")
fmt.Println(" zfs-restore mount tank/restored /mnt - Mount to recover files")
fmt.Println("\nEnvironment Variables (can be set in .env file):") fmt.Println("\nEnvironment Variables (can be set in .env file):")
fmt.Println(" CLIENT_ID - Client identifier (default: client1)") fmt.Println(" CLIENT_ID - Client identifier (default: client1)")
fmt.Println(" API_KEY - API key for authentication (default: secret123)") fmt.Println(" API_KEY - API key for authentication (default: secret123)")

View File

@@ -148,6 +148,17 @@ func (c *Client) RestoreSnapshot(snapshot *SnapshotMetadata, targetDataset strin
} }
} }
// If force is used, destroy the dataset first (including all snapshots)
if force {
if _, err := zfs.GetDataset(targetDataset); err == nil {
fmt.Printf("→ Destroying existing dataset %s (including all snapshots)...\n", targetDataset)
cmd := exec.Command("zfs", "destroy", "-r", targetDataset)
if err := cmd.Run(); err != nil {
fmt.Printf(" Warning: could not destroy dataset: %v\n", err)
}
}
}
// Request download from server // Request download from server
downloadURL := fmt.Sprintf("%s/download?client_id=%s&api_key=%s&snapshot_id=%s", downloadURL := fmt.Sprintf("%s/download?client_id=%s&api_key=%s&snapshot_id=%s",
c.ServerURL, c.ClientID, c.APIKey, snapshot.SnapshotID) c.ServerURL, c.ClientID, c.APIKey, snapshot.SnapshotID)
@@ -242,15 +253,22 @@ func (c *Client) RestoreToFile(snapshot *SnapshotMetadata, outputFile string) er
return nil return nil
} }
// MountSnapshot mounts a restored dataset to a specified mountpoint. // MountDataset mounts a restored dataset to a specified mountpoint for file recovery.
// This allows browsing the restored files. func (c *Client) MountDataset(dataset, mountpoint string) error {
func (c *Client) MountSnapshot(dataset, mountpoint string) error { fmt.Printf("\n=== Mounting Dataset ===\n")
fmt.Printf("Dataset: %s\n", dataset)
fmt.Printf("Mountpoint: %s\n\n", mountpoint)
ds, err := zfs.GetDataset(dataset) ds, err := zfs.GetDataset(dataset)
if err != nil { if err != nil {
return fmt.Errorf("dataset not found: %v", err) return fmt.Errorf("dataset not found: %v", err)
} }
// Create mountpoint if it doesn't exist // Check current mountpoint
currentMP, _ := ds.GetProperty("mountpoint")
fmt.Printf("Current mountpoint: %s\n", currentMP)
// Create mountpoint directory if it doesn't exist
if err := os.MkdirAll(mountpoint, 0755); err != nil { if err := os.MkdirAll(mountpoint, 0755); err != nil {
return fmt.Errorf("failed to create mountpoint: %v", err) return fmt.Errorf("failed to create mountpoint: %v", err)
} }
@@ -260,13 +278,17 @@ func (c *Client) MountSnapshot(dataset, mountpoint string) error {
return fmt.Errorf("failed to set mountpoint: %v", err) return fmt.Errorf("failed to set mountpoint: %v", err)
} }
// Mount the dataset // Mount the dataset if not already mounted
cmd := exec.Command("zfs", "mount", dataset) cmd := exec.Command("zfs", "mount", dataset)
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to mount: %v", err) // Might already be mounted, that's OK
fmt.Printf(" (dataset may already be mounted)\n")
} }
fmt.Printf("✓ Mounted %s at %s\n", dataset, mountpoint) fmt.Printf("\n✓ Mounted successfully!\n")
fmt.Printf(" Access files at: %s\n", mountpoint)
fmt.Printf(" When done, run: umount %s\n", mountpoint)
return nil return nil
} }