diff --git a/dbm-services/common/db-resource/internal/controller/apply/apply.go b/dbm-services/common/db-resource/internal/controller/apply/apply.go index 0e8bb426eb..dcb87cfd56 100644 --- a/dbm-services/common/db-resource/internal/controller/apply/apply.go +++ b/dbm-services/common/db-resource/internal/controller/apply/apply.go @@ -65,25 +65,23 @@ func (c *ApplyHandler) ConfirmApply(r *gin.Context) { if c.Prepare(r, ¶m) != nil { return } - requestId := r.GetString("request_id") hostIds := cmutil.RemoveDuplicate(param.HostIds) var cnt int64 err := model.DB.Self.Table(model.TbRpApplyDetailLogName()).Where("request_id = ?", param.RequestId).Count(&cnt).Error if err != nil { logger.Error("use request id %s,query apply resouece failed %s", param.RequestId, err.Error()) - c.SendResponse(r, fmt.Errorf("%w", err), "use request id search applyed resource failed", requestId) return } if len(hostIds) != int(cnt) { c.SendResponse(r, fmt.Errorf("need return resource count is %d,but use request id only found total count %d", - len(hostIds), cnt), requestId, "") + len(hostIds), cnt), "") return } var rs []model.TbRpDetail err = model.DB.Self.Table(model.TbRpDetailName()).Where(" bk_host_id in (?) and status != ? ", hostIds, model.Prepoccupied).Find(&rs).Error if err != nil { - c.SendResponse(r, err, err.Error(), requestId) + c.SendResponse(r, err, err.Error()) return } if len(rs) > 0 { @@ -91,7 +89,7 @@ func (c *ApplyHandler) ConfirmApply(r *gin.Context) { for _, v := range rs { errMsg += fmt.Sprintf("%s:%s\n", v.IP, v.Status) } - c.SendResponse(r, fmt.Errorf("the following example:%s,abnormal state", errMsg), "", requestId) + c.SendResponse(r, fmt.Errorf("the following example:%s,abnormal state", errMsg), "") return } // update to used status @@ -103,7 +101,7 @@ func (c *ApplyHandler) ConfirmApply(r *gin.Context) { }, ) if err != nil { - c.SendResponse(r, err, err.Error(), requestId) + c.SendResponse(r, err, err.Error()) return } uerr := model.DB.Self.Table(model.TbRpOperationInfoTableName()).Where("request_id = ?", @@ -112,7 +110,7 @@ func (c *ApplyHandler) ConfirmApply(r *gin.Context) { logger.Warn("update tb_rp_operation_info failed %s ", uerr.Error()) } archive(hostIds) - c.SendResponse(r, nil, "successful", requestId) + c.SendResponse(r, nil, "successful") } func archive(bkHostIds []int) { @@ -151,20 +149,18 @@ func (c *ApplyHandler) ApplyBase(r *gin.Context, mode string) { var param apply.RequestInputParam var pickers []*apply.PickerObject var err error - var requestId string if c.Prepare(r, ¶m) != nil { return } - requestId = r.GetString("request_id") if err = param.ParamCheck(); err != nil { - c.SendResponse(r, errno.ErrApplyResourceParamCheck.AddErr(err), err.Error(), requestId) + c.SendResponse(r, errno.ErrApplyResourceParamCheck.AddErr(err), err.Error()) return } // get the resource lock if it is dry run you do not need to acquire it if !param.DryRun { - lock := newLocker(param.LockKey(), requestId) + lock := newLocker(param.LockKey(), c.RequestId) if err = lock.Lock(); err != nil { - c.SendResponse(r, errno.ErrResourceLock.AddErr(err), err.Error(), requestId) + c.SendResponse(r, errno.ErrResourceLock.AddErr(err), err.Error()) return } defer func() { @@ -175,27 +171,29 @@ func (c *ApplyHandler) ApplyBase(r *gin.Context, mode string) { }() } defer func() { - apply.RollBackAllInstanceUnused(pickers) + if err != nil { + apply.RollBackAllInstanceUnused(pickers) + } }() pickers, err = apply.CycleApply(param) if err != nil { - c.SendResponse(r, err, "", requestId) + c.SendResponse(r, errno.ErrResourceinsufficient.Add(param.BuildMessage()+"\n"+err.Error()), "") return } if param.DryRun { - c.SendResponse(r, nil, map[string]interface{}{"check_success": true}, requestId) + c.SendResponse(r, nil, map[string]interface{}{"check_success": true}) return } data, err := apply.LockReturnPickers(pickers, mode) if err != nil { - c.SendResponse(r, errno.ErresourceLockReturn.AddErr(err), nil, requestId) + c.SendResponse(r, errno.ErresourceLockReturn.AddErr(err), nil) return } - logger.Info(fmt.Sprintf("The %s, will return %d machines", requestId, len(data))) + logger.Info(fmt.Sprintf("The %s, will return %d machines", c.RequestId, len(data))) task.ApplyResponeLogChan <- task.ApplyResponeLogItem{ - RequestId: requestId, + RequestId: c.RequestId, Data: data, } - task.RecordRsOperatorInfoChan <- param.GetOperationInfo(requestId, mode, data) - c.SendResponse(r, nil, data, requestId) + task.RecordRsOperatorInfoChan <- param.GetOperationInfo(c.RequestId, mode, data) + c.SendResponse(r, nil, data) } diff --git a/dbm-services/common/db-resource/internal/controller/controller.go b/dbm-services/common/db-resource/internal/controller/controller.go index 8ee84ac1b3..578bd0539e 100644 --- a/dbm-services/common/db-resource/internal/controller/controller.go +++ b/dbm-services/common/db-resource/internal/controller/controller.go @@ -23,8 +23,10 @@ import ( "github.com/gin-gonic/gin" ) -// BaseHandler TODO -type BaseHandler struct{} +// BaseHandler base handler +type BaseHandler struct { + RequestId string +} // Response http respone type Response struct { @@ -39,12 +41,13 @@ func (c *BaseHandler) Prepare(r *gin.Context, schema interface{}) error { requestId := r.GetString("request_id") if cmutil.IsEmpty(requestId) { err := fmt.Errorf("get request id error ~") - c.SendResponse(r, err, nil, requestId) + c.SendResponse(r, err, nil) return err } + c.RequestId = requestId if err := r.ShouldBind(&schema); err != nil { logger.Error("ShouldBind Failed %s", err.Error()) - c.SendResponse(r, err, nil, requestId) + c.SendResponse(r, err, nil) return err } logger.Info("param is %v", schema) @@ -52,13 +55,13 @@ func (c *BaseHandler) Prepare(r *gin.Context, schema interface{}) error { } // SendResponse retrnurns a response -func (c *BaseHandler) SendResponse(r *gin.Context, err error, data interface{}, requestId string) { +func (c *BaseHandler) SendResponse(r *gin.Context, err error, data interface{}) { code, message := errno.DecodeErr(err) r.JSON(http.StatusOK, Response{ Code: code, Message: message, Data: data, - RequestId: requestId, + RequestId: c.RequestId, }) } @@ -76,13 +79,13 @@ func (c *BackStageHandler) RegisterRouter(engine *gin.Engine) { } } -// RunModuleCheck 运行模块检查 +// RunModuleCheck run module check func (c BackStageHandler) RunModuleCheck(r *gin.Context) { err := task.InspectCheckResource() if err != nil { logger.Error("inspectCheckResource failed %v", err) } - c.SendResponse(r, nil, "Check Success", "") + c.SendResponse(r, nil, "Check Success") } // RunAsyncCmdb async from cmdb @@ -91,5 +94,5 @@ func (c BackStageHandler) RunAsyncCmdb(r *gin.Context) { if err != nil { logger.Error("asyncResourceHardInfo failed %v", err) } - c.SendResponse(r, nil, "async success", "") + c.SendResponse(r, nil, "async success") } diff --git a/dbm-services/common/db-resource/internal/controller/manage/rs_import.go b/dbm-services/common/db-resource/internal/controller/manage/rs_import.go index 3d0309d15a..7f57a8f1e2 100644 --- a/dbm-services/common/db-resource/internal/controller/manage/rs_import.go +++ b/dbm-services/common/db-resource/internal/controller/manage/rs_import.go @@ -35,11 +35,11 @@ import ( // ImportMachParam 资源导入请求参数 type ImportMachParam struct { // ForBizs 业务标签,表示这个资源将来给ForBizs这个业务使用 - ForBiz int `json:"for_biz"` - RsType string `json:"resource_type"` - BkBizId int `json:"bk_biz_id" binding:"number"` - Hosts []HostBase `json:"hosts" binding:"gt=0,dive,required"` - Labels map[string]string `json:"labels"` + ForBiz int `json:"for_biz"` + RsType string `json:"resource_type"` + BkBizId int `json:"bk_biz_id" binding:"number"` + Hosts []HostBase `json:"hosts" binding:"gt=0,dive,required"` + Labels []string `json:"labels"` apply.ActionInfo } @@ -82,7 +82,7 @@ func (p *ImportMachParam) existCheck() (err error) { for _, r := range alreadyExistRs { errMsg += fmt.Sprintf(" bk_cloud_id:%d,ip:%s \n", r.BkCloudID, r.IP) } - return fmt.Errorf(errMsg) + return fmt.Errorf("%s", errMsg) } } return nil @@ -95,22 +95,22 @@ func (c *MachineResourceHandler) Import(r *rf.Context) { logger.Error(fmt.Sprintf("Preare Error %s", err.Error())) return } - requestId := r.GetString("request_id") + // requestId := r.GetString("request_id") if err := input.existCheck(); err != nil { - c.SendResponse(r, errno.RepeatedIpExistSystem.Add(err.Error()), requestId, err.Error()) + c.SendResponse(r, errno.RepeatedIpExistSystem.Add(err.Error()), err.Error()) return } resp, err := Doimport(input) if err != nil { logger.Error(fmt.Sprintf("ImportByIps failed %s", err.Error())) - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } if len(resp.NotFoundInCCHosts) == len(input.Hosts) { - c.SendResponse(r, fmt.Errorf("all machines failed to query cmdb information"), resp, requestId) + c.SendResponse(r, fmt.Errorf("all machines failed to query cmdb information"), resp) return } - c.SendResponse(r, err, resp, requestId) + c.SendResponse(r, err, resp) } // ImportHostResp 导入主机参数 @@ -121,8 +121,7 @@ type ImportHostResp struct { } func (p ImportMachParam) transParamToBytes() (lableJson json.RawMessage, err error) { - // lableJson = []byte("{}") - lableJson, err = json.Marshal(cmutil.CleanStrMap(p.Labels)) + lableJson, err = json.Marshal(p.Labels) if err != nil { logger.Error(fmt.Sprintf("ConverLableToJsonStr Failed,Error:%s", err.Error())) return diff --git a/dbm-services/common/db-resource/internal/controller/manage/rs_lable.go b/dbm-services/common/db-resource/internal/controller/manage/rs_lable.go index 0bfc3b53f0..a16d97b07e 100644 --- a/dbm-services/common/db-resource/internal/controller/manage/rs_lable.go +++ b/dbm-services/common/db-resource/internal/controller/manage/rs_lable.go @@ -29,15 +29,15 @@ func (c *LableHandler) Edit(r *rf.Context) { logger.Error(fmt.Sprintf("Preare Error %s", err.Error())) return } - requestId := r.GetString("request_id") + // requestId := r.GetString("request_id") lableJson, err := cmutil.ConverMapToJsonStr(cmutil.CleanStrMap(input.Labels)) if err != nil { logger.Error(fmt.Sprintf("ConverLableToJsonStr Failed,Error:%s", err.Error())) - c.SendResponse(r, err, nil, requestId) + c.SendResponse(r, err, nil) return } if len(input.BkHostIds) == 0 { - c.SendResponse(r, nil, nil, requestId) + c.SendResponse(r, nil, nil) return } err = model.DB.Self.Table(model.TbRpDetailName()).Where("bk_host_id in ? ", input.BkHostIds).Update("label", @@ -45,8 +45,8 @@ func (c *LableHandler) Edit(r *rf.Context) { Error if err != nil { logger.Error(fmt.Sprintf("Update Lable Failed %s", err.Error())) - c.SendResponse(r, err, nil, requestId) + c.SendResponse(r, err, nil) return } - c.SendResponse(r, nil, nil, requestId) + c.SendResponse(r, nil, nil) } diff --git a/dbm-services/common/db-resource/internal/controller/manage/rs_list.go b/dbm-services/common/db-resource/internal/controller/manage/rs_list.go index 8b59d354c1..415ef80aff 100644 --- a/dbm-services/common/db-resource/internal/controller/manage/rs_list.go +++ b/dbm-services/common/db-resource/internal/controller/manage/rs_list.go @@ -34,7 +34,7 @@ type MachineResourceGetterInputParam struct { City []string `json:"city"` SubZoneIds []string `json:"subzone_ids"` DeviceClass []string `json:"device_class"` - Labels map[string]string `json:"labels"` + Labels []string `json:"labels"` Hosts []string `json:"hosts"` BkCloudIds []int `json:"bk_cloud_ids"` RsType string `json:"resource_type"` @@ -62,18 +62,17 @@ func (c *MachineResourceHandler) List(r *rf.Context) { if c.Prepare(r, &input) != nil { return } - requestId := r.GetString("request_id") if err := input.paramCheck(); err != nil { - c.SendResponse(r, errno.ErrErrInvalidParam.AddErr(err), nil, requestId) + c.SendResponse(r, errno.ErrErrInvalidParam.AddErr(err), nil) return } db := model.DB.Self.Table(model.TbRpDetailName()) if err := input.queryBs(db); err != nil { - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } if err := db.Count(&count).Error; err != nil { - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } if input.Limit > 0 { @@ -81,10 +80,10 @@ func (c *MachineResourceHandler) List(r *rf.Context) { } var data []model.TbRpDetail if err := db.Find(&data).Error; err != nil { - c.SendResponse(r, errno.ErrDBQuery.AddErr(err), requestId, err.Error()) + c.SendResponse(r, errno.ErrDBQuery.AddErr(err), err.Error()) return } - c.SendResponse(r, nil, map[string]interface{}{"details": data, "count": count}, requestId) + c.SendResponse(r, nil, map[string]interface{}{"details": data, "count": count}) } func (c *MachineResourceGetterInputParam) paramCheck() (err error) { @@ -193,7 +192,9 @@ func (c *MachineResourceGetterInputParam) queryBs(db *gorm.DB) (err error) { if len(c.SubZoneIds) > 0 { db.Where(" sub_zone_id in (?) ", c.SubZoneIds) } - + if len(c.Labels) > 0 { + db.Where(model.JSONQuery("labels").JointOrContains(c.Labels)) + } if cmutil.IsNotEmpty(c.OsType) { db.Where("os_type = ?", c.OsType) } @@ -203,19 +204,19 @@ func (c *MachineResourceGetterInputParam) queryBs(db *gorm.DB) (err error) { // ListAll TODO func (c *MachineResourceHandler) ListAll(r *rf.Context) { - requestId := r.GetString("request_id") + // requestId := r.GetString("request_id") var data []model.TbRpDetail db := model.DB.Self.Table(model.TbRpDetailName()).Where("status in (?)", []string{model.Unused, model.Prepoccupied, model.Preselected}) err := db.Scan(&data).Error if err != nil { - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } var count int64 if err := db.Count(&count).Error; err != nil { - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } - c.SendResponse(r, nil, map[string]interface{}{"details": data, "count": count}, requestId) + c.SendResponse(r, nil, map[string]interface{}{"details": data, "count": count}) } diff --git a/dbm-services/common/db-resource/internal/controller/manage/rs_manage.go b/dbm-services/common/db-resource/internal/controller/manage/rs_manage.go index 88803cec6b..3321afaa10 100644 --- a/dbm-services/common/db-resource/internal/controller/manage/rs_manage.go +++ b/dbm-services/common/db-resource/internal/controller/manage/rs_manage.go @@ -70,24 +70,24 @@ func (c *MachineResourceHandler) Delete(r *rf.Context) { logger.Error("Preare Error %s", err.Error()) return } - requestId := r.GetString("request_id") affect_row, err := model.DeleteTbRpDetail(input.BkHostIds) if err != nil { logger.Error("failed to delete data:%s", err.Error()) - c.SendResponse(r, err, nil, requestId) + c.SendResponse(r, err, nil) return } if affect_row == 0 { - c.SendResponse(r, fmt.Errorf("no data was deleted"), nil, requestId) + c.SendResponse(r, fmt.Errorf("no data was deleted"), nil) return } - c.SendResponse(r, nil, requestId, "Delete Success") + c.SendResponse(r, nil, "Delete Success") } // BatchUpdateMachineInput 批量编辑主机信息请求参数 type BatchUpdateMachineInput struct { BkHostIds []int `json:"bk_host_ids" binding:"required,dive,gt=0" ` ForBiz int `json:"for_biz"` + Labels []string `json:"labels"` RsType string `json:"resource_type"` RackId string `json:"rack_id"` SetBizEmpty bool `json:"set_empty_biz"` @@ -103,10 +103,12 @@ const ( // BatchUpdate 批量编辑主机信息 func (c *MachineResourceHandler) BatchUpdate(r *rf.Context) { var input BatchUpdateMachineInput - requestId := r.GetString("request_id") + var err error + var lableJson, storageJson []byte + updateMap := make(map[string]interface{}) - if err := c.Prepare(r, &input); err != nil { + if err = c.Prepare(r, &input); err != nil { logger.Error("Preare Error %s", err.Error()) return } @@ -120,13 +122,20 @@ func (c *MachineResourceHandler) BatchUpdate(r *rf.Context) { if lo.IsNotEmpty(input.RsType) { updateMap["rs_type"] = input.RsType } + lableJson, err = json.Marshal(input.Labels) + if err != nil { + logger.Error(fmt.Sprintf("ConverLableToJsonStr Failed,Error:%s", err.Error())) + c.SendResponse(r, err, err.Error()) + return + } + updateMap["label"] = lableJson // update disk if len(input.StorageDevice) > 0 { - storageJson, err := json.Marshal(input.StorageDevice) + storageJson, err = json.Marshal(input.StorageDevice) if err != nil { logger.Error(fmt.Sprintf("conver resource types Failed,Error:%s", err.Error())) - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } updateMap["storage_device"] = storageJson @@ -138,15 +147,16 @@ func (c *MachineResourceHandler) BatchUpdate(r *rf.Context) { } // do update - err := model.DB.Self.Table(model.TbRpDetailName()).Select("dedicated_biz", "rs_type", "storage_device", "rack_id"). + err = model.DB.Self.Table(model.TbRpDetailName()).Select("dedicated_biz", "rs_type", "storage_device", "rack_id", + "label"). Where("bk_host_id in (?)", input.BkHostIds).Updates(updateMap).Error if err != nil { - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } // return respone - c.SendResponse(r, nil, "ok", requestId) + c.SendResponse(r, nil, "ok") } // MachineResourceInputParam 多个不同的主句的编辑的不同的参数 @@ -166,7 +176,6 @@ type MachineResource struct { // Update 编辑主机信息 func (c *MachineResourceHandler) Update(r *rf.Context) { var input MachineResourceInputParam - requestId := r.GetString("request_id") if err := c.Prepare(r, &input); err != nil { logger.Error("Preare Error %s", err.Error()) return @@ -192,7 +201,7 @@ func (c *MachineResourceHandler) Update(r *rf.Context) { storageJson, err := json.Marshal(v.StorageDevice) if err != nil { logger.Error(fmt.Sprintf("conver resource types Failed,Error:%s", err.Error())) - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } updateMap["storage_device"] = storageJson @@ -202,15 +211,15 @@ func (c *MachineResourceHandler) Update(r *rf.Context) { if err != nil { tx.Rollback() logger.Error(fmt.Sprintf("conver resource types Failed,Error:%s", err.Error())) - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } } if err := tx.Commit().Error; err != nil { - c.SendResponse(r, err, requestId, err.Error()) + c.SendResponse(r, err, err.Error()) return } - c.SendResponse(r, nil, requestId, "Save Success") + c.SendResponse(r, nil, "Save Success") } // GetMountPoints get disk mount points @@ -219,7 +228,7 @@ func (c MachineResourceHandler) GetMountPoints(r *rf.Context) { var rs []json.RawMessage if err := db.Select("json_keys(storage_device)").Where("JSON_LENGTH(storage_device) > 0").Find(&rs).Error; err != nil { logger.Error("get mountpoints failed %s", err.Error()) - c.SendResponse(r, err, err.Error(), "") + c.SendResponse(r, err, err.Error()) return } var mountpoints []string @@ -227,14 +236,14 @@ func (c MachineResourceHandler) GetMountPoints(r *rf.Context) { var mp []string if err := json.Unmarshal(v, &mp); err != nil { logger.Error("unmarshal failed %s", err.Error()) - c.SendResponse(r, err, err.Error(), "") + c.SendResponse(r, err, err.Error()) return } if len(mp) > 0 { mountpoints = append(mountpoints, mp...) } } - c.SendResponse(r, nil, cmutil.RemoveDuplicate(mountpoints), r.GetString("request_id")) + c.SendResponse(r, nil, cmutil.RemoveDuplicate(mountpoints)) } // GetDiskTypes get disk types @@ -245,7 +254,7 @@ func (c MachineResourceHandler) GetDiskTypes(r *rf.Context) { Find(&rs).Error if err != nil { logger.Error("get DiskType failed %s", err.Error()) - c.SendResponse(r, err, err.Error(), "") + c.SendResponse(r, err, err.Error()) return } var diskTypes []string @@ -253,14 +262,14 @@ func (c MachineResourceHandler) GetDiskTypes(r *rf.Context) { var mp []string if err := json.Unmarshal(v, &mp); err != nil { logger.Error("unmarshal failed %s", err.Error()) - c.SendResponse(r, err, err.Error(), "") + c.SendResponse(r, err, err.Error()) return } if len(mp) > 0 { diskTypes = append(diskTypes, mp...) } } - c.SendResponse(r, nil, cmutil.RemoveDuplicate(diskTypes), r.GetString("request_id")) + c.SendResponse(r, nil, cmutil.RemoveDuplicate(diskTypes)) } // GetSubZoneParam get subzones param @@ -278,10 +287,10 @@ func (c MachineResourceHandler) GetSubZones(r *rf.Context) { db := model.DB.Self.Table(model.TbRpDetailName()) err := db.Distinct("sub_zone").Where("city in ? ", input.LogicCitys).Find(&subZones).Error if err != nil { - c.SendResponse(r, err, "", err.Error()) + c.SendResponse(r, err, err.Error()) return } - c.SendResponse(r, nil, subZones, r.GetString("request_id")) + c.SendResponse(r, nil, subZones) } // GetDeviceClass 获取机型 @@ -290,8 +299,8 @@ func (c MachineResourceHandler) GetDeviceClass(r *rf.Context) { db := model.DB.Self.Table(model.TbRpDetailName()) err := db.Distinct("device_class").Where("device_class !=''").Find(&class).Error if err != nil { - c.SendResponse(r, err, "", err.Error()) + c.SendResponse(r, err, err.Error()) return } - c.SendResponse(r, nil, class, r.GetString("request_id")) + c.SendResponse(r, nil, class) } diff --git a/dbm-services/common/db-resource/internal/controller/manage/rs_operation_info.go b/dbm-services/common/db-resource/internal/controller/manage/rs_operation_info.go index fe83ca94e4..3f00f3f736 100644 --- a/dbm-services/common/db-resource/internal/controller/manage/rs_operation_info.go +++ b/dbm-services/common/db-resource/internal/controller/manage/rs_operation_info.go @@ -42,10 +42,9 @@ type GetOperationInfoParam struct { Offset int `json:"offset"` } -// OperationInfoList TODO +// OperationInfoList returns the list of operation info func (o MachineResourceHandler) OperationInfoList(r *gin.Context) { var input GetOperationInfoParam - requestId := r.GetString("request_id") if err := o.Prepare(r, &input); err != nil { logger.Error(fmt.Sprintf("Preare Error %s", err.Error())) return @@ -54,7 +53,7 @@ func (o MachineResourceHandler) OperationInfoList(r *gin.Context) { input.query(db) var count int64 if err := db.Count(&count).Error; err != nil { - o.SendResponse(r, errno.ErrDBQuery.AddErr(err), requestId, err.Error()) + o.SendResponse(r, errno.ErrDBQuery.AddErr(err), err.Error()) return } var data []model.TbRpOperationInfo @@ -62,11 +61,11 @@ func (o MachineResourceHandler) OperationInfoList(r *gin.Context) { db = db.Offset(input.Offset).Limit(input.Limit) } if err := db.Scan(&data).Error; err != nil { - o.SendResponse(r, errno.ErrDBQuery.AddErr(err), err.Error(), requestId) + o.SendResponse(r, errno.ErrDBQuery.AddErr(err), err.Error()) return } - o.SendResponse(r, nil, map[string]interface{}{"details": data, "count": count}, requestId) + o.SendResponse(r, nil, map[string]interface{}{"details": data, "count": count}) } func (p GetOperationInfoParam) query(db *gorm.DB) { @@ -134,12 +133,12 @@ func (o MachineResourceHandler) RecordImportResource(r *gin.Context) { } ipJsStr, err := json.Marshal(ipList) if err != nil { - o.SendResponse(r, errno.ErrJSONMarshal.Add("input ips"), "failed", "") + o.SendResponse(r, errno.ErrJSONMarshal.Add("input ips"), "failed") return } bkHostIdJsStr, err := json.Marshal(hostIdList) if err != nil { - o.SendResponse(r, errno.ErrJSONMarshal.Add("input hostids"), "failed", "") + o.SendResponse(r, errno.ErrJSONMarshal.Add("input hostids"), "failed") } m := model.TbRpOperationInfo{ TotalCount: len(ipList), @@ -152,7 +151,7 @@ func (o MachineResourceHandler) RecordImportResource(r *gin.Context) { CreateTime: time.Now(), } if err := model.DB.Self.Table(model.TbRpOperationInfoTableName()).Create(&m).Error; err != nil { - o.SendResponse(r, fmt.Errorf("记录导入任务日志失败,%w", err), err.Error(), "") + o.SendResponse(r, fmt.Errorf("记录导入任务日志失败,%w", err), err.Error()) } - o.SendResponse(r, nil, "记录日志成功", "") + o.SendResponse(r, nil, "记录日志成功") } diff --git a/dbm-services/common/db-resource/internal/controller/manage/rs_spec.go b/dbm-services/common/db-resource/internal/controller/manage/rs_spec.go index 903da29b04..b8535a5f96 100644 --- a/dbm-services/common/db-resource/internal/controller/manage/rs_spec.go +++ b/dbm-services/common/db-resource/internal/controller/manage/rs_spec.go @@ -38,15 +38,15 @@ type SpecInfo struct { GroupMark string `json:"group_mark" binding:"required" ` DeviceClass []string `json:"device_class"` Spec meta.Spec `json:"spec"` + Labels []string `json:"labels"` StorageSpecs []meta.DiskSpec `json:"storage_spec"` } // SpecSum TODO func (m MachineResourceHandler) SpecSum(r *gin.Context) { var input SpecCheckInput - requestId := r.GetString("request_id") if err := m.Prepare(r, &input); err != nil { - m.SendResponse(r, err, err.Error(), requestId) + m.SendResponse(r, err, err.Error()) return } rpdata := make(map[string]int64) @@ -58,7 +58,7 @@ func (m MachineResourceHandler) SpecSum(r *gin.Context) { idcCitys, err = dbmapi.GetIdcCityByLogicCity(input.LocationSpec.City) if err != nil { logger.Error("request real citys by logic city %s from bkdbm api failed:%v", input.LocationSpec.City, err) - m.SendResponse(r, err, err.Error(), requestId) + m.SendResponse(r, err, err.Error()) return } } @@ -93,12 +93,13 @@ func (m MachineResourceHandler) SpecSum(r *gin.Context) { s.MatchStorage(db) s.MatchSpec(db) s.MatchLocationSpec(db) + s.MatchLables(db) if err := db.Scan(&count).Error; err != nil { logger.Error("query pre check count failed %s", err.Error()) - m.SendResponse(r, errno.ErrDBQuery.AddErr(err), err.Error(), requestId) + m.SendResponse(r, errno.ErrDBQuery.AddErr(err), err.Error()) return } rpdata[item.GroupMark] = count } - m.SendResponse(r, nil, rpdata, requestId) + m.SendResponse(r, nil, rpdata) } diff --git a/dbm-services/common/db-resource/internal/controller/statistic/statistic.go b/dbm-services/common/db-resource/internal/controller/statistic/statistic.go index 3fde36d190..7fcb87b3eb 100644 --- a/dbm-services/common/db-resource/internal/controller/statistic/statistic.go +++ b/dbm-services/common/db-resource/internal/controller/statistic/statistic.go @@ -51,8 +51,6 @@ func (s *Handler) RegisterRouter(engine *gin.Engine) { } } -// CountGroupbyResourceType 按照资源类型统计 - // CountGroupbyResourceTypeResult 按照资源类型统计结果数据 type CountGroupbyResourceTypeResult struct { RsType string `json:"rs_type"` @@ -67,9 +65,9 @@ func (s *Handler) CountGroupbyResourceType(c *gin.Context) { Find(&data, "status = ? ", model.Unused).Error if err != nil { logger.Error("query failed %s", err.Error) - s.SendResponse(c, err, err.Error(), "") + s.SendResponse(c, err, err.Error()) } - s.SendResponse(c, nil, data, "") + s.SendResponse(c, nil, data) } // ResourDistributionParam 统计资源分布参数 @@ -117,7 +115,7 @@ func (s *Handler) ResourceDistribution(c *gin.Context) { var param ResourDistributionParam if err := s.Prepare(c, ¶m); err != nil { logger.Error("parse ResourDistributionParam failed: %v", err) - s.SendResponse(c, err, "Failed to parse parameters", "") + s.SendResponse(c, err, "Failed to parse parameters") return } @@ -125,13 +123,13 @@ func (s *Handler) ResourceDistribution(c *gin.Context) { specList, err := dbmClient.GetDbmSpec(param.SpecParam.getQueryParam()) if err != nil { logger.Error("get dbm spec failed: %v", err) - s.SendResponse(c, err, "Failed to get DBM specifications", "") + s.SendResponse(c, err, "Failed to get DBM specifications") return } allLogicCityInfos, err := dbmapi.GetAllLogicCityInfo() if err != nil { logger.Error("get all logic city info failed: %v", err) - s.SendResponse(c, err, "Failed to get logic city info", "") + s.SendResponse(c, err, "Failed to get logic city info") return } cityMap := make(map[string]string) @@ -140,14 +138,14 @@ func (s *Handler) ResourceDistribution(c *gin.Context) { } db := model.DB.Self.Table(model.TbRpDetailName()) if err := param.dbFilter(db); err != nil { - s.SendResponse(c, err, "Failed to apply database filter", "") + s.SendResponse(c, err, "Failed to apply database filter") return } var rsListBefore, rsList []model.TbRpDetail if err := db.Find(&rsListBefore).Error; err != nil { logger.Error("query failed: %v", err) - s.SendResponse(c, err, "Failed to query resource list", "") + s.SendResponse(c, err, "Failed to query resource list") return } for _, rs := range rsListBefore { @@ -167,16 +165,16 @@ func (s *Handler) ResourceDistribution(c *gin.Context) { default: err := errors.New("unknown aggregation type") msg := fmt.Sprintf("Unknown aggregation type: %s", param.GroupBy) - s.SendResponse(c, err, msg, "") + s.SendResponse(c, err, msg) return } if processErr != nil { - s.SendResponse(c, processErr, "Failed to process data", "") + s.SendResponse(c, processErr, "Failed to process data") return } - s.SendResponse(c, nil, result, "") + s.SendResponse(c, nil, result) } func (s *Handler) processDeviceClassGroup( @@ -184,6 +182,7 @@ func (s *Handler) processDeviceClassGroup( specList []dbmapi.DbmSpec, clusterType string, ) interface{} { + if lo.IsEmpty(clusterType) { return groupByDeviceClass(rsList) } @@ -195,6 +194,7 @@ func (s *Handler) processDeviceClassGroup( filteredList = append(filteredList, rs) break } + } } return groupByDeviceClass(filteredList) @@ -223,9 +223,6 @@ func (r ResourDistributionParam) dbFilter(db *gorm.DB) (err error) { } func dealCity(city string) string { - // if lo.IsEmpty(city) { - // city = "无区域信息" - // } return city } diff --git a/dbm-services/common/db-resource/internal/model/TbRpDetail.go b/dbm-services/common/db-resource/internal/model/TbRpDetail.go index 77c233fbb9..55dc48dd39 100644 --- a/dbm-services/common/db-resource/internal/model/TbRpDetail.go +++ b/dbm-services/common/db-resource/internal/model/TbRpDetail.go @@ -64,31 +64,48 @@ type TbRpDetail struct { StorageDevice json.RawMessage `gorm:"column:storage_device;type:json;comment:'磁盘设备'" json:"storage_device"` TotalStorageCap int `gorm:"column:total_storage_cap;type:int(11);comment:'磁盘总容量'" json:"total_storage_cap"` Storages map[string]bk.DiskDetail `gorm:"-" json:"-"` + // 操作系统类型 Liunx,Windows /*Linux(1) Windows(2) AIX(3) Unix(4) Solaris(5) FreeBSD(7)*/ - OsType string `gorm:"column:os_type;type:varchar(32);not null;comment:'操作系统类型'" json:"os_type"` // 操作系统类型 Liunx,Windows - OsBit string `gorm:"column:os_bit;type:varchar(32);not null;comment:'操作系统位数'" json:"os_bit"` - OsVerion string `gorm:"column:os_version;type:varchar(64);not null;comment:'操作系统版本'" json:"os_version"` // 操作系统版本 - OsName string `gorm:"column:os_name;type:varchar(64);not null;comment:'操作系统名称'" json:"os_name"` // 操作系统名称 - Raid string `gorm:"column:raid;type:varchar(20);not null" json:"raid"` // 磁盘Raid - CityID string `gorm:"column:city_id;type:varchar(64);not null" json:"city_id"` // 实际城市ID - City string `gorm:"column:city;type:varchar(128);not null" json:"city"` // 实际城市名称 - SubZone string `gorm:"column:sub_zone;type:varchar(32);not null" json:"sub_zone"` // 园区, 例如光明 cc_device_szone - SubZoneID string `gorm:"column:sub_zone_id;type:varchar(64);not null" json:"sub_zone_id"` // 园区ID cc_device_szone_id - RackID string `gorm:"column:rack_id;type:varchar(64);not null" json:"rack_id"` // 存放机架ID,判断是否是同机架 - NetDeviceID string `gorm:"column:net_device_id;type:varchar(128)" json:"net_device_id"` // 网络设备ID, 判断是同交换机 - Label json.RawMessage `gorm:"column:label;type:json" json:"label"` // 标签 - LabelMap map[string]string `gorm:"-" json:"-"` - IsInit int `gorm:"column:is_init;type:int(11);comment:'是否初始化过'" json:"-"` // 是否初始化过 - IsIdle int `gorm:"column:is_idle;type:int(11);comment:'是否空闲检查过'" json:"-"` // 是否空闲检查过 - Status string `gorm:"column:status;type:varchar(20);not null" json:"status"` // Unused: 未使用 Used: 已经售卖被使用: Preselected:预占用 - BkAgentId string `gorm:"index:idx_bk_agent_id;column:bk_agent_id;type:varchar(64);not null" json:"bk_agent_id"` + OsType string `gorm:"column:os_type;type:varchar(32);not null;comment:'操作系统类型'" json:"os_type"` + OsBit string `gorm:"column:os_bit;type:varchar(32);not null;comment:'操作系统位数'" json:"os_bit"` + // 操作系统版本 + OsVerion string `gorm:"column:os_version;type:varchar(64);not null;comment:'操作系统版本'" json:"os_version"` + // 操作系统名称 + OsName string `gorm:"column:os_name;type:varchar(64);not null;comment:'操作系统名称'" json:"os_name"` + // 磁盘Raid + Raid string `gorm:"column:raid;type:varchar(20);not null" json:"raid"` + // 实际城市ID + CityID string `gorm:"column:city_id;type:varchar(64);not null" json:"city_id"` + // 实际城市名称 + City string `gorm:"column:city;type:varchar(128);not null" json:"city"` + // 园区, 例如光明 cc_device_szone + SubZone string `gorm:"column:sub_zone;type:varchar(32);not null" json:"sub_zone"` + // 园区ID cc_device_szone_id + SubZoneID string `gorm:"column:sub_zone_id;type:varchar(64);not null" json:"sub_zone_id"` + // 存放机架ID,判断是否是同机架 + RackID string `gorm:"column:rack_id;type:varchar(64);not null" json:"rack_id"` + // 网络设备ID, 判断是同交换机 + NetDeviceID string `gorm:"column:net_device_id;type:varchar(128)" json:"net_device_id"` + // 标签 + Label json.RawMessage `gorm:"column:label;type:json" json:"label"` + LabelMap map[string]string `gorm:"-" json:"-"` + // 是否初始化过 + IsInit int `gorm:"column:is_init;type:int(11);comment:'是否初始化过'" json:"-"` + // 是否空闲检查过 + IsIdle int `gorm:"column:is_idle;type:int(11);comment:'是否空闲检查过'" json:"-"` + // Unused: 未使用 Used: 已经售卖被使用: Preselected:预占用 + Status string `gorm:"column:status;type:varchar(20);not null" json:"status"` + BkAgentId string `gorm:"index:idx_bk_agent_id;column:bk_agent_id;type:varchar(64);not null" json:"bk_agent_id"` // gse Agent当前运行状态码, -1:未知 0:初始安装 1:启动中 2:运行中 3:有损状态 4:繁忙状态 5:升级中 6:停止中 7:解除安装 AgentStatusCode int `gorm:"column:gse_agent_status_code;type:int(11);not null" json:"gse_agent_status_code"` // agent status 最后一次更新时间 AgentStatusUpdateTime time.Time `gorm:"column:agent_status_update_time;type:timestamp;default:1970-01-01 08:00:01" json:"agent_status_update_time"` - ConsumeTime time.Time `gorm:"column:consume_time;type:timestamp;default:1970-01-01 08:00:01" json:"consume_time"` // 消费时间 - UpdateTime time.Time `gorm:"column:update_time;type:timestamp;default:CURRENT_TIMESTAMP()" json:"update_time"` // 最后修改时间 - CreateTime time.Time `gorm:"column:create_time;type:timestamp;default:CURRENT_TIMESTAMP()" json:"create_time"` // 创建时间 + // 消费时间 + ConsumeTime time.Time `gorm:"column:consume_time;type:timestamp;default:1970-01-01 08:00:01" json:"consume_time"` + // 最后修改时间 + UpdateTime time.Time `gorm:"column:update_time;type:timestamp;default:CURRENT_TIMESTAMP()" json:"update_time"` + // 创建时间 + CreateTime time.Time `gorm:"column:create_time;type:timestamp;default:CURRENT_TIMESTAMP()" json:"create_time"` // foreiginKey:关联表的结构字段 references:当前表的结构字段 // SubStorages []TbRpStorageItem `gorm:"foreignKey:BkHostID;references:BkHostID"` } @@ -109,17 +126,17 @@ func ConvertOsTypeToHuman(osType string) string { } } -// TableName TODO +// TableName table name func (TbRpDetail) TableName() string { return TbRpDetailName() } -// TbRpDetailName TODO +// TbRpDetailName tbrp detail table name func TbRpDetailName() string { return "tb_rp_detail" } -// MatchDbmSpec 资源是否匹配dbm的规格 +// MatchDbmSpec whether the resource matches dbm specifications func (t TbRpDetail) MatchDbmSpec(spec dbmapi.DbmSpec) bool { logger.Info("spec:%+v", spec) logger.Info("cpu:%d,mem:%d,city:%s,disk:%s", t.CPUNum, t.DramCap, t.City, string(t.StorageDevice)) @@ -259,7 +276,7 @@ type BatchGetTbDetailResult struct { Data []TbRpDetail `json:"data"` } -// BatchGetSatisfiedByAssetIds 批量设置资源状态 +// BatchGetSatisfiedByAssetIds batch setting resource status func BatchGetSatisfiedByAssetIds(elements []BatchGetTbDetail, mode string) (result []BatchGetTbDetailResult, err error) { db := DB.Self.Begin() @@ -285,7 +302,7 @@ func BatchGetSatisfiedByAssetIds(elements []BatchGetTbDetail, mode string) (resu return } -// SetSatisfiedStatus 获取满足条件的的资源,并更新状态 +// SetSatisfiedStatus get resources that meet the conditions and update status func SetSatisfiedStatus(tx *gorm.DB, bkhostIds []int, status string) (result []TbRpDetail, err error) { err = tx.Exec("select * from tb_rp_detail where bk_host_id in (?) for update", bkhostIds).Error if err != nil { diff --git a/dbm-services/common/db-resource/internal/svr/apply/api.go b/dbm-services/common/db-resource/internal/svr/apply/api.go index 88156d420c..60fe75402c 100644 --- a/dbm-services/common/db-resource/internal/svr/apply/api.go +++ b/dbm-services/common/db-resource/internal/svr/apply/api.go @@ -78,6 +78,23 @@ type RequestInputParam struct { ActionInfo } +// BuildMessage build apply message +func (param RequestInputParam) BuildMessage() (msg string) { + var count int + groupMap := make(map[string]int) + groupCountMap := make(map[string]int) + for _, d := range param.Details { + groupMap[d.Affinity]++ + groupCountMap[d.Affinity] += d.Count + count += d.Count + } + msg = fmt.Sprintf("此次申请分%d组申请%d个机器\n", len(param.Details), count) + for affinity, count := range groupMap { + msg += fmt.Sprintf("按照亲和性%s申请的资源分组%d,总共包含机器数量%d\n", affinity, count, groupCountMap[affinity]) + } + return msg +} + // SortDetails 优先去匹配有明确需求的参数 func (param RequestInputParam) SortDetails() ([]ObjectDetail, error) { if len(param.Details) == 1 { @@ -172,36 +189,38 @@ func (param RequestInputParam) LockKey() string { } const ( - // SAME_SUBZONE_CROSS_SWTICH TODO + // SAME_SUBZONE_CROSS_SWTICH 同城同园区跨交换机跨机架 SAME_SUBZONE_CROSS_SWTICH = "SAME_SUBZONE_CROSS_SWTICH" - // SAME_SUBZONE TODO + // SAME_SUBZONE 同城同园区 SAME_SUBZONE = "SAME_SUBZONE" - // CROS_SUBZONE TODO + // CROS_SUBZONE 同城跨园区 CROS_SUBZONE = "CROS_SUBZONE" - // MAX_EACH_ZONE_EQUAL TODO + // MAX_EACH_ZONE_EQUAL 尽量每个zone分配数量相等 MAX_EACH_ZONE_EQUAL = "MAX_EACH_ZONE_EQUAL" // CROSS_RACK 跨机架 CROSS_RACK = "CROSS_RACK" - // NONE TODO + // NONE 无亲和性 NONE = "NONE" ) -// ObjectDetail TODO +// ObjectDetail 资源申请对象详情 +// 反亲和性 目前只有一种选项,当campus是空的时候,则此值生效 +// SAME_SUBZONE_CROSS_SWTICH: 同城同subzone跨交换机跨机架、 +// SAME_SUBZONE: 同城同subzone +// CROS_SUBZONE:同城跨subzone +// NONE: 无需亲和性处理 type ObjectDetail struct { - BkCloudId int `json:"bk_cloud_id"` - GroupMark string `json:"group_mark" binding:"required" ` // 资源组标记 - Labels map[string]string `json:"labels"` // 标签 + BkCloudId int `json:"bk_cloud_id"` + Hosts Hosts `json:"hosts"` // 主机id + GroupMark string `json:"group_mark" binding:"required" ` // 资源组标记 + Labels []string `json:"labels"` // 标签 // 通过机型规格 或者 资源规格描述来匹配资源 // 这两个条件是 || 关系 DeviceClass []string `json:"device_class"` // 机器类型 "IT5.8XLARGE128" "SA3.2XLARGE32" Spec meta.Spec `json:"spec"` // 规格描述 StorageSpecs []meta.DiskSpec `json:"storage_spec"` LocationSpec meta.LocationSpec `json:"location_spec"` // 地域区间 - // 反亲和性 目前只有一种选项,当campus是空的时候,则此值生效 - // SAME_SUBZONE_CROSS_SWTICH: 同城同subzone跨交换机跨机架、 - // SAME_SUBZONE: 同城同subzone - // CROS_SUBZONE:同城跨subzone - // NONE: 无需亲和性处理 + Affinity string `json:"affinity"` // Windows,Linux OsType string `json:"os_type"` @@ -209,6 +228,24 @@ type ObjectDetail struct { Count int `json:"count" binding:"required,min=1"` // 申请数量 } +// Hosts bk hosts +type Hosts []Host + +// GetBkHostIds get bk host ids +func (a Hosts) GetBkHostIds() []int { + var bkHostIds []int + for _, v := range a { + bkHostIds = append(bkHostIds, v.BkHostId) + } + return bkHostIds +} + +// Host bk host +type Host struct { + BkHostId int `json:"bk_host_id"` + IP string `json:"ip"` +} + // GetDiskMatchInfo get request disk message func (a *ObjectDetail) GetDiskMatchInfo() (message string) { if len(a.StorageSpecs) > 0 { diff --git a/dbm-services/common/db-resource/internal/svr/apply/apply.go b/dbm-services/common/db-resource/internal/svr/apply/apply.go index 58c2a45910..3f65977d93 100644 --- a/dbm-services/common/db-resource/internal/svr/apply/apply.go +++ b/dbm-services/common/db-resource/internal/svr/apply/apply.go @@ -36,6 +36,7 @@ type SearchContext struct { RsType string IntetionBkBizId int IdcCitys []string + SpecialHostIds []int } // CycleApply 循环匹配 @@ -68,6 +69,7 @@ func CycleApply(param RequestInputParam) (pickers []*PickerObject, err error) { RsType: param.ResourceType, ObjectDetail: &v, IdcCitys: idcCitys, + SpecialHostIds: v.Hosts.GetBkHostIds(), } if err = s.PickCheck(); err != nil { return pickers, err @@ -100,21 +102,18 @@ func RollBackAllInstanceUnused(ms []*PickerObject) { } func (o *SearchContext) pickBase(db *gorm.DB) { - db.Where("gse_agent_status_code = ? ", bk.GSE_AGENT_OK) - if o.BkCloudId <= 0 { - db.Where(" bk_cloud_id = ? and status = ? ", o.ObjectDetail.BkCloudId, model.Unused) - } else { - db.Where(" bk_cloud_id = ? and status = ? ", o.BkCloudId, model.Unused) + // 如果指定了特殊资源,就只查询这些资源 + if len(o.SpecialHostIds) > 0 { + db.Where("bk_host_id in (?) and status = ? ", o.SpecialHostIds, model.Unused) + return } - // os type - // Windows - // Liunx + db.Where(" bk_cloud_id = ? and status = ? and gse_agent_status_code = ? ", o.BkCloudId, model.Unused, bk.GSE_AGENT_OK) + // os type: Windows, Liunx osType := o.ObjectDetail.OsType if cmutil.IsEmpty(o.ObjectDetail.OsType) { osType = "Linux" } db.Where("os_type = ? ", osType) - // match os name like Windows Server 2012 if len(o.ObjectDetail.OsNames) > 0 { conditions := []clause.Expression{} @@ -162,8 +161,10 @@ func (o *SearchContext) pickBase(db *gorm.DB) { // PickCheck precheck func (o *SearchContext) PickCheck() (err error) { var count int64 - logger.Info("前置检查轮资源匹配") + if len(o.SpecialHostIds) > 0 { + return o.PickCheckSpecialBkhostIds() + } db := model.DB.Self.Table(model.TbRpDetailName()).Select("count(*)") o.pickBase(db) if err := db.Scan(&count).Error; err != nil { @@ -172,12 +173,61 @@ func (o *SearchContext) PickCheck() (err error) { } if int(count) < o.Count { - return errno.ErrResourceinsufficient.AddErr(fmt.Errorf("申请需求:%s\n\r资源池符合条件的资源总数:%d 小于申请的数量", o.GetMessage(), - count)) + return fmt.Errorf("申请需求:%s\n\r资源池符合条件的资源总数:%d 小于申请的数量", o.GetMessage(), count) + } + return nil +} + +// PickCheckSpecialBkhostIds 根据bkhostids取资源 +func (o *SearchContext) PickCheckSpecialBkhostIds() (err error) { + var rs []int + err = model.DB.Self.Table(model.TbRpDetailName()).Select("bk_host_id").Where( + "bk_host_id in (?) and status = ? and bk_cloud_id = ? ", + o.SpecialHostIds, model.Used, o.BkCloudId).Scan(&rs).Error + if err != nil { + logger.Error("query pre check count failed %s", err.Error()) + return errno.ErrDBQuery.AddErr(err) + } + if len(rs) != len(o.SpecialHostIds) { + emptyIps := []string{} + hostIpMap := lo.SliceToMap(o.Hosts, func(item Host) (int, string) { return item.BkHostId, item.IP }) + for hostid, ip := range hostIpMap { + if !lo.Contains(rs, hostid) { + emptyIps = append(emptyIps, ip) + } + } + return fmt.Errorf("指定ip申请资源,部分资源不存在:%v", emptyIps) } return nil } +// filterEmptyMountPointStorage 过滤没有挂载点的磁盘匹配需求 +func (o *SearchContext) filterEmptyMountPointStorage(items []model.TbRpDetail, + diskSpecs []meta.DiskSpec) (ts []model.TbRpDetail, err error) { + for _, ins := range items { + if err = ins.UnmarshalDiskInfo(); err != nil { + logger.Error("%s umarshal disk failed %s", ins.IP, err.Error()) + return nil, err + } + logger.Info("%v", ins.Storages) + noUseStorages := make(map[string]bk.DiskDetail) + smp := meta.GetDiskSpecMountPoints(o.StorageSpecs) + for mp, v := range ins.Storages { + if cmutil.ElementNotInArry(mp, smp) { + noUseStorages[mp] = v + } + } + logger.Info("nouse: %v", noUseStorages) + if matchNoMountPointStorage(diskSpecs, noUseStorages) { + ts = append(ts, ins) + } + } + if len(ts) == 0 { + return nil, errno.ErrResourceinsufficient.Add(fmt.Sprintf("匹配磁盘%s,的资源为 0", o.GetDiskMatchInfo())) + } + return ts, nil +} + // PickInstance match resource func (o *SearchContext) PickInstance() (picker *PickerObject, err error) { picker = NewPicker(o.Count, o.GroupMark) @@ -190,35 +240,20 @@ func (o *SearchContext) PickInstance() (picker *PickerObject, err error) { } // 过滤没有挂载点的磁盘匹配需求 logger.Info("storage spec %v", o.StorageSpecs) + diskSpecs := meta.GetEmptyDiskSpec(o.StorageSpecs) - if len(diskSpecs) > 0 { - ts := []model.TbRpDetail{} - for _, ins := range items { - if err = ins.UnmarshalDiskInfo(); err != nil { - logger.Error("%s umarshal disk failed %s", ins.IP, err.Error()) - return picker, err - } - logger.Info("%v", ins.Storages) - noUseStorages := make(map[string]bk.DiskDetail) - smp := meta.GetDiskSpecMountPoints(o.StorageSpecs) - for mp, v := range ins.Storages { - if cmutil.ElementNotInArry(mp, smp) { - noUseStorages[mp] = v - } - } - logger.Info("nouse: %v", noUseStorages) - if matchNoMountPointStorage(diskSpecs, noUseStorages) { - ts = append(ts, ins) - } - } - if len(ts) == 0 { - return picker, errno.ErrResourceinsufficient.Add(fmt.Sprintf("匹配磁盘%s,的资源为 0", o.GetDiskMatchInfo())) + if len(diskSpecs) > 0 && len(o.SpecialHostIds) == 0 { + items, err = o.filterEmptyMountPointStorage(items, diskSpecs) + if err != nil { + logger.Error("filter empty mount point storage failed %s", err.Error()) + return picker, err } - items = ts } + if err = o.PickInstanceBase(picker, items); err != nil { return nil, err } + if picker.PickerDone() { return picker, nil } @@ -230,12 +265,11 @@ func (o *SearchContext) PickInstance() (picker *PickerObject, err error) { // MatchLables match lables func (o *SearchContext) MatchLables(db *gorm.DB) { if len(o.Labels) > 0 { - for key, v := range o.Labels { - db.Where(" ( json_contains(label,json_object(?,?) )", key, v) - } - return + db.Where(model.JSONQuery("labels").JointOrContains(o.Labels)) + } else { + // 如果请求没有标签, 只能匹配没有标签的资源 + db.Where(" JSON_TYPE(label) = 'NULL' OR JSON_LENGTH(label) < 1 ") } - db.Where(" JSON_TYPE(label) = 'NULL' OR JSON_LENGTH(label) <= 1 ") } func matchNoMountPointStorage(spec []meta.DiskSpec, sinc map[string]bk.DiskDetail) bool { @@ -270,9 +304,16 @@ func diskDetailMatch(d bk.DiskDetail, s meta.DiskSpec) bool { return true } -// PickInstanceBase TODO +// PickInstanceBase pick instance base func (o *SearchContext) PickInstanceBase(picker *PickerObject, items []model.TbRpDetail) (err error) { logger.Info("the anti-affinity is %s", o.Affinity) + if len(o.SpecialHostIds) > 0 { + for _, v := range items { + picker.SatisfiedHostIds = append(picker.SatisfiedHostIds, v.BkCloudID) + } + picker.Count = len(o.SpecialHostIds) + return nil + } switch o.Affinity { case NONE: picker.PriorityElements, err = o.AnalysisResourcePriority(items, true) @@ -296,7 +337,7 @@ func (o *SearchContext) PickInstanceBase(picker *PickerObject, items []model.TbR return } -// MatchLocationSpec 匹配location参数 +// MatchLocationSpec match location parameter func (o *SearchContext) MatchLocationSpec(db *gorm.DB) { if o.LocationSpec.IsEmpty() { return @@ -317,7 +358,7 @@ func (o *SearchContext) MatchLocationSpec(db *gorm.DB) { } } -// MatchStorage 匹配存储参数 +// MatchStorage match storage parameters func (o *SearchContext) MatchStorage(db *gorm.DB) { if len(o.StorageSpecs) == 0 { return @@ -347,7 +388,7 @@ func isWindowsPath(path string) bool { return strings.Contains(path, "\\") } -// MatchSpec TODO +// MatchSpec match spec func (o *SearchContext) MatchSpec(db *gorm.DB) { if len(o.DeviceClass) > 0 { switch { diff --git a/dbm-services/common/db-resource/internal/svr/apply/core.go b/dbm-services/common/db-resource/internal/svr/apply/core.go index 35de15225a..1030e07ded 100644 --- a/dbm-services/common/db-resource/internal/svr/apply/core.go +++ b/dbm-services/common/db-resource/internal/svr/apply/core.go @@ -34,15 +34,14 @@ type subzone = string // PickerObject TODO type PickerObject struct { - Item string - Count int - PickDistrbute map[string]int - ExistSubZone []subzone // 已存在的园区 - SatisfiedHostIds []int - SelectedResources []*model.TbRpDetail - + Item string + Count int + PickDistrbute map[string]int + // 已存在的园区 + ExistSubZone []subzone + SatisfiedHostIds []int + // SelectedResources []*model.TbRpDetail // 待选择实例 - // PickeElements map[subzone][]InstanceObject // 具备优先级的待选实例列表 PriorityElements map[subzone]*PriorityQueue diff --git a/dbm-services/common/db-resource/internal/svr/apply/match_resource.go b/dbm-services/common/db-resource/internal/svr/apply/match_resource.go index d486fffadf..043b72086b 100644 --- a/dbm-services/common/db-resource/internal/svr/apply/match_resource.go +++ b/dbm-services/common/db-resource/internal/svr/apply/match_resource.go @@ -172,7 +172,6 @@ func (c *PickerObject) pickerOneByPriority(key string, cross_switch bool) bool { } c.ExistEquipmentIds = append(c.ExistEquipmentIds, v.Equipment) c.SatisfiedHostIds = append(c.SatisfiedHostIds, v.BkHostId) - c.SelectedResources = append(c.SelectedResources, v.InsDetail) c.ExistLinkNetdeviceIds = append(c.ExistLinkNetdeviceIds, v.LinkNetdeviceId...) c.PickDistrbute[key]++ return true