GetBackups retrieves all backups for a VM across all available storages.
(vm *VM)
| 36 | |
| 37 | // GetBackups retrieves all backups for a VM across all available storages. |
| 38 | func (c *Client) GetBackups(vm *VM) ([]Backup, error) { |
| 39 | c.logger.Debug("GetBackups: Starting backup retrieval for VM %d on node %s", vm.ID, vm.Node) |
| 40 | |
| 41 | // 1. Get storages on the node |
| 42 | storages, err := c.GetNodeStorages(vm.Node) |
| 43 | if err != nil { |
| 44 | return nil, fmt.Errorf("failed to get node storages: %w", err) |
| 45 | } |
| 46 | |
| 47 | c.logger.Debug("GetBackups: Found %d storages on node %s", len(storages), vm.Node) |
| 48 | |
| 49 | var allBackups []Backup |
| 50 | var mu sync.Mutex |
| 51 | var wg sync.WaitGroup |
| 52 | |
| 53 | // 2. Iterate over storages in parallel |
| 54 | for _, storage := range storages { |
| 55 | // Check if storage supports backups |
| 56 | // Storage content is a comma-separated string, e.g. "iso,backup" |
| 57 | if !strings.Contains(storage.Content, "backup") { |
| 58 | continue |
| 59 | } |
| 60 | |
| 61 | wg.Add(1) |
| 62 | go func(s *Storage) { |
| 63 | defer wg.Done() |
| 64 | |
| 65 | c.logger.Debug("GetBackups: Checking storage %s for backups", s.Name) |
| 66 | |
| 67 | // 3. List content of type "backup" |
| 68 | path := fmt.Sprintf("/nodes/%s/storage/%s/content", vm.Node, s.Name) |
| 69 | |
| 70 | // We need to pass content=backup as query param. |
| 71 | fullPath := fmt.Sprintf("%s?content=backup", path) |
| 72 | |
| 73 | var result map[string]interface{} |
| 74 | // Use GetWithCache to improve performance, especially for slow network storages |
| 75 | // Backups don't change instantly without user action, and we clear cache on operations |
| 76 | if err := c.GetWithCache(fullPath, &result, NodeDataTTL); err != nil { |
| 77 | c.logger.Debug("Failed to list backups on storage %s: %v", s.Name, err) |
| 78 | return |
| 79 | } |
| 80 | |
| 81 | data, ok := result["data"].([]interface{}) |
| 82 | if !ok { |
| 83 | c.logger.Debug("GetBackups: No data in response for storage %s", s.Name) |
| 84 | return |
| 85 | } |
| 86 | |
| 87 | c.logger.Debug("GetBackups: Found %d items on storage %s", len(data), s.Name) |
| 88 | |
| 89 | var storageBackups []Backup |
| 90 | |
| 91 | for _, item := range data { |
| 92 | if backupData, ok := item.(map[string]interface{}); ok { |
| 93 | // Filter by VMID |
| 94 | itemVMID := 0 |
| 95 | if v, ok := backupData["vmid"].(float64); ok { |
nothing calls this directly
no test coverage detected