| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package models
- import (
- "context"
- "regexp"
- "strconv"
- "strings"
- "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"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- )
- var IsolatedDeviceModelManager *SIsolatedDeviceModelManager
- func init() {
- IsolatedDeviceModelManager = &SIsolatedDeviceModelManager{
- SStandaloneAnonResourceBaseManager: db.NewStandaloneAnonResourceBaseManager(
- SIsolatedDeviceModel{},
- "isolated_device_models_tbl",
- "isolated_device_model",
- "isolated_device_models",
- ),
- }
- IsolatedDeviceModelManager.SetVirtualObject(IsolatedDeviceModelManager)
- }
- type SIsolatedDeviceModelManager struct {
- db.SStandaloneAnonResourceBaseManager
- }
- type SIsolatedDeviceModel struct {
- db.SStandaloneAnonResourceBase
- Model string `width:"512" charset:"ascii" nullable:"false" list:"domain" create:"domain_required" update:"domain"`
- VendorId string `width:"16" charset:"ascii" nullable:"false" list:"domain" create:"domain_required" update:"domain"`
- 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"`
- // 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,
- query jsonutils.JSONObject,
- input api.IsolatedDeviceModelCreateInput,
- ) (api.IsolatedDeviceModelCreateInput, error) {
- if utils.IsInStringArray(input.DevType, api.VALID_PASSTHROUGH_TYPES) {
- return input, httperrors.NewInputParameterError("device type %q unsupported", input.DevType)
- }
- input.VendorId = strings.ToLower(input.VendorId)
- input.DeviceId = strings.ToLower(input.DeviceId)
- deviceVendorReg := regexp.MustCompile(`^[a-f0-9]{4}$`)
- if !deviceVendorReg.MatchString(input.VendorId) {
- return input, httperrors.NewInputParameterError("bad vendor id %s", input.VendorId)
- }
- if !deviceVendorReg.MatchString(input.DeviceId) {
- return input, httperrors.NewInputParameterError("bad vendor id %s", input.DeviceId)
- }
- if cnt := manager.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 cnt := manager.Query().Equals("model", input.Model).Count(); cnt > 0 {
- return input, httperrors.NewDuplicateResourceError("model %s has been registered", input.Model)
- }
- return input, nil
- }
- func (self *SIsolatedDeviceModel) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- input := api.IsolatedDeviceModelCreateInput{}
- err := data.Unmarshal(&input)
- if err != nil {
- log.Errorf("!!!data.Unmarshal api.IsolatedDeviceModelCreateInput fail %s", err)
- }
- go func() {
- for i := range input.Hosts {
- iHost, err := HostManager.FetchByIdOrName(ctx, userCred, input.Hosts[i])
- if err != nil {
- log.Errorf("failed fetch host %s: %s", input.Hosts[i], err)
- 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)
- }
- }
- }()
- }
- 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 {
- return err
- }
- if !modelIsEmpty {
- return httperrors.NewNotEmptyError("device model has guests")
- }
- return nil
- }
- func (self *SIsolatedDeviceModel) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) {
- hosts, err := IsolatedDeviceManager.GetHostsByModel(self.Model, self.VendorId, self.DeviceId, self.DevType)
- if err != nil {
- log.Errorf("failed get hosts by isolated device model: %s", err)
- return
- }
- go func() {
- for i := range hosts {
- iHost, err := HostManager.FetchByIdOrName(ctx, userCred, hosts[i])
- if err != nil {
- log.Errorf("failed fetch host %s: %s", hosts[i], err)
- continue
- }
- 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)
- }
- }
- }()
- }
- func (self *SIsolatedDeviceModel) ValidateUpdateData(
- ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, input api.IsolatedDeviceModelUpdateInput,
- ) (api.IsolatedDeviceModelUpdateInput, error) {
- input.VendorId = strings.ToLower(input.VendorId)
- input.DeviceId = strings.ToLower(input.DeviceId)
- deviceVendorReg := regexp.MustCompile(`^[a-f0-9]{4}$`)
- if input.VendorId != "" && !deviceVendorReg.MatchString(input.VendorId) {
- return input, httperrors.NewInputParameterError("bad vendor id %s", input.VendorId)
- }
- if input.DeviceId != "" && !deviceVendorReg.MatchString(input.DeviceId) {
- return input, httperrors.NewInputParameterError("bad vendor id %s", 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)
- }
- }
- }
- if self.Model != input.Model {
- if cnt := IsolatedDeviceModelManager.Query().Equals("model", input.Model).Count(); cnt > 0 {
- return input, httperrors.NewDuplicateResourceError("model %s has been registered", input.Model)
- }
- }
- return input, nil
- }
- func (manager *SIsolatedDeviceModelManager) ListItemFilter(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- query api.IsolatedDeviceModelListInput,
- ) (*sqlchemy.SQuery, error) {
- q, err := manager.SStandaloneAnonResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneAnonResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter")
- }
- if len(query.DevType) > 0 {
- q = q.In("dev_type", query.DevType)
- }
- if len(query.Model) > 0 {
- q = q.In("model", query.Model)
- }
- if len(query.VendorId) > 0 {
- q = q.Equals("vendor_id", query.VendorId)
- }
- 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
- }
- func (manager *SIsolatedDeviceModelManager) GetByVendorDevice(vendorId, deviceId string) (*SIsolatedDeviceModel, error) {
- devModel := new(SIsolatedDeviceModel)
- err := manager.Query().Equals("vendor_id", vendorId).Equals("device_id", deviceId).First(devModel)
- if err != nil {
- return nil, err
- }
- devModel.SetModelManager(manager, devModel)
- return devModel, nil
- }
- func (manager *SIsolatedDeviceModelManager) GetByDevModel(model string) (*SIsolatedDeviceModel, error) {
- devModel := new(SIsolatedDeviceModel)
- err := manager.Query().Equals("model", model).First(devModel)
- if err != nil {
- return nil, err
- }
- devModel.SetModelManager(manager, devModel)
- return devModel, nil
- }
- func (manager *SIsolatedDeviceModelManager) GetByDevType(devType string) (*SIsolatedDeviceModel, error) {
- devModel := new(SIsolatedDeviceModel)
- err := manager.Query().Equals("dev_type", devType).First(devModel)
- if err != nil {
- return nil, err
- }
- devModel.SetModelManager(manager, devModel)
- return devModel, nil
- }
- func (obj *SIsolatedDeviceModel) PerformSetHardwareInfo(ctx context.Context, userCred mcclient.TokenCredential, _ jsonutils.JSONObject, data *api.IsolatedDeviceModelHardwareInfo) (*api.IsolatedDeviceModelHardwareInfo, error) {
- settings := map[string]interface{}{
- api.ISOLATED_DEVICE_MODEL_METADATA_MEMORY_MB: data.MemoryMB,
- api.ISOLATED_DEVICE_MODEL_METADATA_TFLOPS: data.TFLOPS,
- api.ISOLATED_DEVICE_MODEL_METADATA_BANDWIDTH: data.Bandwidth,
- }
- for k, v := range settings {
- if err := obj.SetMetadata(ctx, k, v, userCred); err != nil {
- return nil, errors.Wrapf(err, "set %s to %v", k, v)
- }
- }
- return data, nil
- }
- func (obj *SIsolatedDeviceModel) GetDetailsHardwareInfo(ctx context.Context, userCred mcclient.TokenCredential, _ jsonutils.JSONObject) (*api.IsolatedDeviceModelHardwareInfo, error) {
- info := new(api.IsolatedDeviceModelHardwareInfo)
- // parse memory size MB
- if memStr := obj.GetMetadata(ctx, api.ISOLATED_DEVICE_MODEL_METADATA_MEMORY_MB, userCred); memStr != "" {
- memSize, err := strconv.Atoi(memStr)
- if err != nil {
- return nil, errors.Wrapf(err, "convert memory size %d to int", memSize)
- }
- info.MemoryMB = memSize
- }
- // parse bandwidth
- if bwStr := obj.GetMetadata(ctx, api.ISOLATED_DEVICE_MODEL_METADATA_BANDWIDTH, userCred); bwStr != "" {
- bw, err := strconv.ParseFloat(bwStr, 64)
- if err != nil {
- return nil, errors.Wrapf(err, "convert bandwidth %s to float", bwStr)
- }
- info.Bandwidth = bw
- }
- // parse TFLOPS
- if tflopsStr := obj.GetMetadata(ctx, api.ISOLATED_DEVICE_MODEL_METADATA_TFLOPS, userCred); tflopsStr != "" {
- tflops, err := strconv.ParseFloat(tflopsStr, 64)
- if err != nil {
- return nil, errors.Wrapf(err, "convert TFLOPS %s to float", tflopsStr)
- }
- info.TFLOPS = tflops
- }
- return info, nil
- }
|