| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- package models
- import (
- "context"
- "fmt"
- "net/http"
- "strings"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/httputils"
- "yunion.io/x/pkg/utils"
- commonapi "yunion.io/x/onecloud/pkg/apis"
- computeapi "yunion.io/x/onecloud/pkg/apis/compute"
- imageapi "yunion.io/x/onecloud/pkg/apis/image"
- api "yunion.io/x/onecloud/pkg/apis/llm"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/llm/options"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
- "yunion.io/x/onecloud/pkg/mcclient/modules/image"
- "yunion.io/x/onecloud/pkg/util/logclient"
- )
- func init() {
- GetVolumeManager()
- }
- var volumeManager *SVolumeManager
- func GetVolumeManager() *SVolumeManager {
- if volumeManager != nil {
- return volumeManager
- }
- volumeManager = &SVolumeManager{
- SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
- SVolume{},
- "volumes_tbl",
- "llm_volume",
- "llm_volumes",
- ),
- }
- volumeManager.SetVirtualObject(volumeManager)
- return volumeManager
- }
- type SVolumeManager struct {
- db.SVirtualResourceBaseManager
- SMountedModelsResourceManager
- }
- type SVolume struct {
- db.SVirtualResourceBase
- SMountedModelsResource
- LLMId string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"admin_optional" update:"user"`
- // 存储类型
- StorageType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"admin_optional" update:"user"`
- // 模板ID
- TemplateId string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"admin_optional" update:"user"`
- // size in MB
- SizeMB int `nullable:"false" default:"0" create:"optional" list:"user" update:"user"`
- CmpId string `width:"128" charset:"ascii" nullable:"true" list:"user"`
- Containers api.ContainerVolumeRelations `charset:"utf8" nullable:"true" list:"user" create:"optional"`
- }
- func (volume *SVolume) StartDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "VolumeDeleteTask", volume, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return err
- }
- volume.SetStatus(ctx, userCred, commonapi.STATUS_DELETING, "")
- task.ScheduleRun(nil)
- return nil
- }
- func (volume *SVolume) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- return volume.SVirtualResourceBase.Delete(ctx, userCred)
- }
- func (volume *SVolume) StartResizeTask(ctx context.Context, userCred mcclient.TokenCredential, input api.VolumeResizeTaskInput, parentTaskId string) (*taskman.STask, error) {
- volume.SetStatus(ctx, userCred, computeapi.DISK_START_RESIZE, "StartResizeTask")
- params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
- task, err := taskman.TaskManager.NewTask(ctx, "VolumeResizeTask", volume, userCred, params, parentTaskId, "", nil)
- if err != nil {
- return nil, errors.Wrap(err, "NewTask")
- }
- if err := task.ScheduleRun(nil); err != nil {
- return nil, errors.Wrap(err, "ScheduleRun")
- }
- return task, nil
- }
- func fetchImage(ctx context.Context, userCred mcclient.TokenCredential, imageId string) (*imageapi.ImageDetails, error) {
- s := auth.GetSession(ctx, userCred, options.Options.Region)
- imgObj, err := image.Images.Get(s, imageId, nil)
- if err != nil {
- return nil, errors.Wrapf(err, "Image.Get %s", imageId)
- }
- img := imageapi.ImageDetails{}
- err = imgObj.Unmarshal(&img)
- if err != nil {
- return nil, errors.Wrap(err, "Unmarshal")
- }
- return &img, nil
- }
- func (volume *SVolume) UpdateMountedModelFullNames(mountModels []string) error {
- _, err := db.Update(volume, func() error {
- volume.MountedModels = mountModels
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "update volume mounted_apps")
- }
- return nil
- }
- func (volume *SVolume) GetDisk(ctx context.Context) (*computeapi.DiskDetails, error) {
- if len(volume.CmpId) == 0 {
- return nil, errors.ErrInvalidStatus
- }
- s := auth.GetAdminSession(ctx, "")
- disk := computeapi.DiskDetails{}
- resp, err := compute.Disks.GetById(s, volume.CmpId, jsonutils.Marshal(map[string]interface{}{
- "scope": "max",
- }))
- if err != nil {
- if httputils.ErrorCode(err) == 404 {
- return nil, errors.Wrapf(errors.ErrNotFound, "GetById %s", volume.CmpId)
- }
- return nil, errors.Wrap(err, "fetch disk")
- }
- resp.Unmarshal(&disk)
- return &disk, nil
- }
- func (volume *SVolume) WaitDiskStatus(ctx context.Context, userCred mcclient.TokenCredential, targetStatus []string, timeoutSecs int) (*computeapi.DiskDetails, error) {
- expire := time.Now().Add(time.Second * time.Duration(timeoutSecs))
- for time.Now().Before(expire) {
- disk, err := volume.GetDisk(ctx)
- if err != nil {
- return nil, errors.Wrap(err, "GetDisk")
- }
- if utils.IsInArray(disk.Status, targetStatus) {
- return disk, nil
- }
- if strings.Contains(disk.Status, "fail") {
- return nil, errors.Wrap(errors.ErrInvalidStatus, disk.Status)
- }
- time.Sleep(2 * time.Second)
- }
- return nil, errors.Wrapf(httperrors.ErrTimeout, "wait disk status %s timeout", targetStatus)
- }
- func (volume *SVolume) GetLLM() *SLLM {
- if len(volume.LLMId) == 0 {
- return nil
- }
- obj, err := GetLLMManager().FetchById(volume.LLMId)
- if err != nil {
- log.Errorf("Volume %s fetch llm %s error %s", volume.Id, volume.LLMId, err)
- return nil
- }
- return obj.(*SLLM)
- }
- func (volume *SVolume) PerformReset(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.VolumePerformResetInput) (*api.LLMBatchPerformOutput, error) {
- if volume.Status != computeapi.DISK_READY {
- return nil, errors.Wrapf(httperrors.ErrInvalidStatus, "invalid status %s", volume.Status)
- }
- task, err := volume.StartResetTask(ctx, userCred, input, "")
- if err != nil {
- return nil, errors.Wrap(err, "StartResetTask")
- }
- return &api.LLMBatchPerformOutput{
- Data: []api.LLMPerformOutput{
- {
- Id: volume.Id,
- Name: volume.Name,
- RequestStatus: http.StatusOK,
- TaskId: task.Id,
- },
- },
- Task: task,
- }, nil
- }
- func (volume *SVolume) StartResetTask(ctx context.Context, userCred mcclient.TokenCredential, input api.VolumePerformResetInput, parentTaskId string) (*taskman.STask, error) {
- volume.SetStatus(ctx, userCred, api.VOLUME_STATUS_START_RESET, "StartResetTask")
- params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
- task, err := taskman.TaskManager.NewTask(ctx, "VolumeResetTask", volume, userCred, params, parentTaskId, "")
- if err != nil {
- return nil, errors.Wrap(err, "NewTask")
- }
- err = task.ScheduleRun(nil)
- if err != nil {
- return nil, errors.Wrap(err, "ScheduleRun")
- }
- return task, nil
- }
- func (volume *SVolume) DoReset(ctx context.Context, userCred mcclient.TokenCredential, templateId, backupId *string, sizeGb int) error {
- // clear desktop app list
- {
- llm := volume.GetLLM()
- if llm != nil {
- llm.purgeModelList()
- }
- }
- // clear mounts
- {
- _, err := db.Update(volume, func() error {
- volume.MountedModels = nil
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "update volume mounted_apps")
- }
- }
- // reset disk
- s := auth.GetSession(ctx, userCred, options.Options.Region)
- params := computeapi.DiskRebuildInput{}
- params.TemplateId = templateId
- params.BackupId = backupId
- emptyStr := ""
- if params.BackupId == nil {
- params.BackupId = &emptyStr
- }
- if sizeGb > 0 {
- size := fmt.Sprintf("%dG", sizeGb)
- params.Size = &size
- }
- log.Debugf("need to reset phone data disk ... %s %dG", jsonutils.Marshal(params), sizeGb)
- _, err := compute.Disks.PerformAction(s, volume.CmpId, "rebuild", jsonutils.Marshal(params))
- if err != nil {
- return errors.Wrap(err, "rebuild disk")
- }
- return nil
- }
- func (volume *SVolume) UpdateSize(ctx context.Context, userCred mcclient.TokenCredential, sizeMb int) error {
- if volume.SizeMB == sizeMb {
- return nil
- }
- oldSize := volume.SizeMB
- _, err := db.Update(volume, func() error {
- volume.SizeMB = sizeMb
- return nil
- })
- if err != nil {
- logclient.AddSimpleActionLog(volume, logclient.ACT_RESIZE, err, userCred, false)
- return errors.Wrap(err, "update volume size")
- }
- notes := struct {
- OldSizeMb int `json:"old_size_mb"`
- NewSizeMb int `json:"new_size_mb"`
- }{
- OldSizeMb: oldSize,
- NewSizeMb: sizeMb,
- }
- logclient.AddSimpleActionLog(volume, logclient.ACT_RESIZE, jsonutils.Marshal(notes), userCred, true)
- return nil
- }
|