backup_helper.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package handler
  15. import (
  16. "fmt"
  17. "sort"
  18. "yunion.io/x/log"
  19. schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
  20. "yunion.io/x/onecloud/pkg/scheduler/core"
  21. )
  22. func transToBackupSchedResult(
  23. result *core.SchedResultItemList, preferMasterHost, preferBackupHost string, count int64, sid string,
  24. ) *schedapi.ScheduleOutput {
  25. // clean each result sched result item's count
  26. for _, item := range result.Data {
  27. item.Count = 0
  28. }
  29. apiResults := newBackupSchedResult(result, preferMasterHost, preferBackupHost, count, sid)
  30. return apiResults
  31. }
  32. func newBackupSchedResult(
  33. result *core.SchedResultItemList,
  34. preferMasterHost, preferBackupHost string,
  35. count int64,
  36. sid string,
  37. ) *schedapi.ScheduleOutput {
  38. ret := new(schedapi.ScheduleOutput)
  39. apiResults := make([]*schedapi.CandidateResource, 0)
  40. storageUsed := core.NewStorageUsed()
  41. var wireHostMap map[string]core.SchedResultItems
  42. for i := 0; i < int(count); i++ {
  43. log.V(10).Debugf("Select backup host from result: %s", result)
  44. target, err := getSchedBackupResult(result, preferMasterHost, preferBackupHost, sid, wireHostMap, storageUsed)
  45. if err != nil {
  46. er := &schedapi.CandidateResource{Error: err.Error()}
  47. apiResults = append(apiResults, er)
  48. continue
  49. }
  50. apiResults = append(apiResults, target)
  51. }
  52. ret.Candidates = apiResults
  53. return ret
  54. }
  55. func getSchedBackupResult(
  56. result *core.SchedResultItemList,
  57. preferMasterHost, preferBackupHost string,
  58. sid string, wireHostMap map[string]core.SchedResultItems,
  59. storageUsed *core.StorageUsed,
  60. ) (*schedapi.CandidateResource, error) {
  61. if wireHostMap == nil {
  62. wireHostMap = buildWireHostMap(result)
  63. } else {
  64. reviseWireHostMap(wireHostMap)
  65. }
  66. masterHost, backupHost := selectHosts(wireHostMap, preferMasterHost, preferBackupHost)
  67. if masterHost == nil {
  68. return nil, fmt.Errorf("Can't find master host %q", preferMasterHost)
  69. }
  70. if backupHost == nil {
  71. return nil, fmt.Errorf("Can't find backup host %q by master %q", preferBackupHost, masterHost.ID)
  72. }
  73. markHostUsed(masterHost)
  74. markHostUsed(backupHost)
  75. ret := masterHost.ToCandidateResource(storageUsed)
  76. ret.BackupCandidate = backupHost.ToCandidateResource(storageUsed)
  77. ret.SessionId = sid
  78. ret.BackupCandidate.SessionId = sid
  79. return ret, nil
  80. }
  81. func buildWireHostMap(result *core.SchedResultItemList) map[string]core.SchedResultItems {
  82. sort.Sort(sort.Reverse(result.Data))
  83. wireHostMap := make(map[string]core.SchedResultItems)
  84. for i := 0; i < len(result.Data); i++ {
  85. networks := result.Data[i].Candidater.Getter().Networks()
  86. for j := 0; j < len(networks); j++ {
  87. if hosts, ok := wireHostMap[networks[j].WireId]; ok {
  88. if hostInResultItemsIndex(result.Data[i].ID, hosts) < 0 {
  89. wireHostMap[networks[j].WireId] = append(hosts, result.Data[i])
  90. }
  91. } else {
  92. wireHostMap[networks[j].WireId] = core.SchedResultItems{result.Data[i]}
  93. }
  94. }
  95. }
  96. return wireHostMap
  97. }
  98. func reviseWireHostMap(wireHostMap map[string]core.SchedResultItems) {
  99. for _, hosts := range wireHostMap {
  100. sort.Sort(sort.Reverse(hosts))
  101. }
  102. }
  103. func markHostUsed(host *core.SchedResultItem) {
  104. host.Count++
  105. host.Capacity--
  106. }
  107. func hostInResultItemsIndex(hostId string, hosts core.SchedResultItems) int {
  108. for i := 0; i < len(hosts); i++ {
  109. if hosts[i].ID == hostId {
  110. return i
  111. }
  112. }
  113. return -1
  114. }
  115. func selectHosts(
  116. wireHostMap map[string]core.SchedResultItems, preferMasterHost, preferBackupHost string,
  117. ) (*core.SchedResultItem, *core.SchedResultItem) {
  118. var scroe int64
  119. var masterIdx, backupIdx int
  120. var selectedWireId string
  121. for wireId, hosts := range wireHostMap {
  122. masterIdx, backupIdx = -1, -1
  123. if len(hosts) < 2 {
  124. continue
  125. }
  126. if len(preferMasterHost) > 0 {
  127. if masterIdx = hostInResultItemsIndex(preferMasterHost, hosts); masterIdx < 0 {
  128. continue
  129. }
  130. }
  131. if len(preferBackupHost) > 0 {
  132. if backupIdx = hostInResultItemsIndex(preferBackupHost, hosts); backupIdx < 0 {
  133. continue
  134. }
  135. }
  136. // select master host index
  137. if masterIdx < 0 {
  138. for i := 0; i < len(hosts); i++ {
  139. if hosts[i].ID != preferBackupHost {
  140. masterIdx = i
  141. }
  142. }
  143. }
  144. if hosts[masterIdx].Capacity <= 0 {
  145. if len(preferMasterHost) > 0 {
  146. // in case prefer master host capacity isn't enough
  147. break
  148. } else {
  149. continue
  150. }
  151. }
  152. // select backup host index
  153. if backupIdx < 0 {
  154. for i := 0; i < len(hosts); i++ {
  155. if i != masterIdx {
  156. backupIdx = i
  157. }
  158. }
  159. }
  160. if hosts[backupIdx].Capacity <= 0 {
  161. if len(preferBackupHost) > 0 {
  162. // in case perfer backup host capacity isn't enough
  163. break
  164. } else {
  165. continue
  166. }
  167. }
  168. // the highest total score wins
  169. curScore := hosts[masterIdx].Capacity + hosts[backupIdx].Capacity
  170. if curScore > scroe {
  171. selectedWireId = wireId
  172. scroe = curScore
  173. }
  174. }
  175. if len(selectedWireId) == 0 {
  176. return nil, nil
  177. }
  178. return wireHostMap[selectedWireId][masterIdx], wireHostMap[selectedWireId][backupIdx]
  179. }