mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
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:
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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}) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user