tzwang 5 months ago
parent
commit
19b0291d2c
16 changed files with 570 additions and 177 deletions
  1. +21
    -1
      desc/core/pcm-core.api
  2. +10
    -4
      desc/pcm.api
  3. +3
    -3
      internal/handler/core/compareresourcespechandler.go
  4. +1
    -1
      internal/handler/core/editresourcespechandler.go
  5. +24
    -0
      internal/handler/core/syncresourcespechandler.go
  6. +10
    -4
      internal/handler/routes.go
  7. +129
    -106
      internal/logic/core/compareresourcespeclogic.go
  8. +46
    -5
      internal/logic/core/deleteresourcespeclogic.go
  9. +131
    -22
      internal/logic/core/editresourcespeclogic.go
  10. +135
    -0
      internal/logic/core/syncresourcespeclogic.go
  11. +2
    -0
      internal/logic/hpc/commithpctasklogic.go
  12. +1
    -1
      internal/scheduler/service/utils/jcs/middleware.go
  13. +10
    -2
      internal/scheduler/service/utils/status/hpc_task_sync.go
  14. +19
    -1
      internal/types/types.go
  15. +12
    -12
      pkg/models/tbaseresourcespecmodel_gen.go
  16. +16
    -15
      pkg/models/tresourcespecmodel_gen.go

+ 21
- 1
desc/core/pcm-core.api View File

@@ -1394,7 +1394,7 @@ type ResourceCostRecord {
} }


type ResourceSpecReq { type ResourceSpecReq {
ClusterId string `form:"clusterId"`
ClusterId string `form:"clusterId,optional"`
Type string `form:"type,optional"` Type string `form:"type,optional"`
Name string `form:"name,optional"` Name string `form:"name,optional"`
Status string `form:"status,optional"` Status string `form:"status,optional"`
@@ -1446,4 +1446,24 @@ type BaseResourceSpec {
UserId string `json:"userId" gorm:"column:user_id"` UserId string `json:"userId" gorm:"column:user_id"`
CreateTime string `json:"createTime" gorm:"column:create_time"` CreateTime string `json:"createTime" gorm:"column:create_time"`
UpdateTime string `json:"updateTime" gorm:"column:update_time"` UpdateTime string `json:"updateTime" gorm:"column:update_time"`
}

type EditResourceReq {
Id int64 `json:"id,string" gorm:"column:id;primaryKey;autoIncrement"`
status string `json:"status" gorm:"column:status"`
CostPerUnit string `json:"costPerUnit" gorm:"column:cost_per_unit"`
CostType string `json:"costType" gorm:"column:cost_type"` //计费类型(hourly, daily, monthly,perUse)
Type string `json:"type,optional" gorm:"column:type"`

// 基础资源规格
StorageValue string `json:"storageValue,optional"`
StorageUnit string `json:"storageUnit,optional"`
CpuValue string `json:"cpuValue,optional"`
CpuUnit string `json:"cpuUnit,optional"`
MemoryValue string `json:"memoryValue,optional"`
MemoryUnit string `json:"memoryUnit,optional"`
}

type SyncResourceReq {
Id string `json:"id"`
} }

+ 10
- 4
desc/pcm.api View File

@@ -179,9 +179,14 @@ service pcm {
@handler getClusterByIdHandler @handler getClusterByIdHandler
get /core/getClusterById (getClusterByIdReq) returns (getClusterByIdResp) get /core/getClusterById (getClusterByIdReq) returns (getClusterByIdResp)


@doc "获取指定集群资源规格列表"
@handler getClusterResourceSpecHandler
get /core/ai/resourceSpec/list (ResourceSpecReq) returns (PageResult)
//集群资源规格----- 开始
@doc "与Api接口对比集群资源规格"
@handler compareResourceSpecHandler
get /core/ai/resourceSpec/compare (ResourceSpecReq) returns (PageResult)

@doc "同步指定资源规格"
@handler syncResourceSpecHandler
put /core/ai/resourceSpec/sync (SyncResourceReq) returns (CommonResp)


@doc "获取指定资源规格详情" @doc "获取指定资源规格详情"
@handler detailResourceSpecHandler @handler detailResourceSpecHandler
@@ -193,11 +198,12 @@ service pcm {


@doc "编辑资源规格" @doc "编辑资源规格"
@handler editResourceSpecHandler @handler editResourceSpecHandler
put /core/ai/resourceSpec/edit (ResourceSpec) returns (CommonResp)
put /core/ai/resourceSpec/edit (EditResourceReq) returns (CommonResp)


@doc "删除资源规格" @doc "删除资源规格"
@handler deleteResourceSpecHandler @handler deleteResourceSpecHandler
delete /core/ai/resourceSpec/delete/:id (DeletePathId) returns (CommonResp) delete /core/ai/resourceSpec/delete/:id (DeletePathId) returns (CommonResp)
//集群资源规格----- 结束
} }


//hpc二级接口 //hpc二级接口


internal/handler/core/getclusterresourcespechandler.go → internal/handler/core/compareresourcespechandler.go View File

@@ -9,7 +9,7 @@ import (
"net/http" "net/http"
) )


func GetClusterResourceSpecHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
func CompareResourceSpecHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.ResourceSpecReq var req types.ResourceSpecReq
if err := httpx.Parse(r, &req); err != nil { if err := httpx.Parse(r, &req); err != nil {
@@ -17,8 +17,8 @@ func GetClusterResourceSpecHandler(svcCtx *svc.ServiceContext) http.HandlerFunc
return return
} }


l := core.NewGetClusterResourceSpecLogic(r.Context(), svcCtx)
resp, err := l.GetClusterResourceSpec(&req)
l := core.NewCompareResourceSpecLogic(r.Context(), svcCtx)
resp, err := l.CompareResourceSpec(&req)
result.HttpResult(r, w, resp, err) result.HttpResult(r, w, resp, err)
} }
} }

+ 1
- 1
internal/handler/core/editresourcespechandler.go View File

@@ -11,7 +11,7 @@ import (


func EditResourceSpecHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { func EditResourceSpecHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
var req types.ResourceSpec
var req types.EditResourceReq
if err := httpx.Parse(r, &req); err != nil { if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err) result.ParamErrorResult(r, w, err)
return return


+ 24
- 0
internal/handler/core/syncresourcespechandler.go View File

@@ -0,0 +1,24 @@
package core

import (
"github.com/zeromicro/go-zero/rest/httpx"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/logic/core"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/types"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/repository/result"
"net/http"
)

func SyncResourceSpecHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.SyncResourceReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}

l := core.NewSyncResourceSpecLogic(r.Context(), svcCtx)
resp, err := l.SyncResourceSpec(&req)
result.HttpResult(r, w, resp, err)
}
}

+ 10
- 4
internal/handler/routes.go View File

@@ -370,6 +370,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/core/ai/resourceSpec/cancelAlarm", Path: "/core/ai/resourceSpec/cancelAlarm",
Handler: core.CancelResourceSpecAlarmHandler(serverCtx), Handler: core.CancelResourceSpecAlarmHandler(serverCtx),
}, },
{
// 与Api接口对比集群资源规格
Method: http.MethodGet,
Path: "/core/ai/resourceSpec/compare",
Handler: core.CompareResourceSpecHandler(serverCtx),
},
{ {
// 删除资源规格 // 删除资源规格
Method: http.MethodDelete, Method: http.MethodDelete,
@@ -389,10 +395,10 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Handler: core.EditResourceSpecHandler(serverCtx), Handler: core.EditResourceSpecHandler(serverCtx),
}, },
{ {
// 获取指定集群资源规格列表
Method: http.MethodGet,
Path: "/core/ai/resourceSpec/list",
Handler: core.GetClusterResourceSpecHandler(serverCtx),
// 同步指定资源规格
Method: http.MethodPut,
Path: "/core/ai/resourceSpec/sync",
Handler: core.SyncResourceSpecHandler(serverCtx),
}, },
{ {
// 获取节点资产 // 获取节点资产


internal/logic/core/getclusterresourcespeclogic.go → internal/logic/core/compareresourcespeclogic.go View File

@@ -2,31 +2,31 @@ package core


import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/logic/schedule" "gitlink.org.cn/JointCloud/pcm-coordinator/internal/logic/schedule"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/types"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models" "gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/utils" "gitlink.org.cn/JointCloud/pcm-coordinator/pkg/utils"
"gorm.io/gorm"
"time" "time"


"gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/types"

"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
) )


type GetClusterResourceSpecLogic struct {
type CompareResourceSpecLogic struct {
logx.Logger logx.Logger
ctx context.Context ctx context.Context
svcCtx *svc.ServiceContext svcCtx *svc.ServiceContext
} }


const ( const (
ChangeTypeCreated = 0
ChangeTypeModified = 1
ChangeTypeDeleted = 2
ChangeTypeNormal = 0 // 资源规格正常
ChangeTypeModified = 1 // 资源规格变更
ChangeTypeDeleted = 2 // 资源被删除
) )


type APIResponse struct { type APIResponse struct {
@@ -54,22 +54,23 @@ type Metric struct {
Value float64 `json:"value"` Value float64 `json:"value"`
} }


func NewGetClusterResourceSpecLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetClusterResourceSpecLogic {
return &GetClusterResourceSpecLogic{
func NewCompareResourceSpecLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CompareResourceSpecLogic {
return &CompareResourceSpecLogic{
Logger: logx.WithContext(ctx), Logger: logx.WithContext(ctx),
ctx: ctx, ctx: ctx,
svcCtx: svcCtx, svcCtx: svcCtx,
} }
} }


func (l *GetClusterResourceSpecLogic) GetClusterResourceSpec(req *types.ResourceSpecReq) (*types.PageResult, error) {
func (l *CompareResourceSpecLogic) CompareResourceSpec(req *types.ResourceSpecReq) (resp *types.PageResult, err error) {
log.Debug().Msgf("开始比较资源规格,ClusterId: %s, PageNum: %d, PageSize: %d", req.ClusterId, req.PageNum, req.PageSize)
if req.ClusterId == "" { if req.ClusterId == "" {
return nil, errors.New("ClusterId is required")
return resp, nil
} }


// 获取集群资源数据 // 获取集群资源数据
startTime := time.Now() startTime := time.Now()
apiResources, err := l.fetchClusterResources(req.ClusterId)
apiResources, err := l.FetchClusterResources(req.ClusterId)
log.Debug().Msgf("调用获取ai训练资源接口耗时: %v", time.Since(startTime)) log.Debug().Msgf("调用获取ai训练资源接口耗时: %v", time.Since(startTime))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch cluster resources: %w", err) return nil, fmt.Errorf("failed to fetch cluster resources: %w", err)
@@ -84,24 +85,31 @@ func (l *GetClusterResourceSpecLogic) GetClusterResourceSpec(req *types.Resource
return l.queryDatabaseResults(req) return l.queryDatabaseResults(req)
} }


func (l *GetClusterResourceSpecLogic) fetchClusterResources(ClusterId string) ([]APIResponse, error) {
func (l *CompareResourceSpecLogic) FetchClusterResources(clusterId string) ([]APIResponse, error) {
queryLogic := schedule.NewQueryResourcesLogic(l.ctx, l.svcCtx) queryLogic := schedule.NewQueryResourcesLogic(l.ctx, l.svcCtx)
resources, err := queryLogic.QueryResources(&types.QueryResourcesReq{
ClusterIDs: []string{ClusterId},
})
resources, err := queryLogic.QueryResources(&types.QueryResourcesReq{})
if err != nil { if err != nil {
return nil, fmt.Errorf("query resources failed: %w", err) return nil, fmt.Errorf("query resources failed: %w", err)
} }


var apiResponses []APIResponse var apiResponses []APIResponse
if err := l.decodeAPIResponse(resources.Data, &apiResponses); err != nil {
if err := decodeAPIResponse(resources.Data, &apiResponses); err != nil {
return nil, fmt.Errorf("decode response failed: %w", err) return nil, fmt.Errorf("decode response failed: %w", err)
} }

return apiResponses, nil
// 过滤出指定集群的资源
var filteredResponses []APIResponse
for _, response := range apiResponses {
if response.ClusterId == clusterId && response.Resources != nil {
filteredResponses = append(filteredResponses, response)
}
}
if len(filteredResponses) == 0 {
return nil, fmt.Errorf("no resources found for cluster ID: %s", clusterId)
}
return filteredResponses, nil
} }


func (l *GetClusterResourceSpecLogic) decodeAPIResponse(input interface{}, output *[]APIResponse) error {
func decodeAPIResponse(input interface{}, output *[]APIResponse) error {
config := &mapstructure.DecoderConfig{ config := &mapstructure.DecoderConfig{
Result: output, Result: output,
TagName: "json", TagName: "json",
@@ -124,7 +132,7 @@ func (l *GetClusterResourceSpecLogic) decodeAPIResponse(input interface{}, outpu
return nil return nil
} }


func (l *GetClusterResourceSpecLogic) syncResourcesToDB(apiResponses []APIResponse) error {
func (l *CompareResourceSpecLogic) syncResourcesToDB(apiResponses []APIResponse) error {
for _, response := range apiResponses { for _, response := range apiResponses {
// 转换API响应到数据库模型 // 转换API响应到数据库模型
dbSpecs, apiSpecs, err := l.processAPIResponse(response) dbSpecs, apiSpecs, err := l.processAPIResponse(response)
@@ -133,14 +141,14 @@ func (l *GetClusterResourceSpecLogic) syncResourcesToDB(apiResponses []APIRespon
} }


// 处理资源变更 // 处理资源变更
if err := l.handleResourceChanges(utils.StringToInt64(response.ClusterId), dbSpecs, apiSpecs); err != nil {
if err := l.handleResourceChanges(dbSpecs, apiSpecs); err != nil {
return fmt.Errorf("failed to handle resource changes: %w", err) return fmt.Errorf("failed to handle resource changes: %w", err)
} }
} }
return nil return nil
} }


func (l *GetClusterResourceSpecLogic) processAPIResponse(response APIResponse) ([]models.TResourceSpec, []models.TResourceSpec, error) {
func (l *CompareResourceSpecLogic) processAPIResponse(response APIResponse) ([]models.TResourceSpec, []models.TResourceSpec, error) {
ClusterId := utils.StringToInt64(response.ClusterId) ClusterId := utils.StringToInt64(response.ClusterId)
var dbSpecs []models.TResourceSpec var dbSpecs []models.TResourceSpec
if err := l.svcCtx.DbEngin.Model(models.TResourceSpec{}).Preload("BaseResourceSpecs"). if err := l.svcCtx.DbEngin.Model(models.TResourceSpec{}).Preload("BaseResourceSpecs").
@@ -151,6 +159,10 @@ func (l *GetClusterResourceSpecLogic) processAPIResponse(response APIResponse) (


var apiSpecs []models.TResourceSpec var apiSpecs []models.TResourceSpec
for _, res := range response.Resources { for _, res := range response.Resources {
// 检查资源类型和名称是否存在
if res.Resource.Name == "" || res.Resource.Type == "" {
continue
}
spec := l.convertToResourceSpec(ClusterId, res) spec := l.convertToResourceSpec(ClusterId, res)
apiSpecs = append(apiSpecs, spec) apiSpecs = append(apiSpecs, spec)
} }
@@ -158,11 +170,10 @@ func (l *GetClusterResourceSpecLogic) processAPIResponse(response APIResponse) (
return dbSpecs, apiSpecs, nil return dbSpecs, apiSpecs, nil
} }


func (l *GetClusterResourceSpecLogic) handleResourceChanges(ClusterId int64, dbSpecs, apiSpecs []models.TResourceSpec) error {
// 创建资源映射
func (l *CompareResourceSpecLogic) handleResourceChanges(dbSpecs, apiSpecs []models.TResourceSpec) error {
dbMap := make(map[string]models.TResourceSpec) dbMap := make(map[string]models.TResourceSpec)
for _, spec := range dbSpecs { for _, spec := range dbSpecs {
key := resourceKey(spec.Type, spec.Name)
key := spec.SourceKey
dbMap[key] = spec dbMap[key] = spec
} }


@@ -172,21 +183,93 @@ func (l *GetClusterResourceSpecLogic) handleResourceChanges(ClusterId int64, dbS
apiMap[key] = spec apiMap[key] = spec
} }


// 处理新增或更新的资源
var createSpecs []*models.TResourceSpec
var modifiedIDs []int64
var normalIDs []int64

// 第一阶段:收集需要处理的操作
for key, apiSpec := range apiMap { for key, apiSpec := range apiMap {
dbSpec, exists := dbMap[key] dbSpec, exists := dbMap[key]
if !exists { if !exists {
if err := l.createNewResource(&apiSpec); err != nil {
return err
}
// 创建资源副本避免指针重复
newSpec := apiSpec
// 初始化时间字段
newSpec.CreateTime = time.Now()
newSpec.UpdateTime = time.Now()
createSpecs = append(createSpecs, &newSpec)
continue continue
} }


// 检查资源规格变更
if l.isSpecChanged(dbSpec, apiSpec) { if l.isSpecChanged(dbSpec, apiSpec) {
if err := l.updateResource(&dbSpec, apiSpec); err != nil {
return err
modifiedIDs = append(modifiedIDs, dbSpec.Id)
} else {
normalIDs = append(normalIDs, dbSpec.Id)
}
}

// 第二阶段:批量处理数据库操作
// 批量创建新资源及关联资源
if len(createSpecs) > 0 {
tx := l.svcCtx.DbEngin.Begin()
if tx.Error != nil {
return fmt.Errorf("failed to start transaction: %w", tx.Error)
}

// 批量插入主资源
if err := tx.CreateInBatches(createSpecs, 100).Error; err != nil {
tx.Rollback()
return fmt.Errorf("failed to batch create resources: %w", err)
}

// 准备关联资源数据
var baseResources []models.TBaseResourceSpec
for _, spec := range createSpecs {
for i := range spec.BaseResourceSpecs {
br := &spec.BaseResourceSpecs[i]
br.ResourceSpecId = spec.Id
br.CreateTime = time.Now()
br.UpdateTime = time.Now()
baseResources = append(baseResources, *br)
}
}

// 批量插入关联资源
if len(baseResources) > 0 {
if err := tx.CreateInBatches(baseResources, 100).Error; err != nil {
tx.Rollback()
return fmt.Errorf("failed to batch create base resources: %w", err)
} }
} }

if err := tx.Commit().Error; err != nil {
return fmt.Errorf("transaction commit failed: %w", err)
}
}

// 批量更新变更资源
now := time.Now()
if len(modifiedIDs) > 0 {
if err := l.svcCtx.DbEngin.Model(&models.TResourceSpec{}).
Where("id IN ?", modifiedIDs).
Updates(map[string]interface{}{
"change_type": ChangeTypeModified,
"update_time": now,
}).Error; err != nil {
return fmt.Errorf("batch update modified failed: %w", err)
}
}

// 批量更新正常资源
if len(normalIDs) > 0 {
if err := l.svcCtx.DbEngin.Model(&models.TResourceSpec{}).
Where("id IN ?", normalIDs).
Updates(map[string]interface{}{
"change_type": ChangeTypeNormal,
"update_time": now,
}).Error; err != nil {
return fmt.Errorf("batch update normal failed: %w", err)
}
} }


// 处理删除的资源 // 处理删除的资源
@@ -205,101 +288,40 @@ func resourceKey(resType, name string) string {
return fmt.Sprintf("%s::%s", resType, name) return fmt.Sprintf("%s::%s", resType, name)
} }


func (l *GetClusterResourceSpecLogic) createNewResource(spec *models.TResourceSpec) error {
func (l *CompareResourceSpecLogic) createNewResource(spec *models.TResourceSpec) error {
return l.svcCtx.DbEngin.Transaction(func(tx *gorm.DB) error { return l.svcCtx.DbEngin.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(spec).Error; err != nil { if err := tx.Create(spec).Error; err != nil {
return fmt.Errorf("failed to create resource: %w", err) return fmt.Errorf("failed to create resource: %w", err)
} }


for i := range spec.BaseResourceSpecs {
spec.BaseResourceSpecs[i].ResourceSpecId = spec.Id
spec.BaseResourceSpecs[i].Id = 0
}

if len(spec.BaseResourceSpecs) > 0 {
if err := tx.CreateInBatches(spec.BaseResourceSpecs, 100).Error; err != nil {
return fmt.Errorf("failed to create base resources: %w", err)
}
}

return nil return nil
}) })
} }


func (l *GetClusterResourceSpecLogic) updateResource(existing *models.TResourceSpec, newSpec models.TResourceSpec) error {
// 标识资源规格变更
func (l *CompareResourceSpecLogic) updateResource(existing *models.TResourceSpec, newSpec models.TResourceSpec, changeType int) error {
return l.svcCtx.DbEngin.Transaction(func(tx *gorm.DB) error { return l.svcCtx.DbEngin.Transaction(func(tx *gorm.DB) error {
updates := map[string]interface{}{ updates := map[string]interface{}{
"total_count": newSpec.TotalCount,
"available_count": newSpec.AvailableCount,
"change_type": ChangeTypeModified,
"update_time": time.Now(),
"change_type": changeType,
"update_time": time.Now(),
} }


if err := tx.Model(existing).Updates(updates).Error; err != nil { if err := tx.Model(existing).Updates(updates).Error; err != nil {
return fmt.Errorf("failed to update resource: %w", err) return fmt.Errorf("failed to update resource: %w", err)
} }


return l.syncBaseResources(tx, existing.Id, newSpec.BaseResourceSpecs)
return nil
}) })
} }


func (l *GetClusterResourceSpecLogic) syncBaseResources(tx *gorm.DB, specID int64, newResources []models.TBaseResourceSpec) error {
// 处理基础资源更新
var existingResources []models.TBaseResourceSpec
if err := tx.Where("resource_spec_id = ?", specID).Find(&existingResources).Error; err != nil {
return fmt.Errorf("failed to query base resources: %w", err)
}

existingMap := make(map[string]models.TBaseResourceSpec)
for _, r := range existingResources {
key := resourceKey(r.Type, r.Name)
existingMap[key] = r
}

// 处理更新和新增
for i, newRes := range newResources {
newRes.ResourceSpecId = specID
key := resourceKey(newRes.Type, newRes.Name)

if existing, exists := existingMap[key]; exists {
newRes.Id = existing.Id
newRes.CreateTime = existing.CreateTime
if err := tx.Save(&newRes).Error; err != nil {
return fmt.Errorf("failed to update base resource: %w", err)
}
} else {
if err := tx.Create(&newRes).Error; err != nil {
return fmt.Errorf("failed to create base resource: %w", err)
}
}
newResources[i] = newRes
}

// 处理删除
currentIDs := make(map[int64]struct{})
for _, r := range newResources {
currentIDs[r.Id] = struct{}{}
}

for _, existing := range existingResources {
if _, exists := currentIDs[existing.Id]; !exists {
if err := tx.Delete(&existing).Error; err != nil {
return fmt.Errorf("failed to delete base resource: %w", err)
}
}
}

return nil
}

func (l *GetClusterResourceSpecLogic) markResourceDeleted(id int64) error {
func (l *CompareResourceSpecLogic) markResourceDeleted(id int64) error {
return l.svcCtx.DbEngin.Model(&models.TResourceSpec{}). return l.svcCtx.DbEngin.Model(&models.TResourceSpec{}).
Where("id = ?", id). Where("id = ?", id).
Update("change_type", ChangeTypeDeleted). Update("change_type", ChangeTypeDeleted).
Error Error
} }


func (l *GetClusterResourceSpecLogic) isSpecChanged(old, new models.TResourceSpec) bool {
func (l *CompareResourceSpecLogic) isSpecChanged(old, new models.TResourceSpec) bool {
if old.TotalCount != new.TotalCount || if old.TotalCount != new.TotalCount ||
old.AvailableCount != new.AvailableCount || old.AvailableCount != new.AvailableCount ||
old.Region != new.Region { old.Region != new.Region {
@@ -326,8 +348,9 @@ func (l *GetClusterResourceSpecLogic) isSpecChanged(old, new models.TResourceSpe
return len(oldBaseMap) > 0 return len(oldBaseMap) > 0
} }


func (l *GetClusterResourceSpecLogic) convertToResourceSpec(ClusterId int64, res Resource) models.TResourceSpec {
func (l *CompareResourceSpecLogic) convertToResourceSpec(ClusterId int64, res Resource) models.TResourceSpec {
spec := models.TResourceSpec{ spec := models.TResourceSpec{
SourceKey: resourceKey(res.Resource.Type, res.Resource.Name),
Type: res.Resource.Type, Type: res.Resource.Type,
Name: res.Resource.Name, Name: res.Resource.Name,
TotalCount: int64(res.Resource.Total.Value), TotalCount: int64(res.Resource.Total.Value),
@@ -335,7 +358,7 @@ func (l *GetClusterResourceSpecLogic) convertToResourceSpec(ClusterId int64, res
ClusterId: ClusterId, ClusterId: ClusterId,
CreateTime: time.Now(), CreateTime: time.Now(),
UpdateTime: time.Now(), UpdateTime: time.Now(),
ChangeType: ChangeTypeCreated,
ChangeType: ChangeTypeNormal,
} }


for _, br := range res.BaseResources { for _, br := range res.BaseResources {
@@ -354,7 +377,7 @@ func (l *GetClusterResourceSpecLogic) convertToResourceSpec(ClusterId int64, res
return spec return spec
} }


func (l *GetClusterResourceSpecLogic) queryDatabaseResults(req *types.ResourceSpecReq) (*types.PageResult, error) {
func (l *CompareResourceSpecLogic) queryDatabaseResults(req *types.ResourceSpecReq) (*types.PageResult, error) {
result := &types.PageResult{ result := &types.PageResult{
PageNum: req.PageNum, PageNum: req.PageNum,
PageSize: req.PageSize, PageSize: req.PageSize,
@@ -376,7 +399,7 @@ func (l *GetClusterResourceSpecLogic) queryDatabaseResults(req *types.ResourceSp
return result, nil return result, nil
} }


func (l *GetClusterResourceSpecLogic) buildBaseQuery(req *types.ResourceSpecReq) *gorm.DB {
func (l *CompareResourceSpecLogic) buildBaseQuery(req *types.ResourceSpecReq) *gorm.DB {
query := l.svcCtx.DbEngin.Model(&models.TResourceSpec{}). query := l.svcCtx.DbEngin.Model(&models.TResourceSpec{}).
Where("cluster_id = ?", utils.StringToInt64(req.ClusterId)). Where("cluster_id = ?", utils.StringToInt64(req.ClusterId)).
Where("deleted_at IS NULL") Where("deleted_at IS NULL")

+ 46
- 5
internal/logic/core/deleteresourcespeclogic.go View File

@@ -2,7 +2,10 @@ package core


import ( import (
"context" "context"
"github.com/pkg/errors"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models" "gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models"
"gorm.io/gorm"
"time"


"gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc" "gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/types" "gitlink.org.cn/JointCloud/pcm-coordinator/internal/types"
@@ -25,11 +28,49 @@ func NewDeleteResourceSpecLogic(ctx context.Context, svcCtx *svc.ServiceContext)
} }


func (l *DeleteResourceSpecLogic) DeleteResourceSpec(req *types.DeletePathId) (resp *types.CommonResp, err error) { func (l *DeleteResourceSpecLogic) DeleteResourceSpec(req *types.DeletePathId) (resp *types.CommonResp, err error) {
db := l.svcCtx.DbEngin.Model(&models.TResourceSpec{}).Table("t_resource_spec")
err = db.Delete(&models.TResourceSpec{}, req.Id).Error
if err != nil {
return nil, err
// 初始化事务
tx := l.svcCtx.DbEngin.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
panic(r)
}
}()

// 1. 检查主资源规格是否存在
var mainSpec models.TResourceSpec
if err := tx.Where("id = ? AND deleted_at IS NULL", req.Id).
First(&mainSpec).
Error; err != nil {
tx.Rollback()
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.Errorf("资源规格不存在 (ID: %s)", req.Id)
}
return nil, errors.Wrapf(err, "查询资源规格失败 (ID: %s)", req.Id)
}

// 2. 删除主资源规格(软删除)
if err := tx.Model(&models.TResourceSpec{}).
Where("id = ?", req.Id).
Update("deleted_at", time.Now()).
Error; err != nil {
tx.Rollback()
return nil, errors.Wrapf(err, "删除主资源规格失败 (ID: %s)", req.Id)
}

// 3. 删除关联的基础资源规格(软删除)
if err := tx.Model(&models.TBaseResourceSpec{}).
Where("resource_spec_id = ?", req.Id).
Update("deleted_at", time.Now()).
Error; err != nil {
tx.Rollback()
return nil, errors.Wrapf(err, "删除基础资源规格失败 (ID: %s)", req.Id)
}

// 提交事务
if err := tx.Commit().Error; err != nil {
return nil, errors.Wrap(err, "提交事务失败")
} }


return
return resp, nil
} }

+ 131
- 22
internal/logic/core/editresourcespeclogic.go View File

@@ -3,12 +3,12 @@ package core
import ( import (
"context" "context"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models"

"github.com/zeromicro/go-zero/core/logx"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc" "gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/types" "gitlink.org.cn/JointCloud/pcm-coordinator/internal/types"

"github.com/zeromicro/go-zero/core/logx"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/utils"
"gorm.io/gorm"
) )


type EditResourceSpecLogic struct { type EditResourceSpecLogic struct {
@@ -24,31 +24,140 @@ func NewEditResourceSpecLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
svcCtx: svcCtx, svcCtx: svcCtx,
} }
} }
func (l *EditResourceSpecLogic) EditResourceSpec(req *types.EditResourceReq) (resp *types.CommonResp, err error) {
// 初始化事务
tx := l.svcCtx.DbEngin.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
panic(r)
} else if err != nil {
tx.Rollback()
}
}()


func (l *EditResourceSpecLogic) EditResourceSpec(req *types.ResourceSpec) (resp *types.CommonResp, err error) {
//检查是否存在
var count int64
db := l.svcCtx.DbEngin.Model(&types.ResourceSpec{}).Table("t_resource_spec")
err = db.Where("id = ? and deleted_at is null", req.Id).Count(&count).Error
if err != nil {
// 1. 验证资源规格存在
var existing models.TResourceSpec
if err = tx.Model(&models.TResourceSpec{}).
Where("id = ? AND deleted_at IS NULL", req.Id).
First(&existing).
Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.Errorf("资源规格不存在 (ID: %d)", req.Id)
}
return nil, errors.Wrapf(err, "查询资源规格失败 (ID: %d)", req.Id)
}

// 2. 参数校验
if err = validateRequestParams(req); err != nil {
return nil, err return nil, err
} }
if count == 0 {
return nil, errors.New("资源规格不存在")

// 3. 转换参数
statusInt := utils.StringToInt64(req.Status)
costPerUnit := utils.StringToFloat64(req.CostPerUnit)

// 4. 更新主资源规格
if err = updateMainResourceSpec(tx, req.Id, statusInt, req.CostType, costPerUnit); err != nil {
return nil, err
} }
resp = &types.CommonResp{}
db = l.svcCtx.DbEngin.Model(&types.ResourceSpec{}).Table("t_resource_spec")
err = db.Where("id = ?", req.Id).Save(req).Error
if err != nil {

// 5. 更新子资源规格
if err = updateSubResources(tx, req); err != nil {
return nil, err return nil, err
} }


baseDb := l.svcCtx.DbEngin.Model(models.TBaseResourceSpec{}).Table("t_base_resource_spec")
for _, spec := range req.BaseResourceSpecs {
err = baseDb.Where("id = ?", spec.Id).Updates(&spec).Error
if err != nil {
return nil, err
}
// 提交事务
if err = tx.Commit().Error; err != nil {
return nil, errors.Wrap(err, "提交事务失败")
} }

// 返回成功响应
return resp, nil return resp, nil
} }

// validateRequestParams 验证请求参数合法性
func validateRequestParams(req *types.EditResourceReq) error {
// 状态校验
if req.Status != "0" && req.Status != "1" {
return errors.Errorf("资源规格状态不合法 (ID: %d)", req.Id)
}

// 计费类型校验
validCostTypes := map[string]struct{}{
"hourly": {},
"daily": {},
"monthly": {},
"perUse": {},
}
if _, ok := validCostTypes[req.CostType]; !ok {
return errors.Errorf("资源规格计费类型不合法 (ID: %d)", req.Id)
}

return nil
}

// updateMainResourceSpec 更新主资源规格
func updateMainResourceSpec(tx *gorm.DB, id int64, status int64, costType string, costPerUnit float64) error {
return tx.Model(&models.TResourceSpec{}).
Where("id = ?", id).
Updates(map[string]interface{}{
"status": status,
"cost_type": costType,
"cost_per_unit": costPerUnit,
}).
Error
}

// updateSubResources 更新子资源规格
func updateSubResources(tx *gorm.DB, req *types.EditResourceReq) error {
// 定义更新操作集合
updateOperations := []struct {
Value string
Unit string
SpecType string
SpecName string
}{
{req.CpuValue, req.CpuUnit, "CPU", ""},
{req.MemoryValue, req.MemoryUnit, "MEMORY", "RAM"},
{req.StorageValue, req.StorageUnit, "STORAGE", ""},
}

// 批量执行更新操作
for _, op := range updateOperations {
if op.Value == "" && op.Unit == "" {
continue
}

if err := updateBaseResourceSpec(tx, req.Id, op.SpecType, op.SpecName, op.Value, op.Unit); err != nil {
return errors.Wrapf(err, "更新%s规格失败 (ID: %d)", op.SpecType, req.Id)
}
}
return nil
}

// updateBaseResourceSpec 通用基础资源规格更新函数
func updateBaseResourceSpec(tx *gorm.DB, specID int64, specType string, specName string, value, unit string) error {
updates := make(map[string]interface{})
if value != "" {
updates["total_value"] = value
}
if unit != "" {
updates["total_unit"] = unit
}
if len(updates) == 0 {
return nil
}

query := tx.Model(&models.TBaseResourceSpec{}).
Where("resource_spec_id = ? AND type = ?", specID, specType)

if specName != "" {
query = query.Where("name = ?", specName)
}

if err := query.Updates(updates).Error; err != nil {
return errors.Wrapf(err, "更新%s规格失败", specType)
}
return nil
}

+ 135
- 0
internal/logic/core/syncresourcespeclogic.go View File

@@ -0,0 +1,135 @@
package core

import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models"
"gorm.io/gorm"
"strconv"
"time"

"gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc"
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/types"

"github.com/zeromicro/go-zero/core/logx"
)

type SyncResourceSpecLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}

func NewSyncResourceSpecLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SyncResourceSpecLogic {
return &SyncResourceSpecLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}

func (l *SyncResourceSpecLogic) SyncResourceSpec(req *types.SyncResourceReq) (resp *types.CommonResp, err error) {
var mainSpec models.TResourceSpec
if err := l.svcCtx.DbEngin.Where("id = ? AND deleted_at IS NULL", req.Id).
First(&mainSpec).
Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.Errorf("资源规格不存在 (ID: %s)", req.Id)
}
return nil, errors.Wrapf(err, "查询资源规格失败 (ID: %s)", req.Id)
}
// 获取集群资源数据
startTime := time.Now()
compareLogic := NewCompareResourceSpecLogic(l.ctx, l.svcCtx)
apiResources, err := compareLogic.FetchClusterResources(strconv.FormatInt(mainSpec.ClusterId, 10))
log.Debug().Msgf("调用获取ai训练资源接口耗时: %v", time.Since(startTime))
if err != nil {
return nil, fmt.Errorf("failed to fetch cluster resources: %w", err)
}
for _, response := range apiResources {
// 转换API响应到数据库模型
_, apiSpecs, err := compareLogic.processAPIResponse(response)
if err != nil {
return nil, err
}
// 同步资源到数据库
for _, spec := range apiSpecs {
if spec.SourceKey == mainSpec.SourceKey {
err := l.updateResource(&mainSpec, spec)
if err != nil {
return nil, err
}
}
}
}
return nil, nil
}

func (l *SyncResourceSpecLogic) updateResource(existing *models.TResourceSpec, newSpec models.TResourceSpec) error {
return l.svcCtx.DbEngin.Transaction(func(tx *gorm.DB) error {
updates := map[string]interface{}{
"type": newSpec.Type,
"total_count": newSpec.TotalCount,
"available_count": newSpec.AvailableCount,
"change_type": ChangeTypeNormal,
"update_time": time.Now(),
}

if err := tx.Model(existing).Updates(updates).Error; err != nil {
return fmt.Errorf("failed to update resource: %w", err)
}

return l.syncBaseResources(tx, existing.Id, newSpec.BaseResourceSpecs)
})
}

func (l *SyncResourceSpecLogic) syncBaseResources(tx *gorm.DB, specID int64, newResources []models.TBaseResourceSpec) error {
// 处理基础资源更新
var existingResources []models.TBaseResourceSpec
if err := tx.Where("resource_spec_id = ?", specID).Find(&existingResources).Error; err != nil {
return fmt.Errorf("failed to query base resources: %w", err)
}

existingMap := make(map[string]models.TBaseResourceSpec)
for _, r := range existingResources {
key := resourceKey(r.Type, r.Name)
existingMap[key] = r
}

// 处理更新和新增
for i, newRes := range newResources {
newRes.ResourceSpecId = specID
key := resourceKey(newRes.Type, newRes.Name)

if existing, exists := existingMap[key]; exists {
newRes.Id = existing.Id
newRes.CreateTime = existing.CreateTime
if err := tx.Save(&newRes).Error; err != nil {
return fmt.Errorf("failed to update base resource: %w", err)
}
} else {
if err := tx.Create(&newRes).Error; err != nil {
return fmt.Errorf("failed to create base resource: %w", err)
}
}
newResources[i] = newRes
}

// 处理删除
currentIDs := make(map[int64]struct{})
for _, r := range newResources {
currentIDs[r.Id] = struct{}{}
}

for _, existing := range existingResources {
if _, exists := currentIDs[existing.Id]; !exists {
if err := tx.Delete(&existing).Error; err != nil {
return fmt.Errorf("failed to delete base resource: %w", err)
}
}
}

return nil
}

+ 2
- 0
internal/logic/hpc/commithpctasklogic.go View File

@@ -52,6 +52,7 @@ func (l *CommitHpcTaskLogic) CommitHpcTask(req *types.CommitHpcTaskReq) (resp *t
// 构建主任务结构体 // 构建主任务结构体
userId, _ := strconv.ParseInt(req.Parameters["UserId"], 10, 64) userId, _ := strconv.ParseInt(req.Parameters["UserId"], 10, 64)
taskModel := models.Task{ taskModel := models.Task{
Id: utils.GenSnowflakeID(),
Name: req.Name, Name: req.Name,
Description: req.Description, Description: req.Description,
CommitTime: time.Now(), CommitTime: time.Now(),
@@ -76,6 +77,7 @@ func (l *CommitHpcTaskLogic) CommitHpcTask(req *types.CommitHpcTaskReq) (resp *t
cardCount, _ := strconv.ParseInt(req.Parameters["cardCount"], 10, 64) cardCount, _ := strconv.ParseInt(req.Parameters["cardCount"], 10, 64)
timelimit, _ := strconv.ParseInt(req.Parameters["timeLimit"], 10, 64) timelimit, _ := strconv.ParseInt(req.Parameters["timeLimit"], 10, 64)
hpcInfo := models.TaskHpc{ hpcInfo := models.TaskHpc{
Id: utils.GenSnowflakeID(),
TaskId: taskModel.Id, TaskId: taskModel.Id,
AdapterId: clusterInfo.AdapterId, AdapterId: clusterInfo.AdapterId,
AdapterName: adapterInfo.Name, AdapterName: adapterInfo.Name,


+ 1
- 1
internal/scheduler/service/utils/jcs/middleware.go View File

@@ -51,7 +51,7 @@ func StatusReport(url string, report interface{}) error {
Post(url) Post(url)


bodyStr, _ := jsoniter.MarshalToString(report) bodyStr, _ := jsoniter.MarshalToString(report)
log.Debug().Msgf("任务状态上报到中间件请求参数:[%v], 返回值: [%v]", bodyStr, string(rp.Body()))
log.Debug().Msgf("上报任务状态到中间件,请求url:%s, 请求参数:%s, 响应结果:%s", url, bodyStr, string(rp.Body()))


if err != nil { if err != nil {
logx.Errorf("############ Report Status Message Error %s", err.Error()) logx.Errorf("############ Report Status Message Error %s", err.Error())


+ 10
- 2
internal/scheduler/service/utils/status/hpc_task_sync.go View File

@@ -41,8 +41,16 @@ func UpdateHpcTaskStatus(svc *svc.ServiceContext) {
svc.Scheduler.HpcService.TaskSyncLock.Lock() svc.Scheduler.HpcService.TaskSyncLock.Lock()
defer svc.Scheduler.HpcService.TaskSyncLock.Unlock() defer svc.Scheduler.HpcService.TaskSyncLock.Unlock()
taskList := make([]*models.TaskHpc, 0) taskList := make([]*models.TaskHpc, 0)
//TODO 暂时忽略任务状态
sqlStr := `select * from task_hpc where job_id!='' order by created_time desc limit 10`
sqlStr := `SELECT *
FROM task_hpc
WHERE
job_id != ''
AND (
status NOT IN ('Failed', 'Completed', 'Cancelled')
OR start_time < created_time
)
ORDER BY created_time DESC
LIMIT 10`
db := svc.DbEngin.Raw(sqlStr).Scan(&taskList) db := svc.DbEngin.Raw(sqlStr).Scan(&taskList)
if db.Error != nil { if db.Error != nil {
logx.Errorf(db.Error.Error()) logx.Errorf(db.Error.Error())


+ 19
- 1
internal/types/types.go View File

@@ -2125,6 +2125,20 @@ type Driver_info struct {
Ipmi_username string `json:"ipmi_username" copier:"ipmi_username"` Ipmi_username string `json:"ipmi_username" copier:"ipmi_username"`
} }


type EditResourceReq struct {
Id int64 `json:"id,string" gorm:"column:id;primaryKey;autoIncrement"`
Status string `json:"status" gorm:"column:status"`
CostPerUnit string `json:"costPerUnit" gorm:"column:cost_per_unit"`
CostType string `json:"costType" gorm:"column:cost_type"` //计费类型(hourly, daily, monthly,perUse)
Type string `json:"type,optional" gorm:"column:type"`
StorageValue string `json:"storageValue,optional"`
StorageUnit string `json:"storageUnit,optional"`
CpuValue string `json:"cpuValue,optional"`
CpuUnit string `json:"cpuUnit,optional"`
MemoryValue string `json:"memoryValue,optional"`
MemoryUnit string `json:"memoryUnit,optional"`
}

type EndpointsReq struct { type EndpointsReq struct {
AllowedAccessIps []string `json:"allowedAccessIps" copier:"AllowedAccessIps"` AllowedAccessIps []string `json:"allowedAccessIps" copier:"AllowedAccessIps"`
DevService string `json:"devService" copier:"DevService"` DevService string `json:"devService" copier:"DevService"`
@@ -4591,7 +4605,7 @@ type ResourceSpec struct {
} }


type ResourceSpecReq struct { type ResourceSpecReq struct {
ClusterId string `form:"clusterId"`
ClusterId string `form:"clusterId,optional"`
Type string `form:"type,optional"` Type string `form:"type,optional"`
Name string `form:"name,optional"` Name string `form:"name,optional"`
Status string `form:"status,optional"` Status string `form:"status,optional"`
@@ -5498,6 +5512,10 @@ type SyncClusterAlertReq struct {
AlertRecordsMap map[string]interface{} `json:"alertRecordsMap"` AlertRecordsMap map[string]interface{} `json:"alertRecordsMap"`
} }


type SyncResourceReq struct {
Id string `json:"id"`
}

type Tags struct { type Tags struct {
} }




+ 12
- 12
pkg/models/tbaseresourcespecmodel_gen.go View File

@@ -38,18 +38,18 @@ type (
} }


TBaseResourceSpec struct { TBaseResourceSpec struct {
Id int64 `db:"id" json:"id,omitempty"` // 主键id
ResourceSpecId int64 `db:"resource_spec_id" json:"resourceSpecId,omitempty"` // 关联资源规格ID
Type string `db:"type" json:"type,omitempty"` // 类型名称
Name string `db:"name" json:"name,omitempty"` // 名称(如显存类型)
TotalValue float64 `db:"total_value" json:"totalValue,omitempty"` // 总量值
TotalUnit string `db:"total_unit" json:"totalUnit,omitempty"` // 总量值单位(GB/core等)
AvailableValue float64 `db:"available_value" json:"availableValue,omitempty"` // 可用值
AvailableUnit string `db:"available_unit" json:"availableUnit,omitempty"` // 可用值单位(GB/core等)
UserId int64 `db:"user_id" json:"userId"` // 用户ID
CreateTime time.Time `db:"create_time" json:"createTime"` // 创建时间
UpdateTime time.Time `db:"update_time" json:"updateTime"` // 更新时间
DeletedAt gorm.DeletedAt `db:"deleted_at" json:"-"` // 删除时间
Id int64 `db:"id" json:"id"` // 主键id
ResourceSpecId int64 `db:"resource_spec_id" json:"resourceSpecId"` // 关联资源规格ID
Type string `db:"type" json:"type"` // 类型名称
Name string `db:"name" json:"name"` // 名称(如显存类型)
TotalValue float64 `db:"total_value" json:"totalValue"` // 总量值
TotalUnit string `db:"total_unit" json:"totalUnit"` // 总量值单位(GB/core等)
AvailableValue float64 `db:"available_value" json:"availableValue"` // 可用值
AvailableUnit string `db:"available_unit" json:"availableUnit"` // 可用值单位(GB/core等)
UserId int64 `db:"user_id" json:"userId"` // 用户ID
CreateTime time.Time `db:"create_time" json:"createTime"` // 创建时间
UpdateTime time.Time `db:"update_time" json:"updateTime"` // 更新时间
DeletedAt gorm.DeletedAt `db:"deleted_at" json:"-"` // 删除时间
} }
) )




+ 16
- 15
pkg/models/tresourcespecmodel_gen.go View File

@@ -38,21 +38,22 @@ type (
} }


TResourceSpec struct { TResourceSpec struct {
Id int64 `db:"id" json:"id,omitempty"` // 主键id
Type string `db:"type" json:"type,omitempty"` // 类型名称
Name string `db:"name" json:"name,omitempty"` // 规格名称
TotalCount int64 `db:"total_count" json:"totalCount,omitempty"` // 资源总量
AvailableCount int64 `db:"available_count" json:"availableCount,omitempty"` // 可用数量
ChangeType int64 `db:"change_type" json:"changeType,omitempty"` // 变更类型(0: 正常,1:变更,2:删除)
Status int64 `db:"status" json:"status,omitempty"` // 状态(0:未上架,1:已上架)
Region string `db:"region" json:"region,omitempty"` // 所属区域(可扩展多区域)
ClusterId int64 `db:"cluster_id" json:"clusterId,string,omitempty"` // 集群ID
CostPerUnit float64 `db:"cost_per_unit" json:"costPerUnit,omitempty"` // 单位时间积分消耗
CostType string `db:"cost_type" json:"costType,omitempty"` // 计费类型(hourly, daily, monthly,perUse)
UserId int64 `db:"user_id" json:"userId"` // 用户ID
CreateTime time.Time `db:"create_time" json:"createTime"` // 创建时间
UpdateTime time.Time `db:"update_time" json:"updateTime"` // 更新时间
DeletedAt gorm.DeletedAt `db:"deleted_at" json:"-"` // 删除时间
Id int64 `db:"id" json:"id"` // 主键id
SourceKey string `db:"source_key" json:"source_key"` // 数据源标识(type-name)
Type string `db:"type" json:"type"` // 类型名称
Name string `db:"name" json:"name"` // 规格名称
TotalCount int64 `db:"total_count" json:"totalCount"` // 资源总量
AvailableCount int64 `db:"available_count" json:"availableCount"` // 可用数量
ChangeType int64 `db:"change_type" json:"changeType"` // 变更类型(0: 正常,1:变更,2:删除)
Status int64 `db:"status" json:"status"` // 状态(0:未上架,1:已上架)
Region string `db:"region" json:"region"` // 所属区域(可扩展多区域)
ClusterId int64 `db:"cluster_id" json:"clusterId,string"` // 集群ID
CostPerUnit float64 `db:"cost_per_unit" json:"costPerUnit"` // 单位时间积分消耗
CostType string `db:"cost_type" json:"costType"` // 计费类型(hourly, daily, monthly,perUse)
UserId int64 `db:"user_id" json:"userId"` // 用户ID
CreateTime time.Time `db:"create_time" json:"createTime"` // 创建时间
UpdateTime time.Time `db:"update_time" json:"updateTime"` // 更新时间
DeletedAt gorm.DeletedAt `db:"deleted_at" json:"-"` // 删除时间


BaseResourceSpecs []TBaseResourceSpec `gorm:"foreignKey:ResourceSpecId" json:"baseResourceSpecs,omitempty"` BaseResourceSpecs []TBaseResourceSpec `gorm:"foreignKey:ResourceSpecId" json:"baseResourceSpecs,omitempty"`
} }


Loading…
Cancel
Save