@@ -443,6 +443,169 @@ func (h *HostRepo) CreateVirtualMachine(ctx context.Context, u *domain.User, req
443443 return res , err
444444}
445445
446+ func (h * HostRepo ) PrepareCreateVirtualMachine (ctx context.Context , u * domain.User , req * domain.CreateVMReq , id string ) (* domain.PreparedVirtualMachine , error ) {
447+ var res * domain.PreparedVirtualMachine
448+ err := entx .WithTx2 (ctx , h .db , func (tx * db.Tx ) error {
449+ dbHost , err := tx .Host .Query ().
450+ WithUser ().
451+ WithGroups ().
452+ Where (hostWithUserPredicate (u .ID )).
453+ Where (host .ID (req .HostID )).
454+ First (ctx )
455+ if err != nil {
456+ return errcode .ErrPermision .Wrap (err )
457+ }
458+
459+ if u := dbHost .Edges .User ; u != nil && u .Role == consts .UserRoleAdmin {
460+ if req .Life > 3 * 60 * 60 || req .Life <= 0 {
461+ return errcode .ErrPublicHostBeyondLimit
462+ }
463+ }
464+
465+ if len (dbHost .Edges .Groups ) > 0 && (req .Life <= 0 || req .Life > 7 * 24 * 60 * 60 ) {
466+ return errcode .ErrVmBeyondExpireTime .Wrap (fmt .Errorf ("团队宿主机不支持创建永久虚拟机" ))
467+ }
468+
469+ if req .UsePublicHost && h .cfg .PublicHost .CountLimit > 0 {
470+ cnt , err := tx .VirtualMachine .Query ().
471+ Where (virtualmachine .UserID (u .ID )).
472+ Where (virtualmachine .HasHostWith (host .HasUserWith (user .Role (consts .UserRoleAdmin )))).
473+ Where (virtualmachine .ExpiredAtGT (time .Now ())).
474+ Count (ctx )
475+ if err != nil {
476+ return errcode .ErrDatabaseOperation .Wrap (err )
477+ }
478+ if cnt >= h .cfg .PublicHost .CountLimit {
479+ return errcode .ErrPublicHostBeyondLimit .Wrap (fmt .Errorf ("public host limit reached: %d" , h .cfg .PublicHost .CountLimit ))
480+ }
481+ }
482+
483+ var m * db.Model
484+ if len (req .ModelID ) > 0 {
485+ switch req .ModelID {
486+ case "economy" :
487+ m , err = tx .Model .Query ().
488+ WithPricing ().
489+ WithUser ().
490+ Where (model .HasUserWith (user .Role (consts .UserRoleAdmin ))).
491+ Where (model .Remark (req .ModelID )).
492+ First (ctx )
493+ if err != nil {
494+ return err
495+ }
496+ default :
497+ mid , err := uuid .Parse (req .ModelID )
498+ if err != nil {
499+ return err
500+ }
501+ m , err = tx .Model .Query ().WithPricing ().WithUser ().Where (model .ID (mid )).First (ctx )
502+ if err != nil {
503+ return err
504+ }
505+ }
506+
507+ if m != nil {
508+ if p := m .Edges .Pricing ; p != nil {
509+ apikey := uuid .NewString ()
510+ mak , err := tx .ModelApiKey .Create ().
511+ SetAPIKey (apikey ).
512+ SetUserID (u .ID ).
513+ SetModelID (m .ID ).
514+ SetVirtualmachineID (id ).
515+ Save (ctx )
516+ if err != nil {
517+ return err
518+ }
519+ m .Edges .Apikeys = append (m .Edges .Apikeys , mak )
520+ }
521+ }
522+ }
523+
524+ repoURL := ""
525+ repoFilename := ""
526+ branch := ""
527+ if req .RepoReq != nil {
528+ repoURL = req .RepoReq .RepoURL
529+ repoFilename = req .RepoReq .RepoFilename
530+ branch = req .RepoReq .Branch
531+ }
532+
533+ img , err := tx .Image .Get (ctx , req .ImageID )
534+ if err != nil {
535+ return err
536+ }
537+
538+ var expiredAt * time.Time
539+ if req .Life > 0 {
540+ t := req .Now .Add (time .Duration (req .Life ) * time .Second )
541+ expiredAt = & t
542+ }
543+
544+ crt := tx .VirtualMachine .Create ().
545+ SetID (id ).
546+ SetUserID (u .ID ).
547+ SetName (req .Name ).
548+ SetHostID (dbHost .ID ).
549+ SetCores (req .Resource .CPU ).
550+ SetMemory (req .Resource .Memory ).
551+ SetRepoURL (repoURL ).
552+ SetRepoFilename (repoFilename ).
553+ SetBranch (branch ).
554+ SetCreatedAt (req .Now )
555+ if expiredAt != nil {
556+ crt .SetExpiredAt (* expiredAt )
557+ }
558+ if len (req .ModelID ) > 0 {
559+ crt .SetModelID (m .ID )
560+ }
561+ if req .GitIdentityID != uuid .Nil {
562+ crt .SetGitIdentityID (req .GitIdentityID )
563+ }
564+ if err := crt .Exec (ctx ); err != nil {
565+ return err
566+ }
567+
568+ res = & domain.PreparedVirtualMachine {
569+ VirtualMachine : & domain.VirtualMachine {
570+ ID : id ,
571+ Name : req .Name ,
572+ LifeTimeSeconds : req .Life ,
573+ Host : cvt .From (dbHost , & domain.Host {}),
574+ },
575+ Model : m ,
576+ Image : img ,
577+ }
578+ return nil
579+ })
580+ return res , err
581+ }
582+
583+ func (h * HostRepo ) CompleteCreateVirtualMachine (ctx context.Context , id string , vm * taskflow.VirtualMachine ) (* domain.VirtualMachine , error ) {
584+ var res * db.VirtualMachine
585+ err := entx .WithTx2 (ctx , h .db , func (tx * db.Tx ) error {
586+ up := tx .VirtualMachine .UpdateOneID (id ).
587+ SetEnvironmentID (vm .EnvironmentID )
588+ if vm .AccessToken != "" {
589+ up .SetAccessToken (vm .AccessToken )
590+ }
591+ if err := up .Exec (ctx ); err != nil {
592+ return err
593+ }
594+
595+ var err error
596+ res , err = tx .VirtualMachine .Query ().
597+ WithHost (func (hq * db.HostQuery ) { hq .WithUser () }).
598+ WithUser ().
599+ Where (virtualmachine .ID (id )).
600+ First (ctx )
601+ return err
602+ })
603+ if err != nil {
604+ return nil , err
605+ }
606+ return cvt .From (res , & domain.VirtualMachine {}), nil
607+ }
608+
446609// DeleteVirtualMachine implements domain.HostRepo.
447610func (h * HostRepo ) DeleteVirtualMachine (ctx context.Context , uid uuid.UUID , hostID , id string , fn func (* db.VirtualMachine ) error ) error {
448611 return entx .WithTx2 (ctx , h .db , func (tx * db.Tx ) error {
0 commit comments