From 1eb253e3ee15594e0f0e425c6bddd5587e9debc4 Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Tue, 16 Apr 2024 12:11:23 +0800 Subject: [PATCH] fix(region,host): custom device model add auto detect option Signed-off-by: wanyaoqi --- .../shell/compute/isolated_device_models.go | 70 ++++++++++ pkg/apis/compute/isolated_device.go | 19 +++ pkg/apis/compute/isolated_device_const.go | 2 - .../models/host_isolated_device_models.go | 121 ++++++++++++++++++ pkg/compute/models/isolated_device_models.go | 43 ++++++- pkg/compute/service/handlers.go | 1 + .../isolated_device/isolated_device.go | 1 + .../mod_host_isolated_device_models.go | 20 +++ .../compute/mod_isolated_device_models.go | 2 +- .../options/compute/isolated_device_models.go | 19 +-- 10 files changed, 284 insertions(+), 14 deletions(-) create mode 100644 pkg/compute/models/host_isolated_device_models.go create mode 100644 pkg/mcclient/modules/compute/mod_host_isolated_device_models.go diff --git a/cmd/climc/shell/compute/isolated_device_models.go b/cmd/climc/shell/compute/isolated_device_models.go index fc29c0388d..83f45f382b 100644 --- a/cmd/climc/shell/compute/isolated_device_models.go +++ b/cmd/climc/shell/compute/isolated_device_models.go @@ -15,8 +15,13 @@ package compute import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/printutils" + "yunion.io/x/onecloud/cmd/climc/shell" + "yunion.io/x/onecloud/pkg/mcclient" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + baseoptions "yunion.io/x/onecloud/pkg/mcclient/options" options "yunion.io/x/onecloud/pkg/mcclient/options/compute" ) @@ -28,4 +33,69 @@ func init() { cmd.Delete(new(options.IsolatedDeviceIdsOptions)) cmd.Perform("set-hardware-info", new(options.IsolatedDeviceModelSetHardwareInfoOptions)) cmd.Get("hardware-info", new(options.IsolatedDeviceIdsOptions)) + + type HostIsolatedDeviceModelListOptions struct { + baseoptions.BaseListOptions + Host string `help:"ID or Name of Host"` + IsolatedDeviceModel string `help:"ID or Name of Isolated device model"` + } + R(&HostIsolatedDeviceModelListOptions{}, "host-isolated-device-model-list", + "List host Isolated device model pairs", func(s *mcclient.ClientSession, args *HostIsolatedDeviceModelListOptions) error { + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } + var result *printutils.ListResult + var err error + if len(args.Host) > 0 { + result, err = modules.HostIsolatedDeviceModels.ListDescendent(s, args.Host, params) + } else if len(args.IsolatedDeviceModel) > 0 { + result, err = modules.HostIsolatedDeviceModels.ListDescendent2(s, args.IsolatedDeviceModel, params) + } else { + result, err = modules.HostIsolatedDeviceModels.List(s, params) + } + if err != nil { + return err + } + printList(result, modules.HostIsolatedDeviceModels.GetColumns(s)) + return nil + }) + + type HostIsolatedDeviceModelDetailOptions struct { + HOST string `help:"ID or Name of Host"` + IsolatedDeviceModel string `help:"ID or Name of Isolated device model"` + } + R(&HostIsolatedDeviceModelDetailOptions{}, "host-isolated-device-model-show", "Show host isolated-device-model details", func(s *mcclient.ClientSession, args *HostIsolatedDeviceModelDetailOptions) error { + result, err := modules.HostIsolatedDeviceModels.Get(s, args.HOST, args.IsolatedDeviceModel, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostIsolatedDeviceModelDetailOptions{}, "host-isolated-device-model-detach", "Detach a isolated-device-model from a host", func(s *mcclient.ClientSession, args *HostIsolatedDeviceModelDetailOptions) error { + result, err := modules.HostIsolatedDeviceModels.Detach(s, args.HOST, args.IsolatedDeviceModel, nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + + R(&HostIsolatedDeviceModelDetailOptions{}, "host-isolated-device-model-attach", "Attach a isolated-device-model to a host", func(s *mcclient.ClientSession, args *HostIsolatedDeviceModelDetailOptions) error { + params := jsonutils.NewDict() + result, err := modules.HostIsolatedDeviceModels.Attach(s, args.HOST, args.IsolatedDeviceModel, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + } diff --git a/pkg/apis/compute/isolated_device.go b/pkg/apis/compute/isolated_device.go index ba65aed6c4..c613764dc9 100644 --- a/pkg/apis/compute/isolated_device.go +++ b/pkg/apis/compute/isolated_device.go @@ -194,6 +194,9 @@ type IsolatedDeviceModelListInput struct { // 支持热插拔 HotPluggable HotPluggable bool `json:"hot_pluggable"` + + // 宿主机 Id + HostId string `json:"host_id"` } type IsolatedDeviceModelHardwareInfo struct { @@ -329,3 +332,19 @@ func (info IsolatedDevicePCIEInfo) GetThroughputPerLane() PCIEVersionThroughput } return NewPCIEVersionThroughput(PCIEVersionUnknown) } + +type HostIsolatedDeviceModelDetails struct { + SHostJointsBase + HostJointResourceDetails + // 宿主机Id + HostId string `json:"host_id"` + // 存储Id + IsolatedDeviceModelId string `json:"isolated_device_model_id"` + + Model string + VendorId string + DeviceId string + DevType string + HotPluggable bool + DisableAutoDetect bool +} diff --git a/pkg/apis/compute/isolated_device_const.go b/pkg/apis/compute/isolated_device_const.go index 2b491d6ef1..25b2e368ae 100644 --- a/pkg/apis/compute/isolated_device_const.go +++ b/pkg/apis/compute/isolated_device_const.go @@ -28,8 +28,6 @@ const ( AMD_VENDOR_ID = "1002" ) -const MEAT_PROBED_HOST_COUNT = "probed_host_count" - var VALID_GPU_TYPES = []string{GPU_HPC_TYPE, GPU_VGA_TYPE} var VALID_ATTACH_TYPES = []string{GPU_HPC_TYPE, GPU_VGA_TYPE, USB_TYPE, SRIOV_VGPU_TYPE, LEGACY_VGPU_TYPE} diff --git a/pkg/compute/models/host_isolated_device_models.go b/pkg/compute/models/host_isolated_device_models.go new file mode 100644 index 0000000000..bc54d39a97 --- /dev/null +++ b/pkg/compute/models/host_isolated_device_models.go @@ -0,0 +1,121 @@ +package models + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SHostIsolatedDeviceModelManager struct { + SHostJointsManager +} + +var HostIsolatedDeviceModelManager *SHostIsolatedDeviceModelManager + +func init() { + db.InitManager(func() { + HostIsolatedDeviceModelManager = &SHostIsolatedDeviceModelManager{ + SHostJointsManager: NewHostJointsManager( + "host_id", + SHostIsolatedDeviceModel{}, + "host_isolated_device_models_tbl", + "host_isolated_device_model", + "host_isolated_device_models", + IsolatedDeviceModelManager, + ), + } + HostIsolatedDeviceModelManager.SetVirtualObject(HostIsolatedDeviceModelManager) + HostIsolatedDeviceModelManager.TableSpec().AddIndex(false, "host_id", "isolated_device_model_id") + }) +} + +type SHostIsolatedDeviceModel struct { + SHostJointsBase + + // 宿主机Id + HostId string `width:"36" charset:"ascii" nullable:"false" list:"domain" create:"required" json:"host_id"` + // 设备类型Id + IsolatedDeviceModelId string `width:"36" charset:"ascii" nullable:"false" list:"domain" create:"required" json:"isolated_device_model_id" index:"true"` +} + +func (manager *SHostIsolatedDeviceModelManager) GetMasterFieldName() string { + return "host_id" +} + +func (manager *SHostIsolatedDeviceModelManager) GetSlaveFieldName() string { + return "isolated_device_model_id" +} + +func (self *SHostIsolatedDeviceModel) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { + return db.DeleteModel(ctx, userCred, self) +} + +func (self *SHostIsolatedDeviceModel) Detach(ctx context.Context, userCred mcclient.TokenCredential) error { + return db.DetachJoint(ctx, userCred, self) +} + +func (manager *SHostIsolatedDeviceModelManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HostIsolatedDeviceModelDetails { + rows := make([]api.HostIsolatedDeviceModelDetails, len(objs)) + hostRows := manager.SHostJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + devModelIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.HostIsolatedDeviceModelDetails{ + HostJointResourceDetails: hostRows[i], + } + devModelIds[i] = objs[i].(*SHostIsolatedDeviceModel).IsolatedDeviceModelId + } + + devModels := make(map[string]SIsolatedDeviceModel) + err := db.FetchStandaloneObjectsByIds(IsolatedDeviceModelManager, devModelIds, &devModels) + if err != nil { + log.Errorf("db.FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if devModel, ok := devModels[devModelIds[i]]; ok { + rows[i] = objs[i].(*SHostIsolatedDeviceModel).getExtraDetails(devModel, rows[i]) + } + } + + return rows +} + +func (self *SHostIsolatedDeviceModel) getExtraDetails(devModel SIsolatedDeviceModel, out api.HostIsolatedDeviceModelDetails) api.HostIsolatedDeviceModelDetails { + out.Model = devModel.Model + out.VendorId = devModel.VendorId + out.DeviceId = devModel.DeviceId + out.DevType = devModel.DevType + out.HotPluggable = devModel.HotPluggable.Bool() + out.DisableAutoDetect = devModel.DisableAutoDetect.Bool() + return out +} + +func (self *SHostIsolatedDeviceModel) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { + self.SHostJointsBase.PostCreate(ctx, userCred, ownerId, query, data) + + iHost, err := HostManager.FetchByIdOrName(ctx, userCred, self.HostId) + if err != nil { + log.Errorf("failed fetch host %s: %s", self.HostId, err) + return + } + host := iHost.(*SHost) + log.Infof("start request host %s scan isolated devices", host.GetName()) + if err := host.RequestScanIsolatedDevices(ctx, userCred); err != nil { + log.Errorf("failed scan isolated device %s", err) + } +} diff --git a/pkg/compute/models/isolated_device_models.go b/pkg/compute/models/isolated_device_models.go index 1bcb10593b..0af4028e26 100644 --- a/pkg/compute/models/isolated_device_models.go +++ b/pkg/compute/models/isolated_device_models.go @@ -62,8 +62,15 @@ type SIsolatedDeviceModel struct { 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"` + + // Disable auto detect isolated devices on host + DisableAutoDetect tristate.TriState `default:"false" list:"domain" create:"domain_optional" update:"domain"` } +var _ db.IStandaloneModel = new(SIsolatedDeviceModel) + +func (self *SIsolatedDeviceModel) SetName(name string) {} + func (manager *SIsolatedDeviceModelManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, @@ -102,9 +109,8 @@ func (self *SIsolatedDeviceModel) PostCreate(ctx context.Context, userCred mccli if err != nil { log.Errorf("!!!data.Unmarshal api.IsolatedDeviceModelCreateInput fail %s", err) } - go func() { - defer self.RemoveMetadata(ctx, api.MEAT_PROBED_HOST_COUNT, userCred) + go func() { for i := range input.Hosts { iHost, err := HostManager.FetchByIdOrName(ctx, userCred, input.Hosts[i]) if err != nil { @@ -112,15 +118,37 @@ func (self *SIsolatedDeviceModel) PostCreate(ctx context.Context, userCred mccli continue } host := iHost.(*SHost) + + if self.DisableAutoDetect.Bool() { + err = self.Attach2Host(ctx, userCred, host) + if err != nil { + log.Errorf("failed attach to host %s: %s", input.Hosts[i], err) + continue + } + } + log.Infof("start request host %s scan isolated devices", host.GetName()) if err := host.RequestScanIsolatedDevices(ctx, userCred); err != nil { log.Errorf("failed scan isolated device %s", err) } - self.SetMetadata(ctx, api.MEAT_PROBED_HOST_COUNT, strconv.Itoa(i+1), userCred) } }() } +func (self *SIsolatedDeviceModel) Attach2Host(ctx context.Context, userCred mcclient.TokenCredential, host *SHost) error { + hs := SHostIsolatedDeviceModel{} + hs.SetModelManager(HostIsolatedDeviceModelManager, &hs) + + hs.IsolatedDeviceModelId = self.Id + hs.HostId = host.Id + err := HostIsolatedDeviceModelManager.TableSpec().Insert(ctx, &hs) + if err != nil { + return err + } + db.OpsLog.LogAttachEvent(ctx, host, self, userCred, nil) + return nil +} + func (self *SIsolatedDeviceModel) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error { modelIsEmpty, err := IsolatedDeviceManager.CheckModelIsEmpty(self.Model, self.VendorId, self.DeviceId, self.DevType) if err != nil { @@ -217,6 +245,15 @@ func (manager *SIsolatedDeviceModelManager) ListItemFilter( if len(query.DeviceId) > 0 { q = q.Equals("device_id", query.DeviceId) } + if len(query.HostId) > 0 { + hidmq := HostIsolatedDeviceModelManager.Query("isolated_device_model_id").Equals("host_id", query.HostId).SubQuery() + q = q.Filter(sqlchemy.OR( + sqlchemy.IsFalse(q.Field("disable_auto_detect")), + sqlchemy.IsNull(q.Field("disable_auto_detect")), + sqlchemy.In(q.Field("id"), hidmq)), + ) + } + return q, nil } diff --git a/pkg/compute/service/handlers.go b/pkg/compute/service/handlers.go index 0e0ab9d31e..6f0fc6ffee 100644 --- a/pkg/compute/service/handlers.go +++ b/pkg/compute/service/handlers.go @@ -256,6 +256,7 @@ func InitHandlers(app *appsrv.Application) { models.HostnetworkManager, models.HoststorageManager, models.HostschedtagManager, + models.HostIsolatedDeviceModelManager, models.StorageschedtagManager, models.NetworkschedtagManager, models.CloudproviderschedtagManager, diff --git a/pkg/hostman/isolated_device/isolated_device.go b/pkg/hostman/isolated_device/isolated_device.go index 47ec596546..10e3f560a3 100644 --- a/pkg/hostman/isolated_device/isolated_device.go +++ b/pkg/hostman/isolated_device/isolated_device.go @@ -403,6 +403,7 @@ func (man *isolatedDeviceManager) getCustomIsolatedDeviceModels() ([]IsolatedDev params := jsonutils.NewDict() params.Set("limit", jsonutils.NewInt(0)) params.Set("scope", jsonutils.NewString("system")) + params.Set("host_id", jsonutils.NewString(man.host.GetHostId())) res, err := modules.IsolatedDeviceModels.List(man.getSession(), jsonutils.NewDict()) if err != nil { return nil, errors.Wrap(err, "list isolated_device_models from compute service") diff --git a/pkg/mcclient/modules/compute/mod_host_isolated_device_models.go b/pkg/mcclient/modules/compute/mod_host_isolated_device_models.go new file mode 100644 index 0000000000..5d29f62e06 --- /dev/null +++ b/pkg/mcclient/modules/compute/mod_host_isolated_device_models.go @@ -0,0 +1,20 @@ +package compute + +import ( + "yunion.io/x/onecloud/pkg/mcclient/modulebase" + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +var ( + HostIsolatedDeviceModels modulebase.JointResourceManager +) + +func init() { + HostIsolatedDeviceModels = modules.NewJointComputeManager("host_isolated_device_model", "host_isolated_device_models", + []string{"Host_ID", "Host", "Isolated_device_model_id", "Isolated_device_model", "Model", "Dev_type", "Device_id", "Vendor_id", + "Hot_pluggable", "Disable_auto_detect"}, + []string{}, + &Hosts, + &IsolatedDeviceModels) + modules.RegisterCompute(&HostIsolatedDeviceModels) +} diff --git a/pkg/mcclient/modules/compute/mod_isolated_device_models.go b/pkg/mcclient/modules/compute/mod_isolated_device_models.go index c6496f4825..9569802cd0 100644 --- a/pkg/mcclient/modules/compute/mod_isolated_device_models.go +++ b/pkg/mcclient/modules/compute/mod_isolated_device_models.go @@ -26,7 +26,7 @@ var ( func init() { IsolatedDeviceModels = modules.NewComputeManager("isolated_device_model", "isolated_device_models", []string{"ID", "Dev_type", - "Model", "Vendor_id", "Device_id"}, + "Model", "Vendor_id", "Device_id", "Hot_pluggable", "Disable_auto_detect"}, []string{}) modules.RegisterCompute(&IsolatedDeviceModels) } diff --git a/pkg/mcclient/options/compute/isolated_device_models.go b/pkg/mcclient/options/compute/isolated_device_models.go index 8a5b96f844..4bb37b0868 100644 --- a/pkg/mcclient/options/compute/isolated_device_models.go +++ b/pkg/mcclient/options/compute/isolated_device_models.go @@ -28,6 +28,7 @@ type IsolatedDeviceModelListOptions struct { Model string `help:"filter by device model"` VendorId string `help:"filter by vendor id"` DeviceId string `help:"filter by device id"` + HostId string `help:"filter by host id"` } func (o *IsolatedDeviceModelListOptions) Params() (jsonutils.JSONObject, error) { @@ -35,11 +36,12 @@ func (o *IsolatedDeviceModelListOptions) Params() (jsonutils.JSONObject, error) } type IsolatedDeviceModelCreateOptions struct { - MODEL string `help:"device model name"` - DEV_TYPE string `help:"custom device type"` - VENDOR_ID string `help:"pci vendor id"` - DEVICE_ID string `help:"pci device id"` - Hosts []string `help:"hosts id or name rescan isolated device"` + MODEL string `help:"device model name"` + DEV_TYPE string `help:"custom device type"` + VENDOR_ID string `help:"pci vendor id"` + DEVICE_ID string `help:"pci device id"` + DISABLE_AUTO_DETECT bool `help:"disable auto detect isolated devices on all of host"` + Hosts []string `help:"hosts id or name rescan isolated device"` } func (o *IsolatedDeviceModelCreateOptions) Params() (jsonutils.JSONObject, error) { @@ -49,9 +51,10 @@ func (o *IsolatedDeviceModelCreateOptions) Params() (jsonutils.JSONObject, error type IsolatedDeviceModelUpdateOptions struct { options.BaseIdOptions - MODEL string `help:"device model name"` - VENDOR_ID string `help:"pci vendor id"` - DEVICE_ID string `help:"pci device id"` + MODEL string `help:"device model name"` + VENDOR_ID string `help:"pci vendor id"` + DEVICE_ID string `help:"pci device id"` + DISABLE_AUTO_DETECT bool `help:"disable auto detect isolated devices on all of host"` } func (o *IsolatedDeviceModelUpdateOptions) Params() (jsonutils.JSONObject, error) {