Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 60 additions & 19 deletions backend/handlers/settings_iso.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path/filepath"
"sort"
"strings"
"sync"
"time"

"github.com/julienschmidt/httprouter"
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down
4 changes: 2 additions & 2 deletions backend/handlers/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,9 +361,9 @@ type cachedStorages struct {
}

var vmDiskTypes = map[string]struct{}{
"ceph": {},
"cephfs": {},
"cifs": {},
"dir": {},
"iscsi": {},
"lvm": {},
"lvmthin": {},
"nfs": {},
Expand Down
20 changes: 10 additions & 10 deletions backend/handlers/vm_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion backend/proxmox/iso.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/url"
"strings"

"pvmss/logger"
)
Expand Down Expand Up @@ -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)
}
}
Expand Down
5 changes: 4 additions & 1 deletion frontend/admin_storage.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,11 @@ <h2 class="title is-5 mb-2">
</td>
<td>
<div class="tags">
<span class="tag is-info is-light">{{.Type}}</span>
{{range $type := split .Content ","}}
<span class="tag is-light">{{$type}}</span>
{{if ne $type ""}}
<span class="tag is-light">{{$type}}</span>
{{end}}
{{end}}
</div>
</td>
Expand Down
Loading