Merge pull request #17191 from wanyaoqi/fix/isolated_device_model_hot_pluggable

fix(region): isolated device model add properties hot pluggable
This commit is contained in:
Zexi Li
2023-05-30 17:40:18 +08:00
committed by GitHub
4 changed files with 89 additions and 13 deletions
+9
View File
@@ -129,6 +129,9 @@ type IsolatedDeviceModelCreateInput struct {
// 设备DeviceId
DeviceId string `json:"device_id"`
// 支持热插拔 HotPluggable
HotPluggable bool `json:"hot_pluggable"`
// hosts scan isolated device after isolated_device_model created
Hosts []string `json:"hosts"`
}
@@ -147,6 +150,9 @@ type IsolatedDeviceModelUpdateInput struct {
// 设备DeviceId
DeviceId string `json:"device_id"`
// 支持热插拔 HotPluggable
HotPluggable bool `json:"hot_pluggable"`
}
type IsolatedDeviceModelListInput struct {
@@ -164,4 +170,7 @@ type IsolatedDeviceModelListInput struct {
// 设备DeviceId
DeviceId string `json:"device_id"`
// 支持热插拔 HotPluggable
HotPluggable bool `json:"hot_pluggable"`
}
+45 -8
View File
@@ -1907,9 +1907,23 @@ func (self *SGuest) PerformDetachIsolatedDevice(ctx context.Context, userCred mc
lockman.LockObject(ctx, host)
defer lockman.ReleaseObject(ctx, host)
for i := 0; i < len(devs); i++ {
if devs[i].DevType == api.NIC_TYPE {
continue
// check first
dev := devs[i]
if !utils.IsInStringArray(dev.DevType, []string{api.GPU_HPC_TYPE, api.GPU_VGA_TYPE, api.USB_TYPE}) {
if devModel, err := IsolatedDeviceModelManager.GetByDevType(dev.DevType); err != nil {
msg := fmt.Sprintf("Can't separately detach dev type %s", dev.DevType)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
return nil, httperrors.NewBadRequestError(msg)
} else {
if !devModel.HotPluggable.Bool() && self.GetStatus() == api.VM_RUNNING {
msg := fmt.Sprintf("dev type %s model %s unhotpluggable", dev.DevType, devModel.Model)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
return nil, httperrors.NewBadRequestError(msg)
}
}
}
}
for i := 0; i < len(devs); i++ {
err := self.detachIsolateDevice(ctx, userCred, &devs[i])
if err != nil {
return nil, err
@@ -1928,12 +1942,20 @@ func (self *SGuest) startDetachIsolateDeviceWithoutNic(ctx context.Context, user
return httperrors.NewBadRequestError(msgFmt, device)
}
dev := iDev.(*SIsolatedDevice)
if dev.DevType == api.NIC_TYPE || dev.DevType == api.NVME_PT_TYPE {
return httperrors.NewBadRequestError("Can't separately detach dev type %s", dev.DevType)
}
if dev.IsGPU() && !utils.IsInStringArray(self.GetStatus(), []string{api.VM_READY, api.VM_RUNNING}) {
return httperrors.NewInvalidStatusError("Can't detach GPU when status is %q", self.GetStatus())
if !utils.IsInStringArray(dev.DevType, []string{api.GPU_HPC_TYPE, api.GPU_VGA_TYPE, api.USB_TYPE}) {
if devModel, err := IsolatedDeviceModelManager.GetByDevType(dev.DevType); err != nil {
msg := fmt.Sprintf("Can't separately detach dev type %s", dev.DevType)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
return httperrors.NewBadRequestError(msg)
} else {
if !devModel.HotPluggable.Bool() && self.GetStatus() == api.VM_RUNNING {
msg := fmt.Sprintf("dev type %s model %s unhotpluggable", dev.DevType, devModel.Model)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
return httperrors.NewBadRequestError(msg)
}
}
}
host, _ := self.GetHost()
lockman.LockObject(ctx, host)
defer lockman.ReleaseObject(ctx, host)
@@ -2013,6 +2035,17 @@ func (self *SGuest) startAttachIsolatedDevices(ctx context.Context, userCred mcc
if len(devs) == 0 || len(devs) != count {
return httperrors.NewBadRequestError("guest %s host %s isolated device not enough", self.GetName(), host.GetName())
}
dev := devs[0]
if !utils.IsInStringArray(dev.DevType, []string{api.GPU_HPC_TYPE, api.GPU_VGA_TYPE, api.USB_TYPE}) {
if devModel, err := IsolatedDeviceModelManager.GetByDevType(dev.DevType); err != nil {
return httperrors.NewBadRequestError("Can't separately attach dev type %s", dev.DevType)
} else {
if !devModel.HotPluggable.Bool() && self.GetStatus() == api.VM_RUNNING {
return httperrors.NewBadRequestError("dev type %s model %s unhotpluggable", dev.DevType, devModel.Model)
}
}
}
defer func() { go host.ClearSchedDescCache() }()
for i := 0; i < len(devs); i++ {
err = self.attachIsolatedDevice(ctx, userCred, &devs[i], nil, nil)
@@ -2041,8 +2074,12 @@ func (self *SGuest) startAttachIsolatedDevGeneral(ctx context.Context, userCred
}
dev := iDev.(*SIsolatedDevice)
if !utils.IsInStringArray(dev.DevType, []string{api.GPU_HPC_TYPE, api.GPU_VGA_TYPE, api.USB_TYPE}) {
if _, err = IsolatedDeviceModelManager.GetByDevType(dev.DevType); err != nil {
if devModel, err := IsolatedDeviceModelManager.GetByDevType(dev.DevType); err != nil {
return httperrors.NewBadRequestError("Can't separately attach dev type %s", dev.DevType)
} else {
if !devModel.HotPluggable.Bool() && self.GetStatus() == api.VM_RUNNING {
return httperrors.NewBadRequestError("dev type %s model %s unhotpluggable", dev.DevType, devModel.Model)
}
}
}
if !utils.IsInStringArray(self.GetStatus(), []string{api.VM_READY, api.VM_RUNNING}) {
+17 -5
View File
@@ -23,6 +23,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -59,6 +60,8 @@ type SIsolatedDeviceModel struct {
DeviceId string `width:"16" charset:"ascii" nullable:"false" list:"domain" create:"domain_required" update:"domain"`
DevType string `width:"16" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"`
HotPluggable tristate.TriState `default:"false" list:"domain" create:"domain_optional" update:"domain"`
}
func (manager *SIsolatedDeviceModelManager) ValidateCreateData(ctx context.Context,
@@ -159,16 +162,25 @@ func (self *SIsolatedDeviceModel) ValidateUpdateData(
input.DeviceId = strings.ToLower(input.DeviceId)
deviceVendorReg := regexp.MustCompile(`^[a-f0-9]{4}$`)
if !deviceVendorReg.MatchString(input.VendorId) {
if input.VendorId != "" && !deviceVendorReg.MatchString(input.VendorId) {
return input, httperrors.NewInputParameterError("bad vendor id %s", input.VendorId)
}
if !deviceVendorReg.MatchString(input.DeviceId) {
if input.DeviceId != "" && !deviceVendorReg.MatchString(input.DeviceId) {
return input, httperrors.NewInputParameterError("bad vendor id %s", input.DeviceId)
}
if self.VendorId != input.VendorId || self.DeviceId != input.DeviceId {
if cnt := IsolatedDeviceModelManager.Query().Equals("vendor_id", input.VendorId).Equals("device_id", input.DeviceId).Count(); cnt > 0 {
return input, httperrors.NewDuplicateResourceError("vendor %s device %s has been registered", input.VendorId, input.DeviceId)
if input.VendorId != "" || input.DeviceId != "" {
if input.VendorId == "" {
input.VendorId = self.VendorId
}
if input.DeviceId == "" {
input.DeviceId = self.DeviceId
}
if self.VendorId != input.VendorId || self.DeviceId != input.DeviceId {
if cnt := IsolatedDeviceModelManager.Query().Equals("vendor_id", input.VendorId).Equals("device_id", input.DeviceId).Count(); cnt > 0 {
return input, httperrors.NewDuplicateResourceError("vendor %s device %s has been registered", input.VendorId, input.DeviceId)
}
}
}
+18
View File
@@ -153,6 +153,14 @@ func (manager *SIsolatedDeviceManager) ValidateCreateData(ctx context.Context,
return input, errors.Wrap(err, "SStandaloneResourceBaseManager.ValidateCreateData")
}
if input.HostId != "" && input.Addr != "" {
if hasDevAddr, err := manager.hostHasDevAddr(input.HostId, input.Addr); err != nil {
return input, errors.Wrap(err, "check hostHasDevAddr")
} else if hasDevAddr {
return input, httperrors.NewBadRequestError("dev addr %s registed", input.Addr)
}
}
// validate reserverd resource
// inject default reserverd resource for gpu:
if utils.IsInStringArray(input.DevType, []string{api.GPU_HPC_TYPE, api.GPU_VGA_TYPE}) {
@@ -211,6 +219,7 @@ func (self *SIsolatedDevice) ValidateUpdateData(
}
}
}
return input, nil
}
@@ -900,6 +909,15 @@ func (manager *SIsolatedDeviceManager) GetDevsOnHost(hostId string, model string
return devs, nil
}
func (manager *SIsolatedDeviceManager) hostHasDevAddr(hostId, addr string) (bool, error) {
cnt, err := manager.Query().Equals("addr", addr).
Equals("host_id", hostId).CountWithError()
if err != nil {
return false, err
}
return cnt == 0, nil
}
func (manager *SIsolatedDeviceManager) CheckModelIsEmpty(model, vendor, device, devType string) (bool, error) {
cnt, err := manager.Query().Equals("model", model).
Equals("dev_type", devType).