prepare.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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 test
  15. import (
  16. "context"
  17. "fmt"
  18. "github.com/golang/mock/gomock"
  19. "yunion.io/x/pkg/tristate"
  20. "yunion.io/x/pkg/util/netutils"
  21. "yunion.io/x/pkg/util/sets"
  22. "yunion.io/x/onecloud/pkg/apis/compute"
  23. computeapi "yunion.io/x/onecloud/pkg/apis/compute"
  24. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  25. "yunion.io/x/onecloud/pkg/compute/models"
  26. pre "yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates"
  27. _ "yunion.io/x/onecloud/pkg/scheduler/algorithmprovider"
  28. "yunion.io/x/onecloud/pkg/scheduler/api"
  29. "yunion.io/x/onecloud/pkg/scheduler/core"
  30. "yunion.io/x/onecloud/pkg/scheduler/data_manager/sku"
  31. "yunion.io/x/onecloud/pkg/scheduler/factory"
  32. schmodels "yunion.io/x/onecloud/pkg/scheduler/models"
  33. "yunion.io/x/onecloud/pkg/scheduler/test/mock"
  34. )
  35. type sPredicateName string
  36. var (
  37. HostStatus sPredicateName = "a-GuestHostStatusFilter"
  38. Hypervisor sPredicateName = "b-GuestHypervisorFilter"
  39. Migrate sPredicateName = "d-GuestMigrateFilter"
  40. Domain sPredicateName = "e-GuestDomainFilter"
  41. Image sPredicateName = "e-GuestImageFilter"
  42. CPU sPredicateName = "g-GuestCPUFilter"
  43. Memory sPredicateName = "h-GuestMemoryFilter"
  44. Storage sPredicateName = "i-GuestStorageFilter"
  45. //Network sPredicateName = "j-GuestNetworkFilter"
  46. IsolateDevice sPredicateName = "k-GuestIsolatedDeviceFilter"
  47. ResourceType sPredicateName = "l-GuestResourceTypeFilter"
  48. ServerSku sPredicateName = "n-ServerSkuFilter"
  49. // scheudle tag predicate, need db operator for now
  50. HostSchedtag sPredicateName = "c-GuestAggregateFilter"
  51. DiskSchedtag sPredicateName = "m-GuestDiskschedtagFilter"
  52. NetworkSchedtag sPredicateName = "o-GuestNetschedtagFilter"
  53. // quota
  54. Quota sPredicateName = "z-QuotaFilter"
  55. basePredicateNames = []sPredicateName{
  56. HostStatus, Hypervisor, Migrate, Domain, Image, CPU, Memory, Storage,
  57. IsolateDevice, ResourceType, ServerSku,
  58. }
  59. )
  60. var (
  61. GlobalDoamin = "default"
  62. GlobalProject = "default"
  63. GlobalZone = buildZone("default", "Default")
  64. GlobalCloudregion = buildCloudregion("default", "Default", "")
  65. GlobalWire = "default"
  66. GlobaleVPC = "default"
  67. )
  68. func buildCandidate(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandidater {
  69. cn := mock.NewMockCandidater(ctrl)
  70. getter := buildGetter(ctrl, param)
  71. cn.EXPECT().Getter().AnyTimes().Return(getter)
  72. cn.EXPECT().IndexKey().AnyTimes().Return(getter.Id())
  73. cn.EXPECT().GetResourceType().AnyTimes().Return(getter.ResourceType())
  74. cn.EXPECT().AllocCpuNumaPin(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(nil)
  75. return cn
  76. }
  77. type sGetterParams struct {
  78. HostId string
  79. HostName string
  80. IsPublic *bool
  81. Domain string
  82. PublicScope string
  83. Zone *models.SZone
  84. CloudRegion *models.SCloudregion
  85. CloudProvider *models.SCloudprovider
  86. HostType string
  87. Storages []*api.CandidateStorage
  88. Networks []*api.CandidateNetwork
  89. OvnCapable *bool
  90. Status string
  91. HostStatus string
  92. Enabled *bool
  93. ResourceType string
  94. TotalCPUCount int64
  95. FreeCPUCount int64
  96. TotalMemorySize int64
  97. FreeMemorySize int64
  98. FreeStorageSizeAnyType int64
  99. QuotaKeys *models.SComputeResourceKeys
  100. FreeGroupCount int
  101. Skus []string
  102. }
  103. func buildGetter(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandidatePropertyGetter {
  104. cg := mock.NewMockCandidatePropertyGetter(ctrl)
  105. cg.EXPECT().Id().AnyTimes().Return(param.HostId)
  106. cg.EXPECT().Name().AnyTimes().Return(param.HostName)
  107. cg.EXPECT().Zone().AnyTimes().Return(param.Zone)
  108. if param.IsPublic == nil {
  109. cg.EXPECT().IsPublic().AnyTimes().Return(true)
  110. } else {
  111. cg.EXPECT().IsPublic().AnyTimes().Return(*param.IsPublic)
  112. }
  113. if param.Enabled == nil {
  114. cg.EXPECT().Enabled().AnyTimes().Return(true)
  115. } else {
  116. cg.EXPECT().Enabled().AnyTimes().Return(*param.Enabled)
  117. }
  118. cg.EXPECT().DomainId().AnyTimes().Return(param.Domain)
  119. cg.EXPECT().PublicScope().AnyTimes().Return(param.PublicScope)
  120. cg.EXPECT().Region().AnyTimes().Return(param.CloudRegion)
  121. cg.EXPECT().Cloudprovider().AnyTimes().Return(param.CloudProvider)
  122. cg.EXPECT().HostType().AnyTimes().Return(param.HostType)
  123. cg.EXPECT().Storages().AnyTimes().Return(param.Storages)
  124. cg.EXPECT().Networks().AnyTimes().Return(param.Networks)
  125. cg.EXPECT().Sku(gomock.Any()).AnyTimes().DoAndReturn(func(instanceType string) *sku.ServerSku {
  126. for _, t := range param.Skus {
  127. if t != instanceType {
  128. continue
  129. }
  130. return &sku.ServerSku{
  131. Id: fmt.Sprintf("%s-%s", param.Zone.Id, instanceType),
  132. ZoneId: param.Zone.Id,
  133. }
  134. }
  135. return nil
  136. })
  137. if param.OvnCapable == nil {
  138. cg.EXPECT().OvnCapable().AnyTimes().Return(false)
  139. } else {
  140. cg.EXPECT().OvnCapable().AnyTimes().Return(*param.OvnCapable)
  141. }
  142. if len(param.Status) == 0 {
  143. cg.EXPECT().Status().AnyTimes().Return(computeapi.HOST_HEALTH_STATUS_RUNNING)
  144. } else {
  145. cg.EXPECT().Status().AnyTimes().Return(param.Status)
  146. }
  147. if len(param.HostStatus) == 0 {
  148. cg.EXPECT().HostStatus().AnyTimes().Return(computeapi.HOST_ONLINE)
  149. } else {
  150. cg.EXPECT().HostStatus().AnyTimes().Return(param.HostStatus)
  151. }
  152. if len(param.ResourceType) == 0 {
  153. cg.EXPECT().ResourceType().AnyTimes().Return(computeapi.HostResourceTypeDefault)
  154. } else {
  155. cg.EXPECT().ResourceType().AnyTimes().Return(param.ResourceType)
  156. }
  157. cg.EXPECT().TotalCPUCount(gomock.Any()).AnyTimes().Return(param.TotalCPUCount)
  158. cg.EXPECT().FreeCPUCount(gomock.Any()).AnyTimes().Return(param.FreeCPUCount)
  159. cg.EXPECT().TotalMemorySize(gomock.Any()).AnyTimes().Return(param.TotalMemorySize)
  160. cg.EXPECT().FreeMemorySize(gomock.Any()).AnyTimes().Return(param.FreeMemorySize)
  161. cg.EXPECT().GetFreeCpuNuma().AnyTimes().Return(nil)
  162. cg.EXPECT().GetFreeStorageSizeOfType(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(param.FreeStorageSizeAnyType, int64(0), nil)
  163. if param.QuotaKeys != nil {
  164. cg.EXPECT().GetQuotaKeys(gomock.Any()).AnyTimes().Return(param.QuotaKeys)
  165. }
  166. cg.EXPECT().GetFreeGroupCount(gomock.Any()).AnyTimes().Return(param.FreeGroupCount, nil)
  167. cg.EXPECT().GetPendingUsage().AnyTimes().Return(&schmodels.SPendingUsage{
  168. NetUsage: schmodels.NewResourcePendingUsage(map[string]int{}),
  169. })
  170. return cg
  171. }
  172. func buildScheduler(ctrl *gomock.Controller, networkNicCount map[string]int, predicates ...sPredicateName) core.Scheduler {
  173. pres := sets.NewString()
  174. for _, pre := range predicates {
  175. pres.Insert(string(pre))
  176. }
  177. algorithmProvider, _ := factory.GetAlgorithmProvider(factory.DefaultProvider)
  178. mockScheduler := mock.NewMockScheduler(ctrl)
  179. mockScheduler.EXPECT().BeforePredicate().AnyTimes().Return(nil)
  180. networkNicGetter := mock.NewMockINetworkNicCountGetter(ctrl)
  181. networkNicGetter.EXPECT().GetTotalNicCount(gomock.AssignableToTypeOf([]string{})).AnyTimes().DoAndReturn(func(netIds []string) (map[string]int, error) {
  182. return networkNicCount, nil
  183. })
  184. mockScheduler.EXPECT().Predicates().AnyTimes().DoAndReturn(func() (map[string]core.FitPredicate, error) {
  185. ret, err := factory.GetPredicates(pres)
  186. if err != nil {
  187. return nil, err
  188. }
  189. if networkNicGetter == nil {
  190. fmt.Printf("networkNicGetter is nil")
  191. }
  192. ret["j-GuestNetworkFilter"] = pre.NewNetworkPredicate().WithNetworkCountGetter(networkNicGetter)
  193. return ret, nil
  194. })
  195. mockScheduler.EXPECT().PriorityConfigs().AnyTimes().DoAndReturn(func() ([]core.PriorityConfig, error) {
  196. return factory.GetPriorityConfigs(algorithmProvider.PriorityKeys)
  197. })
  198. return mockScheduler
  199. }
  200. func buildZone(id, name string) *models.SZone {
  201. zone := &models.SZone{}
  202. zone.Id = id
  203. zone.Name = name
  204. zone.Status = "enable"
  205. return zone
  206. }
  207. func buildCloudregion(id, name, provider string) *models.SCloudregion {
  208. if len(provider) == 0 {
  209. provider = computeapi.CLOUD_PROVIDER_ONECLOUD
  210. }
  211. return &models.SCloudregion{
  212. SEnabledStatusStandaloneResourceBase: db.SEnabledStatusStandaloneResourceBase{
  213. SStatusStandaloneResourceBase: db.SStatusStandaloneResourceBase{
  214. SStandaloneResourceBase: db.SStandaloneResourceBase{
  215. SStandaloneAnonResourceBase: db.SStandaloneAnonResourceBase{
  216. Id: id,
  217. },
  218. Name: name,
  219. },
  220. SStatusResourceBase: db.SStatusResourceBase{
  221. Status: "inservice",
  222. },
  223. },
  224. SEnabledResourceBase: db.SEnabledResourceBase{
  225. Enabled: "true",
  226. },
  227. },
  228. Provider: provider,
  229. }
  230. }
  231. func buildStorage(id, name string, capacity int64) *api.CandidateStorage {
  232. storage := &models.SStorage{}
  233. storage.Id, storage.Name = id, name
  234. storage.DomainId = GlobalDoamin
  235. storage.IsPublic = true
  236. storage.PublicScope = "system"
  237. storage.Status = computeapi.STORAGE_ONLINE
  238. storage.Enabled = "true"
  239. storage.ZoneId = GlobalZone.GetId()
  240. storage.Capacity = capacity
  241. storage.StorageType = computeapi.STORAGE_LOCAL
  242. storage.MediumType = computeapi.DISK_TYPE_ROTATE
  243. storage.Cmtbound = 1.0
  244. storage.IsSysDiskStore = "true"
  245. return &api.CandidateStorage{
  246. SStorage: storage,
  247. }
  248. }
  249. func buildNetwork(id, name string, cidr string) *api.CandidateNetwork {
  250. network := &models.SNetwork{}
  251. network.Id, network.Name = id, name
  252. network.Status = computeapi.NETWORK_STATUS_AVAILABLE
  253. network.DomainId = GlobalDoamin
  254. network.ProjectId = GlobalProject
  255. network.WireId = GlobalWire
  256. network.ServerType = computeapi.NETWORK_TYPE_GUEST
  257. prefix, err := netutils.NewIPV4Prefix(cidr)
  258. if err == nil {
  259. network.GuestIpMask = prefix.MaskLen
  260. ipRange := prefix.ToIPRange()
  261. network.GuestIpStart = ipRange.StartIp().String()
  262. network.GuestIpEnd = ipRange.EndIp().String()
  263. }
  264. return &api.CandidateNetwork{
  265. SNetwork: network,
  266. VpcId: GlobaleVPC,
  267. }
  268. }
  269. func buildInstanceGroup(id string, granularity int, force bool) *models.SGroup {
  270. group := &models.SGroup{}
  271. group.Id = id
  272. group.Status = "ready"
  273. group.DomainId = GlobalDoamin
  274. group.ProjectId = GlobalProject
  275. group.Granularity = granularity
  276. group.ForceDispersion = tristate.NewFromBool(force)
  277. return nil
  278. }
  279. func preSchedule(info *api.SchedInfo, candidates []core.Candidater, isForcast bool) (context.Context, *core.Unit, []core.Candidater, core.IResultHelper) {
  280. resultHelper := core.SResultHelperFunc(core.ResultHelp)
  281. if isForcast {
  282. resultHelper = core.SResultHelperFunc(core.ResultHelpForForcast)
  283. info.Suggestion = true
  284. info.IsSuggestion = true
  285. info.SuggestionAll = true
  286. info.ShowSuggestionDetails = true
  287. info.SuggestionLimit = 100
  288. }
  289. return context.Background(), core.NewScheduleUnit(info, nil), candidates, resultHelper
  290. }
  291. func deepCopy(info *api.SchedInfo) *api.SchedInfo {
  292. serverConfigs := *info.ServerConfigs
  293. // disks
  294. disks := make([]*compute.DiskConfig, len(info.Disks))
  295. for i := range disks {
  296. disk := *info.Disks[i]
  297. disks[i] = &disk
  298. }
  299. // network
  300. networks := make([]*compute.NetworkConfig, len(info.Networks))
  301. for i := range networks {
  302. network := *info.Networks[i]
  303. networks[i] = &network
  304. }
  305. // baremetal_disk_config
  306. bareConfigs := make([]*compute.BaremetalDiskConfig, len(info.BaremetalDiskConfigs))
  307. for i := range bareConfigs {
  308. bareConfig := *info.BaremetalDiskConfigs[i]
  309. bareConfigs[i] = &bareConfig
  310. }
  311. // instancegroup
  312. instancegroupIds := make([]string, len(info.InstanceGroupIds))
  313. for i := range instancegroupIds {
  314. instancegroupIds[i] = info.InstanceGroupIds[i]
  315. }
  316. serverConfigs.Disks = disks
  317. serverConfigs.Networks = networks
  318. serverConfigs.BaremetalDiskConfigs = bareConfigs
  319. serverConfig := info.ServerConfig
  320. serverConfig.ServerConfigs = &serverConfigs
  321. scheduInput := *info.ScheduleInput
  322. scheduInput.ServerConfig = serverConfig
  323. copyInfo := *info
  324. copyInfo.ScheduleInput = &scheduInput
  325. preferCandidates := make([]string, len(info.PreferCandidates))
  326. for i := range preferCandidates {
  327. preferCandidates[i] = info.PreferCandidates[i]
  328. }
  329. instanceGroupDetail := make(map[string]*models.SGroup, len(info.InstanceGroupsDetail))
  330. for k, v := range info.InstanceGroupsDetail {
  331. // v only read
  332. instanceGroupDetail[k] = v
  333. }
  334. copyInfo.PreferCandidates = preferCandidates
  335. copyInfo.InstanceGroupsDetail = instanceGroupDetail
  336. return &copyInfo
  337. }