diff --git a/backend/handlers/settings_iso.go b/backend/handlers/settings_iso.go index 9a6ef52..2636012 100644 --- a/backend/handlers/settings_iso.go +++ b/backend/handlers/settings_iso.go @@ -8,6 +8,7 @@ import ( "path/filepath" "sort" "strings" + "sync" "time" "github.com/julienschmidt/httprouter" @@ -85,6 +86,10 @@ func (h *SettingsHandler) fetchAllISOs(ctx context.Context, checkEnabled bool) ( } allISOs := make([]ISOEntry, 0) + var isoMu sync.Mutex + var wg sync.WaitGroup + // Semaphore to limit concurrent API calls to Proxmox (avoid overloading) + semaphore := make(chan struct{}, 5) // For each node, get ISOs from each compatible storage for _, nodeName := range nodes { @@ -95,33 +100,69 @@ func (h *SettingsHandler) fetchAllISOs(ctx context.Context, checkEnabled bool) ( continue } - isoList, err := proxmox.GetISOListResty(ctx, restyClient, nodeName, storage.Storage) - if err != nil { - logger.Get().Debug().Err(err). - Str("node", nodeName). - Str("storage", storage.Storage). - Msg("Failed to get ISO list for storage") - continue - } + wg.Add(1) + go func(n, s string) { + defer wg.Done() - for _, iso := range isoList { - entry := ISOEntry{ - Node: nodeName, - Storage: storage.Storage, - Volid: iso.VolID, - Size: iso.Size, - Format: iso.Format, + // Acquire semaphore + select { + case semaphore <- struct{}{}: + defer func() { <-semaphore }() + case <-ctx.Done(): + return } - if _, ok := enabledSet[iso.VolID]; ok { - entry.Enabled = true + // Check context before making request + if ctx.Err() != nil { + return } - allISOs = append(allISOs, entry) - } + isoList, err := proxmox.GetISOListResty(ctx, restyClient, n, s) + if err != nil { + logger.Get().Debug().Err(err). + Str("node", n). + Str("storage", s). + Msg("Failed to get ISO list for storage (possibly offline or slow)") + return + } + + isoMu.Lock() + defer isoMu.Unlock() + + for _, iso := range isoList { + entry := ISOEntry{ + Node: n, + Storage: s, + Volid: iso.VolID, + Size: iso.Size, + Format: iso.Format, + } + + if _, ok := enabledSet[iso.VolID]; ok { + entry.Enabled = true + } + + allISOs = append(allISOs, entry) + } + }(nodeName, storage.Storage) } } + // Wait for all fetches to complete + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + + // Wait for completion or context cancellation + select { + case <-done: + // All good + case <-ctx.Done(): + return nil, fmt.Errorf("timeout while fetching ISOs: %w", ctx.Err()) + } + return allISOs, nil } diff --git a/backend/handlers/storage.go b/backend/handlers/storage.go index c03e573..e29d03c 100644 --- a/backend/handlers/storage.go +++ b/backend/handlers/storage.go @@ -361,9 +361,9 @@ type cachedStorages struct { } var vmDiskTypes = map[string]struct{}{ - "ceph": {}, - "cephfs": {}, + "cifs": {}, "dir": {}, + "iscsi": {}, "lvm": {}, "lvmthin": {}, "nfs": {}, diff --git a/backend/handlers/vm_create.go b/backend/handlers/vm_create.go index e732713..e6a7fc4 100644 --- a/backend/handlers/vm_create.go +++ b/backend/handlers/vm_create.go @@ -53,14 +53,14 @@ func NormalizeMACAddress(mac string) string { // vmDiskCompatibleStorageTypes defines storage types that support VM disk images // These storage types can store VM disks even if their content string doesn't explicitly list "images" var vmDiskCompatibleStorageTypes = map[string]bool{ - "lvmthin": true, - "lvm": true, - "zfs": true, - "ceph": true, - "iscsi": true, + "cifs": true, "dir": true, + "iscsi": true, + "lvm": true, + "lvmthin": true, "nfs": true, - "cifs": true, + "rbd": true, + "zfs": true, } // countVMsInPool counts the number of VMs in a user's pool @@ -1147,7 +1147,6 @@ func getTPMDiskFormat(storageType string) (string, bool) { // Block-based storages that support raw format blockStorages := map[string]bool{ - "ceph": true, "iscsi": true, "lvm": true, "lvmthin": true, @@ -1157,9 +1156,10 @@ func getTPMDiskFormat(storageType string) (string, bool) { // File-based storages that support raw format fileStorages := map[string]bool{ - "dir": true, - "nfs": true, - "cifs": true, + "cephfs": true, + "cifs": true, + "dir": true, + "nfs": true, } // Check if storage type is compatible diff --git a/backend/proxmox/iso.go b/backend/proxmox/iso.go index 5213770..0f8ff4c 100644 --- a/backend/proxmox/iso.go +++ b/backend/proxmox/iso.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/url" + "strings" "pvmss/logger" ) @@ -45,7 +46,8 @@ func GetISOListResty(ctx context.Context, restyClient *RestyClient, node, storag // Filter for ISO files only var isos []ISO for _, item := range response.Data { - if item.Format == "iso" { + volidLower := strings.ToLower(item.VolID) + if item.Format == "iso" || strings.HasSuffix(volidLower, ".iso") { isos = append(isos, item) } } diff --git a/frontend/admin_storage.html b/frontend/admin_storage.html index 8e76c02..35c4bd0 100644 --- a/frontend/admin_storage.html +++ b/frontend/admin_storage.html @@ -110,8 +110,11 @@