forked from JointCloud/pcm-coordinator
parent
a357b6f631
commit
55e25b2241
|
@ -1394,7 +1394,7 @@ type ResourceCostRecord {
|
|||
}
|
||||
|
||||
type ResourceSpecReq {
|
||||
ClusterId string `form:"clusterId"`
|
||||
ClusterId string `form:"clusterId,optional"`
|
||||
Type string `form:"type,optional"`
|
||||
Name string `form:"name,optional"`
|
||||
Status string `form:"status,optional"`
|
||||
|
@ -1449,10 +1449,19 @@ type BaseResourceSpec {
|
|||
}
|
||||
|
||||
type EditResourceReq {
|
||||
Id int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
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 {
|
||||
|
|
|
@ -242,59 +242,10 @@ func (l *CompareResourceSpecLogic) updateResource(existing *models.TResourceSpec
|
|||
return fmt.Errorf("failed to update resource: %w", err)
|
||||
}
|
||||
|
||||
return l.syncBaseResources(tx, existing.Id, newSpec.BaseResourceSpecs)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (l *CompareResourceSpecLogic) 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 *CompareResourceSpecLogic) markResourceDeleted(id int64) error {
|
||||
return l.svcCtx.DbEngin.Model(&models.TResourceSpec{}).
|
||||
Where("id = ?", id).
|
||||
|
|
|
@ -36,8 +36,9 @@ func (l *EditResourceSpecLogic) EditResourceSpec(req *types.EditResourceReq) (re
|
|||
}
|
||||
}()
|
||||
|
||||
// 1. 验证资源规格存在
|
||||
var existing models.TResourceSpec
|
||||
if err := tx.Model(&models.TResourceSpec{}).
|
||||
if err = tx.Model(&models.TResourceSpec{}).
|
||||
Where("id = ? AND deleted_at IS NULL", req.Id).
|
||||
First(&existing).
|
||||
Error; err != nil {
|
||||
|
@ -47,10 +48,42 @@ func (l *EditResourceSpecLogic) EditResourceSpec(req *types.EditResourceReq) (re
|
|||
return nil, errors.Wrapf(err, "查询资源规格失败 (ID: %d)", req.Id)
|
||||
}
|
||||
|
||||
if req.Status != "0" && req.Status != "1" {
|
||||
return nil, errors.Errorf("资源规格状态不合法 (ID: %d)", req.Id)
|
||||
// 2. 参数校验
|
||||
if err = validateRequestParams(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 5. 更新子资源规格
|
||||
if err = updateSubResources(tx, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
if err = tx.Commit().Error; err != nil {
|
||||
return nil, errors.Wrap(err, "提交事务失败")
|
||||
}
|
||||
|
||||
// 返回成功响应
|
||||
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": {},
|
||||
|
@ -58,152 +91,73 @@ func (l *EditResourceSpecLogic) EditResourceSpec(req *types.EditResourceReq) (re
|
|||
"perUse": {},
|
||||
}
|
||||
if _, ok := validCostTypes[req.CostType]; !ok {
|
||||
return nil, errors.Errorf("资源规格计费类型不合法 (ID: %d)", req.Id)
|
||||
return 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 resp, nil
|
||||
return 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
|
||||
//}
|
||||
// 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
|
||||
}
|
||||
|
|
|
@ -2126,10 +2126,17 @@ type Driver_info struct {
|
|||
}
|
||||
|
||||
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)
|
||||
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 {
|
||||
|
@ -4598,7 +4605,7 @@ type ResourceSpec struct {
|
|||
}
|
||||
|
||||
type ResourceSpecReq struct {
|
||||
ClusterId string `form:"clusterId"`
|
||||
ClusterId string `form:"clusterId,optional"`
|
||||
Type string `form:"type,optional"`
|
||||
Name string `form:"name,optional"`
|
||||
Status string `form:"status,optional"`
|
||||
|
|
Loading…
Reference in New Issue