forked from JointCloud/pcm-coordinator
update resourceSpec
Signed-off-by: jagger <cossjie@foxmail.com>
This commit is contained in:
parent
82aabde7cf
commit
c3b12e876e
|
@ -1446,4 +1446,11 @@ type BaseResourceSpec {
|
|||
UserId string `json:"userId" gorm:"column:user_id"`
|
||||
CreateTime string `json:"createTime" gorm:"column:create_time"`
|
||||
UpdateTime string `json:"updateTime" gorm:"column:update_time"`
|
||||
}
|
||||
|
||||
type EditResourceReq {
|
||||
Id int64 `json:"id" 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)
|
||||
}
|
|
@ -193,7 +193,7 @@ service pcm {
|
|||
|
||||
@doc "编辑资源规格"
|
||||
@handler editResourceSpecHandler
|
||||
put /core/ai/resourceSpec/edit (ResourceSpec) returns (CommonResp)
|
||||
put /core/ai/resourceSpec/edit (EditResourceReq) returns (CommonResp)
|
||||
|
||||
@doc "删除资源规格"
|
||||
@handler deleteResourceSpecHandler
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
func EditResourceSpecHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ResourceSpec
|
||||
var req types.EditResourceReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
result.ParamErrorResult(r, w, err)
|
||||
return
|
||||
|
|
|
@ -2,16 +2,13 @@ package core
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/svc"
|
||||
"gitlink.org.cn/JointCloud/pcm-coordinator/internal/types"
|
||||
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/models"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
"gitlink.org.cn/JointCloud/pcm-coordinator/pkg/utils"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type EditResourceSpecLogic struct {
|
||||
|
@ -27,125 +24,186 @@ func NewEditResourceSpecLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
|
|||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *EditResourceSpecLogic) EditResourceSpec(req *types.ResourceSpec) (resp *types.CommonResp, err error) {
|
||||
startTime := time.Now()
|
||||
resources, err := ConvertResourceSpec(req)
|
||||
l.Infof("转换主资源规格耗时:%v", time.Since(startTime))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "资源规格转换失败")
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}()
|
||||
|
||||
// 检查主资源存在性
|
||||
var existing models.TResourceSpec
|
||||
if err := tx.Model(&models.TResourceSpec{}).
|
||||
Where("id = ? AND deleted_at IS NULL", resources.Id).
|
||||
Where("id = ? AND deleted_at IS NULL", req.Id).
|
||||
First(&existing).
|
||||
Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrapf(err, "资源规格不存在 (ID: %d)", resources.Id)
|
||||
}
|
||||
|
||||
// 更新主资源
|
||||
if err := tx.Model(&models.TResourceSpec{}).
|
||||
Where("id = ?", resources.Id).
|
||||
Select("*").
|
||||
Updates(&resources).
|
||||
Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "更新主资源规格失败")
|
||||
}
|
||||
|
||||
// 更新子资源
|
||||
for _, spec := range resources.BaseResourceSpecs {
|
||||
spec.ResourceSpecId = resources.Id // 确保关联关系正确
|
||||
result := tx.Model(&models.TBaseResourceSpec{}).
|
||||
Where("id = ? AND resource_spec_id = ?", spec.Id, resources.Id).
|
||||
Updates(&spec)
|
||||
if result.Error != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrapf(result.Error, "更新子资源失败 (ID: %d)", spec.Id)
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.Errorf("资源规格不存在 (ID: %d)", req.Id)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "查询资源规格失败 (ID: %d)", req.Id)
|
||||
}
|
||||
|
||||
if req.Status != "0" && req.Status != "1" {
|
||||
return nil, errors.Errorf("资源规格状态不合法 (ID: %d)", req.Id)
|
||||
}
|
||||
|
||||
validCostTypes := map[string]struct{}{
|
||||
"hourly": {},
|
||||
"daily": {},
|
||||
"monthly": {},
|
||||
"perUse": {},
|
||||
}
|
||||
if _, ok := validCostTypes[req.CostType]; !ok {
|
||||
return nil, errors.Errorf("资源规格计费类型不合法 (ID: %d)", req.Id)
|
||||
}
|
||||
|
||||
statusInt := utils.StringToInt64(req.Status)
|
||||
costPerUnit := utils.StringToFloat64(req.CostPerUnit)
|
||||
|
||||
// 4. 更新资源规格
|
||||
updateData := map[string]interface{}{
|
||||
"status": statusInt,
|
||||
"cost_type": req.CostType,
|
||||
"cost_per_unit": costPerUnit,
|
||||
}
|
||||
if err := tx.Model(&models.TResourceSpec{}).
|
||||
Where("id = ?", req.Id).
|
||||
Updates(updateData).
|
||||
Error; err != nil {
|
||||
return nil, errors.Wrapf(err, "更新资源规格失败 (ID: %d)", req.Id)
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return nil, errors.Wrap(err, "事务提交失败")
|
||||
return nil, errors.Wrap(err, "提交事务失败")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 类型转换相关函数保持不变,但建议添加更多错误处理
|
||||
func decodeHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
|
||||
// 增强类型转换错误处理
|
||||
switch {
|
||||
case f.Kind() == reflect.String && t.Kind() == reflect.Int64:
|
||||
v, err := strconv.ParseInt(data.(string), 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("类型转换失败: %v -> %v (%w)", f, t, err)
|
||||
}
|
||||
return v, nil
|
||||
case f.Kind() == reflect.String && t == reflect.TypeOf(time.Time{}):
|
||||
v, err := time.Parse(time.RFC3339, data.(string))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("时间格式解析失败: %w", err)
|
||||
}
|
||||
return v, nil
|
||||
case f.Kind() == reflect.Int32 && t.Kind() == reflect.Int64:
|
||||
return int64(data.(int32)), nil
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func decodeWithHook(input, output interface{}) error {
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
||||
decodeHook,
|
||||
mapstructure.StringToTimeHookFunc(time.RFC3339),
|
||||
),
|
||||
Result: output,
|
||||
TagName: "json",
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建解码器失败: %w", err)
|
||||
}
|
||||
if err := decoder.Decode(input); err != nil {
|
||||
return fmt.Errorf("数据解码失败: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertBaseSpecs(specs []types.BaseResourceSpec) ([]models.TBaseResourceSpec, error) {
|
||||
tSpecs := make([]models.TBaseResourceSpec, 0, len(specs))
|
||||
for i, spec := range specs {
|
||||
var tSpec models.TBaseResourceSpec
|
||||
if err := decodeWithHook(spec, &tSpec); err != nil {
|
||||
return nil, fmt.Errorf("基础资源规格转换失败 (索引 %d): %w", i, err)
|
||||
}
|
||||
tSpecs = append(tSpecs, tSpec)
|
||||
}
|
||||
return tSpecs, nil
|
||||
}
|
||||
|
||||
func ConvertResourceSpec(spec *types.ResourceSpec) (models.TResourceSpec, error) {
|
||||
var tSpec models.TResourceSpec
|
||||
if err := decodeWithHook(spec, &tSpec); err != nil {
|
||||
return models.TResourceSpec{}, fmt.Errorf("主资源规格转换失败: %w", err)
|
||||
}
|
||||
|
||||
baseSpecs, err := convertBaseSpecs(spec.BaseResourceSpecs)
|
||||
if err != nil {
|
||||
return models.TResourceSpec{}, fmt.Errorf("基础资源规格转换失败: %w", err)
|
||||
}
|
||||
tSpec.BaseResourceSpecs = baseSpecs
|
||||
|
||||
return tSpec, nil
|
||||
}
|
||||
//
|
||||
//func (l *EditResourceSpecLogic) EditResourceSpec(req *types.EditResourceReq) (resp *types.CommonResp, err error) {
|
||||
// startTime := time.Now()
|
||||
// resources, err := ConvertResourceSpec(req)
|
||||
// l.Infof("转换主资源规格耗时:%v", time.Since(startTime))
|
||||
// if err != nil {
|
||||
// return nil, errors.Wrap(err, "资源规格转换失败")
|
||||
// }
|
||||
//
|
||||
// tx := l.svcCtx.DbEngin.Begin()
|
||||
// defer func() {
|
||||
// if r := recover(); r != nil {
|
||||
// tx.Rollback()
|
||||
// panic(r)
|
||||
// }
|
||||
// }()
|
||||
//
|
||||
// // 检查主资源存在性
|
||||
// var existing models.TResourceSpec
|
||||
// if err := tx.Model(&models.TResourceSpec{}).
|
||||
// Where("id = ? AND deleted_at IS NULL", resources.Id).
|
||||
// First(&existing).
|
||||
// Error; err != nil {
|
||||
// tx.Rollback()
|
||||
// return nil, errors.Wrapf(err, "资源规格不存在 (ID: %d)", resources.Id)
|
||||
// }
|
||||
//
|
||||
// // 更新主资源
|
||||
// if err := tx.Model(&models.TResourceSpec{}).
|
||||
// Where("id = ?", resources.Id).
|
||||
// Select("*").
|
||||
// Updates(&resources).
|
||||
// Error; err != nil {
|
||||
// tx.Rollback()
|
||||
// return nil, errors.Wrap(err, "更新主资源规格失败")
|
||||
// }
|
||||
//
|
||||
// // 更新子资源
|
||||
// for _, spec := range resources.BaseResourceSpecs {
|
||||
// spec.ResourceSpecId = resources.Id // 确保关联关系正确
|
||||
// result := tx.Model(&models.TBaseResourceSpec{}).
|
||||
// Where("id = ? AND resource_spec_id = ?", spec.Id, resources.Id).
|
||||
// Updates(&spec)
|
||||
// if result.Error != nil {
|
||||
// tx.Rollback()
|
||||
// return nil, errors.Wrapf(result.Error, "更新子资源失败 (ID: %d)", spec.Id)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if err := tx.Commit().Error; err != nil {
|
||||
// return nil, errors.Wrap(err, "事务提交失败")
|
||||
// }
|
||||
//
|
||||
// return resp, nil
|
||||
//}
|
||||
//
|
||||
//// 类型转换相关函数保持不变,但建议添加更多错误处理
|
||||
//func decodeHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
|
||||
// // 增强类型转换错误处理
|
||||
// switch {
|
||||
// case f.Kind() == reflect.String && t.Kind() == reflect.Int64:
|
||||
// v, err := strconv.ParseInt(data.(string), 10, 64)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("类型转换失败: %v -> %v (%w)", f, t, err)
|
||||
// }
|
||||
// return v, nil
|
||||
// case f.Kind() == reflect.String && t == reflect.TypeOf(time.Time{}):
|
||||
// v, err := time.Parse(time.RFC3339, data.(string))
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("时间格式解析失败: %w", err)
|
||||
// }
|
||||
// return v, nil
|
||||
// case f.Kind() == reflect.Int32 && t.Kind() == reflect.Int64:
|
||||
// return int64(data.(int32)), nil
|
||||
// }
|
||||
// return data, nil
|
||||
//}
|
||||
//
|
||||
//func decodeWithHook(input, output interface{}) error {
|
||||
// decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
// DecodeHook: mapstructure.ComposeDecodeHookFunc(
|
||||
// decodeHook,
|
||||
// mapstructure.StringToTimeHookFunc(time.RFC3339),
|
||||
// ),
|
||||
// Result: output,
|
||||
// TagName: "json",
|
||||
// })
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("创建解码器失败: %w", err)
|
||||
// }
|
||||
// if err := decoder.Decode(input); err != nil {
|
||||
// return fmt.Errorf("数据解码失败: %w", err)
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func convertBaseSpecs(specs []types.BaseResourceSpec) ([]models.TBaseResourceSpec, error) {
|
||||
// tSpecs := make([]models.TBaseResourceSpec, 0, len(specs))
|
||||
// for i, spec := range specs {
|
||||
// var tSpec models.TBaseResourceSpec
|
||||
// if err := decodeWithHook(spec, &tSpec); err != nil {
|
||||
// return nil, fmt.Errorf("基础资源规格转换失败 (索引 %d): %w", i, err)
|
||||
// }
|
||||
// tSpecs = append(tSpecs, tSpec)
|
||||
// }
|
||||
// return tSpecs, nil
|
||||
//}
|
||||
//
|
||||
//func ConvertResourceSpec(spec *types.ResourceSpec) (models.TResourceSpec, error) {
|
||||
// var tSpec models.TResourceSpec
|
||||
// if err := decodeWithHook(spec, &tSpec); err != nil {
|
||||
// return models.TResourceSpec{}, fmt.Errorf("主资源规格转换失败: %w", err)
|
||||
// }
|
||||
//
|
||||
// baseSpecs, err := convertBaseSpecs(spec.BaseResourceSpecs)
|
||||
// if err != nil {
|
||||
// return models.TResourceSpec{}, fmt.Errorf("基础资源规格转换失败: %w", err)
|
||||
// }
|
||||
// tSpec.BaseResourceSpecs = baseSpecs
|
||||
//
|
||||
// return tSpec, nil
|
||||
//}
|
||||
|
|
|
@ -2125,6 +2125,13 @@ type Driver_info struct {
|
|||
Ipmi_username string `json:"ipmi_username" copier:"ipmi_username"`
|
||||
}
|
||||
|
||||
type EditResourceReq struct {
|
||||
Id int64 `json:"id" 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 EndpointsReq struct {
|
||||
AllowedAccessIps []string `json:"allowedAccessIps" copier:"AllowedAccessIps"`
|
||||
DevService string `json:"devService" copier:"DevService"`
|
||||
|
|
|
@ -38,18 +38,18 @@ type (
|
|||
}
|
||||
|
||||
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,omitempty"` // 用户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:"-"` // 删除时间
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -38,21 +38,21 @@ type (
|
|||
}
|
||||
|
||||
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,omitempty"` // 用户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
|
||||
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"`
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue