@@ -14,6 +14,8 @@ package apply
1414import (
1515 "fmt"
1616 "path"
17+ "slices"
18+ "sort"
1719 "strings"
1820
1921 "dbm-services/common/db-resource/internal/config"
@@ -32,14 +34,195 @@ import (
3234// SearchContext TODO
3335type SearchContext struct {
3436 * ObjectDetail
35- RsType string
36- IntetionBkBizId int
37- IdcCitys []string
38- SpecialHostIds []int
37+ RsType string
38+ IntetionBkBizId int
39+ IdcCitys []string
40+ SpecialSubZoneIds []string
41+ SpecialHostIds []int
42+ }
43+
44+ // applyGroupsInSameLocaltion apply groups in same location
45+ func applyGroupsInSameLocaltion (param RequestInputParam ) (pickers []* PickerObject , err error ) {
46+ var picker * PickerObject
47+ resourceReqList , err := param .SortDetails ()
48+ if err != nil {
49+ logger .Error ("对请求参数排序失败%v" , err )
50+ return nil , err
51+ }
52+ var idcCitys []string
53+ v := resourceReqList [0 ]
54+ idcCitys , err = getLogicIdcCitys (v )
55+ if err != nil {
56+ logger .Error ("get logic citys failed %s" , err .Error ())
57+ return pickers , err
58+ }
59+ // 根据请求,按照请求的分组,分别计算出每个分组的匹配的园区的优先级
60+ groupcampusNice , err := getGroupcampusNice (param , resourceReqList , idcCitys )
61+ if err != nil {
62+ logger .Error ("order campus nice failed %s" , err .Error ())
63+ return pickers , err
64+ }
65+ // 因为整个大的分组在需要分配机器在同一个园区,这里合并所有的分组的园区优先级
66+ // 合并之后再次排序,返回整体的园区优先级
67+ subzoneIds := sortgroupcampusNice (groupcampusNice )
68+ logger .Info ("sort subzone ids %v" , subzoneIds )
69+ if len (subzoneIds ) == 0 {
70+ return pickers , errno .ErrResourceinsufficient .Add ("没有符合条件的资源" )
71+ }
72+ for _ , subzoneId := range subzoneIds {
73+ pickers = []* PickerObject {}
74+ for _ , v := range resourceReqList {
75+ s := & SearchContext {
76+ IntetionBkBizId : param .ForbizId ,
77+ RsType : param .ResourceType ,
78+ ObjectDetail : & v ,
79+ IdcCitys : idcCitys ,
80+ SpecialHostIds : v .Hosts .GetBkHostIds (),
81+ SpecialSubZoneIds : []string {subzoneId },
82+ }
83+ if err = s .PickCheck (); err != nil {
84+ logger .Error ("挑选资源失败:%v" , err )
85+ goto RollBack
86+ }
87+ // 挑选符合需求的资源
88+ picker , err = s .PickInstance ()
89+ if err != nil {
90+ logger .Error ("挑选资源失败:%v" , err )
91+ goto RollBack
92+ }
93+ // Debug Print Log 挑选实例分区的情况
94+ picker .DebugDistrubuteLog ()
95+ // 更新挑选到的资源的状态为Preselected
96+ if updateErr := picker .PreselectedSatisfiedInstance (); updateErr != nil {
97+ goto RollBack
98+ }
99+ // 追加到挑选好的分组
100+ pickers = append (pickers , picker )
101+ }
102+ return pickers , nil
103+ RollBack:
104+ RollBackAllInstanceUnused (pickers )
105+ }
106+ return pickers , err
107+ }
108+ func getGroupcampusNice (param RequestInputParam , resourceReqList []ObjectDetail ,
109+ idcCitys []string ) (groupcampusNice map [string ]map [string ]* SubZoneSummary ,
110+ err error ) {
111+ groupcampusNice = make (map [string ]map [string ]* SubZoneSummary )
112+ for _ , v := range resourceReqList {
113+ s := & SearchContext {
114+ IntetionBkBizId : param .ForbizId ,
115+ RsType : param .ResourceType ,
116+ ObjectDetail : & v ,
117+ IdcCitys : idcCitys ,
118+ SpecialHostIds : v .Hosts .GetBkHostIds (),
119+ }
120+ var items []model.TbRpDetail
121+ db := model .DB .Self .Table (model .TbRpDetailName ())
122+ s .pickBase (db )
123+ if err = db .Scan (& items ).Error ; err != nil {
124+ logger .Error ("query failed %s" , err .Error ())
125+ return nil , errno .ErrDBQuery .AddErr (err )
126+ }
127+ campusSummarys := make (map [string ]* SubZoneSummary )
128+ for _ , item := range items {
129+ if _ , ok := campusSummarys [item .SubZoneID ]; ! ok {
130+ campusSummarys [item .SubZoneID ] = & SubZoneSummary {
131+ Count : 1 ,
132+ EquipmentIdList : []string {item .RackID },
133+ LinkNetdeviceList : strings .Split (item .NetDeviceID , "," ),
134+ RequestCount : v .Count ,
135+ }
136+ } else {
137+ campusSummarys [item .SubZoneID ].Count ++
138+ campusSummarys [item .SubZoneID ].EquipmentIdList = append (campusSummarys [item .SubZoneID ].EquipmentIdList , item .RackID )
139+ campusSummarys [item .SubZoneID ].LinkNetdeviceList = append (campusSummarys [item .SubZoneID ].LinkNetdeviceList ,
140+ strings .Split (item .NetDeviceID , "," )... )
141+ }
142+ }
143+ groupcampusNice [v .GroupMark ] = campusSummarys
144+ }
145+ return groupcampusNice , nil
146+ }
147+
148+ func sortgroupcampusNice (gpms map [string ]map [string ]* SubZoneSummary ) []string {
149+ subzones := []string {}
150+ gcnsMap := make (map [string ]* CampusNice )
151+ var cns []CampusNice
152+ for _ , campuseSummary := range gpms {
153+ for campus := range campuseSummary {
154+ equipmentIdList := lo .Uniq (campuseSummary [campus ].EquipmentIdList )
155+ linkNetdeviceList := lo .Uniq (campuseSummary [campus ].LinkNetdeviceList )
156+ count := campuseSummary [campus ].Count
157+ requestCount := campuseSummary [campus ].RequestCount
158+ if count >= requestCount && len (equipmentIdList ) >= requestCount &&
159+ len (linkNetdeviceList ) >= requestCount {
160+ cns = append (cns , CampusNice {
161+ Campus : campus ,
162+ Count : int64 (count + len (equipmentIdList )* (1 + PriorityP3 ) + len (linkNetdeviceList )* (PriorityP3 + 1 )),
163+ })
164+ }
165+ }
166+ }
167+
168+ for _ , cn := range cns {
169+ if _ , ok := gcnsMap [cn .Campus ]; ! ok {
170+ gcnsMap [cn .Campus ] = & CampusNice {
171+ Campus : cn .Campus ,
172+ Count : cn .Count ,
173+ }
174+ } else {
175+ gcnsMap [cn .Campus ].Count += cn .Count
176+ }
177+ }
178+ var gcns []CampusNice
179+ for key := range gcnsMap {
180+ gcns = append (gcns , CampusNice {
181+ Campus : key ,
182+ Count : gcnsMap [key ].Count ,
183+ })
184+ }
185+ sort .Sort (CampusWrapper {gcns , func (p , q * CampusNice ) bool {
186+ return q .Count < p .Count
187+ }})
188+
189+ for _ , v := range gcns {
190+ subzones = append (subzones , v .Campus )
191+ }
192+ return subzones
193+ }
194+
195+ // SubZoneSummary subzone summary
196+ type SubZoneSummary struct {
197+ RequestCount int
198+ Count int
199+ EquipmentIdList []string // 存在的设备Id
200+ LinkNetdeviceList []string // 存在的网卡Id
201+ }
202+
203+ func getLogicIdcCitys (v ObjectDetail ) (idcCitys []string , err error ) {
204+ if config .AppConfig .RunMode == "dev" {
205+ idcCitys = []string {}
206+ } else if cmutil .ElementNotInArry (v .Affinity , []string {CROSS_RACK , NONE }) ||
207+ lo .IsNotEmpty (v .LocationSpec .City ) ||
208+ len (v .Hosts ) > 0 {
209+ idcCitys , err = dbmapi .GetIdcCityByLogicCity (v .LocationSpec .City )
210+ if err != nil {
211+ logger .Error ("request real citys by logic city %s from bkdbm api failed:%v" , v .LocationSpec .City , err )
212+ return []string {}, err
213+ }
214+ }
215+ return idcCitys , nil
39216}
40217
41218// CycleApply 循环匹配
42219func CycleApply (param RequestInputParam ) (pickers []* PickerObject , err error ) {
220+ // 多个请求参数分组在同一个地方
221+ affinitys := lo .Uniq (param .GetAllAffinitys ())
222+ if param .GroupsInSameLocation && len (param .Details ) > 1 && len (affinitys ) == 1 &&
223+ slices .Contains ([]string {SAME_SUBZONE , SAME_SUBZONE_CROSS_SWTICH }, affinitys [0 ]) {
224+ return applyGroupsInSameLocaltion (param )
225+ }
43226 resourceReqList , err := param .SortDetails ()
44227 if err != nil {
45228 logger .Error ("对请求参数排序失败%v" , err )
@@ -52,19 +235,11 @@ func CycleApply(param RequestInputParam) (pickers []*PickerObject, err error) {
52235 if v .Affinity == "" || v .Count <= 1 {
53236 v .Affinity = NONE
54237 }
55- var idcCitys []string
56- if config .AppConfig .RunMode == "dev" {
57- idcCitys = []string {}
58- } else if cmutil .ElementNotInArry (v .Affinity , []string {CROSS_RACK , NONE }) ||
59- lo .IsNotEmpty (v .LocationSpec .City ) ||
60- len (v .Hosts ) > 0 {
61- idcCitys , err = dbmapi .GetIdcCityByLogicCity (v .LocationSpec .City )
62- if err != nil {
63- logger .Error ("request real citys by logic city %s from bkdbm api failed:%v" , v .LocationSpec .City , err )
64- return pickers , err
65- }
238+ idcCitys , err := getLogicIdcCitys (v )
239+ if err != nil {
240+ logger .Error ("get logic citys failed %s" , err .Error ())
241+ return pickers , err
66242 }
67-
68243 s := & SearchContext {
69244 IntetionBkBizId : param .ForbizId ,
70245 RsType : param .ResourceType ,
@@ -270,7 +445,7 @@ func (o *SearchContext) MatchIntetionBkBiz(db *gorm.DB) {
270445 // 如果没有指定专属业务,就表示只能选用公共的资源
271446 // 不能匹配打了业务标签的资源
272447 if o .IntetionBkBizId <= 0 {
273- db .Where ("dedicated_biz == 0" )
448+ db .Where ("dedicated_biz = 0" )
274449 } else {
275450 db .Where ("dedicated_biz in (?)" , []int {0 , o .IntetionBkBizId })
276451 }
@@ -281,7 +456,7 @@ func (o *SearchContext) MatchRsType(db *gorm.DB) {
281456 // 如果没有指定资源类型,表示只能选择无资源类型标签的资源
282457 // 没有资源类型标签的资源可以被所有其他类型使用
283458 if lo .IsEmpty (o .RsType ) {
284- db .Where ("rs_type == 'PUBLIC' " )
459+ db .Where ("rs_type = 'PUBLIC' " )
285460 } else {
286461 db .Where ("rs_type in (?)" , []string {"PUBLIC" , o .RsType })
287462 }
@@ -345,12 +520,15 @@ func (o *SearchContext) MatchLocationSpec(db *gorm.DB) {
345520 db = db .Where ("city = ? " , o .LocationSpec .City )
346521 }
347522 if o .LocationSpec .SubZoneIsEmpty () {
523+ if len (o .SpecialSubZoneIds ) > 0 {
524+ db .Where ("sub_zone_id in (?)" , o .SpecialSubZoneIds )
525+ }
348526 return
349527 }
350528 if o .LocationSpec .IncludeOrExclude {
351- db .Where ("sub_zone_id in ? " , o .LocationSpec .SubZoneIds )
529+ db .Where ("sub_zone_id in (?) " , o .LocationSpec .SubZoneIds )
352530 } else {
353- db .Where ("sub_zone_id not in ? " , o .LocationSpec .SubZoneIds )
531+ db .Where ("sub_zone_id not in (?) " , o .LocationSpec .SubZoneIds )
354532 }
355533}
356534
0 commit comments