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

View File

@@ -148,6 +148,26 @@ func (c *Client) RestoreSnapshot(snapshot *SnapshotMetadata, targetDataset strin
}
}
// If force is used, we need to handle carefully to avoid data loss
// First, let's try to download - only destroy if download succeeds
var originalExists bool
if force {
if _, err := zfs.GetDataset(targetDataset); err == nil {
originalExists = true
fmt.Printf("→ Target dataset exists, will overwrite\n")
} else {
originalExists = false
fmt.Printf("→ Target dataset does not exist, will create new\n")
}
} else {
// Check if target dataset exists
if !force {
if _, err := zfs.GetDataset(targetDataset); err == nil {
return fmt.Errorf("target dataset %s already exists. Use --force to overwrite", targetDataset)
}
}
}
// Request download from server
downloadURL := fmt.Sprintf("%s/download?client_id=%s&api_key=%s&snapshot_id=%s",
c.ServerURL, c.ClientID, c.APIKey, snapshot.SnapshotID)
@@ -165,6 +185,18 @@ func (c *Client) RestoreSnapshot(snapshot *SnapshotMetadata, targetDataset strin
return fmt.Errorf("download failed: %s", body)
}
// Download succeeded - now safe to destroy if needed
if force && originalExists {
fmt.Printf("→ Destroying existing dataset %s...\n", targetDataset)
cmd := exec.Command("zfs", "destroy", "-r", targetDataset)
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf(" Destroy output: %s\n", string(output))
return fmt.Errorf("failed to destroy existing dataset: %v", err)
}
fmt.Printf(" Destroyed successfully\n")
}
// Create decompression reader if needed
var reader io.Reader = resp.Body
if snapshot.Compressed {
@@ -194,6 +226,13 @@ func (c *Client) RestoreSnapshot(snapshot *SnapshotMetadata, targetDataset strin
fmt.Printf("\n✓ Snapshot restored successfully!\n")
fmt.Printf(" Dataset: %s\n", targetDataset)
// Verify the dataset exists after restore
if _, err := zfs.GetDataset(targetDataset); err == nil {
fmt.Printf(" Verified: dataset exists\n")
} else {
fmt.Printf(" Warning: could not verify dataset exists: %v\n", err)
}
return nil
}
@@ -242,15 +281,22 @@ func (c *Client) RestoreToFile(snapshot *SnapshotMetadata, outputFile string) er
return nil
}
// MountSnapshot mounts a restored dataset to a specified mountpoint.
// This allows browsing the restored files.
func (c *Client) MountSnapshot(dataset, mountpoint string) error {
// MountDataset mounts a restored dataset to a specified mountpoint for file recovery.
func (c *Client) MountDataset(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)
if err != nil {
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 {
return fmt.Errorf("failed to create mountpoint: %v", err)
}
@@ -260,13 +306,17 @@ func (c *Client) MountSnapshot(dataset, mountpoint string) error {
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)
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
}