diff --git a/pkg/compute/models/capabilities.go b/pkg/compute/models/capabilities.go index 329359c1cc..189ffa77bc 100644 --- a/pkg/compute/models/capabilities.go +++ b/pkg/compute/models/capabilities.go @@ -112,11 +112,12 @@ type SCapabilities struct { ReadOnlyVpcPeerBrands []string `json:",allowempty"` ReadOnlyDisabledVpcPeerBrands []string `json:",allowempty"` - ResourceTypes []string `json:",allowempty"` - StorageTypes []string `json:",allowempty"` // going to remove on 2.14 - DataStorageTypes []string `json:",allowempty"` // going to remove on 2.14 - GPUModels []string `json:",allowempty"` - HostCpuArchs []string `json:",allowempty"` // x86_64 aarch64 + ResourceTypes []string `json:",allowempty"` + StorageTypes []string `json:",allowempty"` // going to remove on 2.14 + DataStorageTypes []string `json:",allowempty"` // going to remove on 2.14 + GPUModels []string `json:",allowempty"` // Deprecated by GPUModelTypes + GPUModelTypes []GpuModelTypes `json:",allowempty"` + HostCpuArchs []string `json:",allowempty"` // x86_64 aarch64 MinNicCount int MaxNicCount int MinDataDiskCount int @@ -195,7 +196,7 @@ func GetCapabilities(ctx context.Context, userCred mcclient.TokenCredential, que capa.StorageTypes, capa.DataStorageTypes = s1, d1 capa.StorageTypes2, capa.StorageTypes3 = s2, s3 capa.DataStorageTypes2, capa.DataStorageTypes3 = d2, d3 - capa.GPUModels = getGPUs(region, zone, domainId) + capa.GPUModels, capa.GPUModelTypes = getGPUs(region, zone, domainId) capa.SchedPolicySupport = isSchedPolicySupported(region, zone) capa.MinNicCount = getMinNicCount(region, zone) capa.MaxNicCount = getMaxNicCount(region, zone) @@ -741,7 +742,12 @@ func getStorageTypes( allHypervisorStorageTypes, allHypervisorStorageInfos } -func getGPUs(region *SCloudregion, zone *SZone, domainId string) []string { +type GpuModelTypes struct { + Model string + DevType string +} + +func getGPUs(region *SCloudregion, zone *SZone, domainId string) ([]string, []GpuModelTypes) { devices := IsolatedDeviceManager.Query().SubQuery() hostQuery := HostManager.Query() if len(domainId) > 0 { @@ -750,7 +756,7 @@ func getGPUs(region *SCloudregion, zone *SZone, domainId string) []string { } hosts := hostQuery.SubQuery() - q := devices.Query(devices.Field("model")) + q := devices.Query(devices.Field("model"), devices.Field("dev_type")) q = q.Startswith("dev_type", "GPU") if region != nil { subq := getRegionZoneSubq(region) @@ -768,22 +774,30 @@ func getGPUs(region *SCloudregion, zone *SZone, domainId string) []string { sqlchemy.IsNullOrEmpty(hosts.Field("manager_id")), )) }*/ - q = q.Distinct() + q = q.GroupBy(devices.Field("model"), devices.Field("dev_type")) rows, err := q.Rows() if err != nil { - return nil + log.Errorf("failed get gpu caps: %s", err) + return nil, nil } defer rows.Close() - gpus := make([]string, 0) + gpus := make([]GpuModelTypes, 0) + gpuModels := make([]string, 0) for rows.Next() { - var model string - rows.Scan(&model) - if len(model) > 0 { - gpus = append(gpus, model) + var m, t string + rows.Scan(&m, &t) + + if m == "" { + continue + } + gpus = append(gpus, GpuModelTypes{m, t}) + + if !utils.IsInStringArray(m, gpuModels) { + gpuModels = append(gpuModels, m) } } - return gpus + return gpuModels, gpus } func getHostCpuArchs(region *SCloudregion, zone *SZone, domainId string) []string { diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 5ed0ac7038..29648c99b5 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -1416,10 +1416,6 @@ func (manager *SGuestManager) validateCreateData( support := desc == "true" imgSupportUEFI = &support } - // imgIsWindows := imgProperties[imageapi.IMAGE_OS_TYPE] == "Windows" - // if imgSupportUEFI && imgIsWindows && len(input.IsolatedDevices) > 0 { - // input.Bios = "UEFI" // windows gpu passthrough - // } if input.OsArch == apis.OS_ARCH_AARCH64 { // arm image supports UEFI by default support := true @@ -1445,6 +1441,19 @@ func (manager *SGuestManager) validateCreateData( imgProperties = map[string]string{"os_type": "Linux"} } input.DisableUsbKbd = imgProperties[imageapi.IMAGE_DISABLE_USB_KBD] == "true" + imgIsWindows := imgProperties[imageapi.IMAGE_OS_TYPE] == "Windows" + + hasGpuVga := func() bool { + for i := 0; i < len(input.IsolatedDevices); i++ { + if input.IsolatedDevices[i].DevType == GPU_VGA_TYPE { + return true + } + } + return false + }() + if imgIsWindows && hasGpuVga && input.Bios != "UEFI" { + return nil, httperrors.NewInputParameterError("Windows use gpu vga requires UEFI image") + } if vdi, ok := imgProperties[imageapi.IMAGE_VDI_PROTOCOL]; ok && len(vdi) > 0 && len(input.Vdi) == 0 { input.Vdi = vdi diff --git a/pkg/compute/models/isolated_devices.go b/pkg/compute/models/isolated_devices.go index 2989f9a4d9..d5be64020e 100644 --- a/pkg/compute/models/isolated_devices.go +++ b/pkg/compute/models/isolated_devices.go @@ -346,17 +346,22 @@ func (manager *SIsolatedDeviceManager) findAttachedDevicesOfGuest(guest *SGuest) return devs } -func (manager *SIsolatedDeviceManager) fuzzyMatchModel(fuzzyStr string) *SIsolatedDevice { +func (manager *SIsolatedDeviceManager) fuzzyMatchModel(fuzzyStr string, devType string) *SIsolatedDevice { dev := SIsolatedDevice{} dev.SetModelManager(manager, &dev) - q := manager.Query().Equals("model", fuzzyStr) - cnt, err := q.CountWithError() - if err != nil || cnt == 0 { - q = manager.Query().Contains("model", fuzzyStr) + q := manager.Query() + if devType != "" { + q = q.Equals("dev_type", devType) } - err = q.First(&dev) + qe := q.Equals("model", fuzzyStr) + cnt, err := qe.CountWithError() + if err != nil || cnt == 0 { + qe = q.Contains("model", fuzzyStr) + } + + err = qe.First(&dev) if err == nil { return &dev } @@ -387,7 +392,7 @@ func (manager *SIsolatedDeviceManager) parseDeviceInfo(userCred mcclient.TokenCr var matchDev *SIsolatedDevice devId = devConfig.Id - matchDev = manager.fuzzyMatchModel(devConfig.Model) + matchDev = manager.fuzzyMatchModel(devConfig.Model, devConfig.DevType) devVendor = devConfig.Vendor devType = devConfig.DevType @@ -486,7 +491,7 @@ func (manager *SIsolatedDeviceManager) attachHostDeviceToGuestByModel(ctx contex return fmt.Errorf("Not found model from info: %#v", devConfig) } // if dev type is not nic, wire is empty string - devs, err := manager.findHostUnusedByModelAndWire(devConfig.Model, host.Id, devConfig.WireId) + devs, err := manager.findHostUnusedByDevConfig(devConfig.Model, devConfig.DevType, host.Id, devConfig.WireId) if err != nil || len(devs) == 0 { return fmt.Errorf("Can't found model %s on host %s", devConfig.Model, host.Id) } @@ -549,10 +554,16 @@ func (manager *SIsolatedDeviceManager) FindUnusedGpusOnHost(hostId string) ([]SI return devs, nil } -func (manager *SIsolatedDeviceManager) findHostUnusedByModelAndWire(model, hostId, wireId string) ([]SIsolatedDevice, error) { +func (manager *SIsolatedDeviceManager) findHostUnusedByDevConfig(model, devType, hostId, wireId string) ([]SIsolatedDevice, error) { devs := make([]SIsolatedDevice, 0) q := manager.findUnusedQuery() - q = q.Equals("model", model).Equals("host_id", hostId).Equals("wire_id", wireId) + q = q.Equals("model", model).Equals("host_id", hostId) + if devType != "" { + q.Equals("dev_type", devType) + } + if wireId != "" { + q = q.Equals("wire_id", wireId) + } err := db.FetchModelObjects(manager, q, &devs) if err != nil { return nil, err