// Command zfs-client is the CLI tool for creating and uploading ZFS snapshots. // It provides commands for backup, status checking, snapshot rotation, and incremental backups. package main import ( "fmt" "os" "git.ma-al.com/goc_marek/zfs/internal/client" ) func main() { if len(os.Args) < 2 { printUsage() os.Exit(1) } // Load configuration from environment and .env file config := client.LoadConfig() c := client.New(config) command := os.Args[1] switch command { case "backup": // Default: create manual backup (full or incremental) fmt.Println("=== Creating and sending backup ===\n") snapshot, err := c.CreateSnapshot() if err != nil { fmt.Printf("Error creating snapshot: %v\n", err) os.Exit(1) } if err := c.SendSnapshot(snapshot); err != nil { fmt.Printf("Error sending snapshot: %v\n", err) os.Exit(1) } fmt.Println("\n✓ Backup completed successfully!") case "backup-full": // Force full backup (no incremental) fmt.Println("=== Creating full backup ===\n") snapshot, err := c.CreateSnapshot() if err != nil { fmt.Printf("Error creating snapshot: %v\n", err) os.Exit(1) } if err := c.SendIncremental(snapshot, ""); err != nil { fmt.Printf("Error sending snapshot: %v\n", err) os.Exit(1) } // Create bookmark for future incremental backups if err := c.CreateBookmark(snapshot); err != nil { fmt.Printf("Warning: failed to create bookmark: %v\n", err) } fmt.Println("\n✓ Full backup completed successfully!") case "backup-incremental": // Incremental backup from last bookmark fmt.Println("=== Creating incremental backup ===\n") // Check for existing bookmark lastBookmark, err := c.GetLastBookmark() if err != nil { fmt.Printf("Error checking bookmarks: %v\n", err) os.Exit(1) } if lastBookmark == "" { fmt.Println("No existing bookmark found. Use 'backup-full' for initial backup.") os.Exit(1) } snapshot, err := c.CreateSnapshot() if err != nil { fmt.Printf("Error creating snapshot: %v\n", err) os.Exit(1) } if err := c.SendIncremental(snapshot, lastBookmark); err != nil { fmt.Printf("Error sending incremental snapshot: %v\n", err) os.Exit(1) } // Create bookmark for future incremental backups if err := c.CreateBookmark(snapshot); err != nil { fmt.Printf("Warning: failed to create bookmark: %v\n", err) } fmt.Println("\n✓ Incremental backup completed successfully!") case "snapshot": // Create typed snapshots (hourly, daily, weekly, monthly) if len(os.Args) < 3 { fmt.Println("Usage: zfs-client snapshot ") os.Exit(1) } snapType := client.SnapshotType(os.Args[2]) switch snapType { case client.SnapshotHourly, client.SnapshotDaily, client.SnapshotWeekly, client.SnapshotMonthly: // Valid type default: fmt.Printf("Invalid snapshot type: %s\n", snapType) fmt.Println("Valid types: hourly, daily, weekly, monthly") os.Exit(1) } fmt.Printf("=== Creating %s snapshot ===\n\n", snapType) snapshot, err := c.CreateSnapshotWithType(snapType) if err != nil { fmt.Printf("Error creating snapshot: %v\n", err) os.Exit(1) } // Check for existing bookmark for incremental lastBookmark, _ := c.GetLastBookmark() if err := c.SendIncremental(snapshot, lastBookmark); err != nil { fmt.Printf("Error sending snapshot: %v\n", err) os.Exit(1) } // Create bookmark if err := c.CreateBookmark(snapshot); err != nil { fmt.Printf("Warning: failed to create bookmark: %v\n", err) } // Rotate local snapshots using server policy if available policy, err := getRotationPolicy(c) if err != nil { fmt.Printf("Warning: failed to get rotation policy: %v\n", err) policy = client.DefaultPolicy() } if err := c.RotateLocalSnapshots(policy); err != nil { fmt.Printf("Warning: failed to rotate snapshots: %v\n", err) } fmt.Printf("\n✓ %s snapshot completed successfully!\n", snapType) case "rotate": // Rotate local snapshots using server policy if available fmt.Println("=== Rotating local snapshots ===\n") policy, err := getRotationPolicy(c) if err != nil { fmt.Printf("Warning: failed to get rotation policy: %v\n", err) policy = client.DefaultPolicy() } if err := c.RotateLocalSnapshots(policy); err != nil { fmt.Printf("Error rotating snapshots: %v\n", err) os.Exit(1) } fmt.Println("\n✓ Rotation completed!") case "rotate-remote": // Request server to rotate remote snapshots if err := c.RequestRotation(); err != nil { fmt.Printf("Error requesting rotation: %v\n", err) os.Exit(1) } case "status": if err := c.GetStatus(); err != nil { fmt.Printf("Error getting status: %v\n", err) os.Exit(1) } case "bookmarks": // List bookmarks fmt.Println("=== ZFS Bookmarks ===\n") bookmark, err := c.GetLastBookmark() if err != nil { fmt.Printf("Error: %v\n", err) os.Exit(1) } if bookmark == "" { fmt.Println("No bookmarks found") } else { fmt.Printf("Last bookmark: %s\n", bookmark) } case "help", "-h", "--help": printUsage() default: fmt.Printf("Unknown command: %s\n", command) printUsage() os.Exit(1) } } // getRotationPolicy fetches the rotation policy from the server. // If the server has a policy configured, it must be used. // Otherwise, the default policy is returned. func getRotationPolicy(c *client.Client) (*client.SnapshotPolicy, error) { serverPolicy, err := c.GetRotationPolicy() if err != nil { return nil, err } if serverPolicy.ServerManaged && serverPolicy.RotationPolicy != nil { fmt.Println(" Using server-managed rotation policy") return serverPolicy.RotationPolicy, nil } // No server policy, use default fmt.Println(" Using default rotation policy") return client.DefaultPolicy(), nil } func printUsage() { fmt.Println("ZFS Snapshot Backup Client") fmt.Println("\nUsage: zfs-client [command]") fmt.Println("\nCommands:") fmt.Println(" backup - Create snapshot and send (auto incremental if bookmark exists)") fmt.Println(" backup-full - Create full backup (no incremental)") fmt.Println(" backup-incremental - Create incremental backup from last bookmark") fmt.Println(" snapshot - Create typed snapshot (hourly|daily|weekly|monthly)") fmt.Println(" rotate - Rotate local snapshots based on retention policy") fmt.Println(" rotate-remote - Request server to rotate old remote snapshots") fmt.Println(" status - Check server status and quota") fmt.Println(" bookmarks - List ZFS bookmarks") fmt.Println(" help - Show this help message") fmt.Println("\nSnapshot Retention Policy (default):") fmt.Println(" Hourly: 24 snapshots") fmt.Println(" Daily: 7 snapshots") fmt.Println(" Weekly: 4 snapshots") fmt.Println(" Monthly: 12 snapshots") fmt.Println("\nEnvironment Variables (can be set in .env file):") fmt.Println(" CLIENT_ID - Client identifier (default: client1)") fmt.Println(" API_KEY - API key for authentication (default: secret123)") fmt.Println(" SERVER_URL - Backup server URL (default: http://localhost:8080)") fmt.Println(" LOCAL_DATASET - ZFS dataset to backup (default: tank/data)") fmt.Println(" COMPRESS - Enable gzip compression (default: true)") fmt.Println(" STORAGE_TYPE - Storage type: s3 or local (default: s3)") fmt.Println("\nExamples:") fmt.Println(" zfs-client backup") fmt.Println(" zfs-client backup-full") fmt.Println(" zfs-client snapshot hourly") fmt.Println(" zfs-client rotate") fmt.Println(" CLIENT_ID=myclient zfs-client backup") }