mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-07 22:24:32 +08:00
362 lines
12 KiB
Go
362 lines
12 KiB
Go
// Copyright 2019 Yunion
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
|
|
"yunion.io/x/pkg/tristate"
|
|
"yunion.io/x/pkg/util/netutils"
|
|
"yunion.io/x/pkg/util/sets"
|
|
|
|
"yunion.io/x/onecloud/pkg/apis/compute"
|
|
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
|
"yunion.io/x/onecloud/pkg/compute/models"
|
|
pre "yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates"
|
|
_ "yunion.io/x/onecloud/pkg/scheduler/algorithmprovider"
|
|
"yunion.io/x/onecloud/pkg/scheduler/api"
|
|
"yunion.io/x/onecloud/pkg/scheduler/core"
|
|
"yunion.io/x/onecloud/pkg/scheduler/data_manager/sku"
|
|
"yunion.io/x/onecloud/pkg/scheduler/factory"
|
|
schmodels "yunion.io/x/onecloud/pkg/scheduler/models"
|
|
"yunion.io/x/onecloud/pkg/scheduler/test/mock"
|
|
)
|
|
|
|
type sPredicateName string
|
|
|
|
var (
|
|
HostStatus sPredicateName = "a-GuestHostStatusFilter"
|
|
Hypervisor sPredicateName = "b-GuestHypervisorFilter"
|
|
Migrate sPredicateName = "d-GuestMigrateFilter"
|
|
Domain sPredicateName = "e-GuestDomainFilter"
|
|
Image sPredicateName = "e-GuestImageFilter"
|
|
CPU sPredicateName = "g-GuestCPUFilter"
|
|
Memory sPredicateName = "h-GuestMemoryFilter"
|
|
Storage sPredicateName = "i-GuestStorageFilter"
|
|
//Network sPredicateName = "j-GuestNetworkFilter"
|
|
IsolateDevice sPredicateName = "k-GuestIsolatedDeviceFilter"
|
|
ResourceType sPredicateName = "l-GuestResourceTypeFilter"
|
|
ServerSku sPredicateName = "n-ServerSkuFilter"
|
|
|
|
// scheudle tag predicate, need db operator for now
|
|
HostSchedtag sPredicateName = "c-GuestAggregateFilter"
|
|
DiskSchedtag sPredicateName = "m-GuestDiskschedtagFilter"
|
|
NetworkSchedtag sPredicateName = "o-GuestNetschedtagFilter"
|
|
|
|
// quota
|
|
Quota sPredicateName = "z-QuotaFilter"
|
|
|
|
basePredicateNames = []sPredicateName{
|
|
HostStatus, Hypervisor, Migrate, Domain, Image, CPU, Memory, Storage,
|
|
IsolateDevice, ResourceType, ServerSku,
|
|
}
|
|
)
|
|
|
|
var (
|
|
GlobalDoamin = "default"
|
|
GlobalProject = "default"
|
|
GlobalZone = buildZone("default", "Default")
|
|
GlobalCloudregion = buildCloudregion("default", "Default", "")
|
|
GlobalWire = "default"
|
|
GlobaleVPC = "default"
|
|
)
|
|
|
|
func buildCandidate(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandidater {
|
|
cn := mock.NewMockCandidater(ctrl)
|
|
getter := buildGetter(ctrl, param)
|
|
cn.EXPECT().Getter().AnyTimes().Return(getter)
|
|
cn.EXPECT().IndexKey().AnyTimes().Return(getter.Id())
|
|
cn.EXPECT().GetResourceType().AnyTimes().Return(getter.ResourceType())
|
|
return cn
|
|
}
|
|
|
|
type sGetterParams struct {
|
|
HostId string
|
|
HostName string
|
|
IsPublic *bool
|
|
Domain string
|
|
PublicScope string
|
|
Zone *models.SZone
|
|
CloudRegion *models.SCloudregion
|
|
CloudProvider *models.SCloudprovider
|
|
HostType string
|
|
Storages []*api.CandidateStorage
|
|
Networks []*api.CandidateNetwork
|
|
OvnCapable *bool
|
|
Status string
|
|
HostStatus string
|
|
Enabled *bool
|
|
ResourceType string
|
|
TotalCPUCount int64
|
|
FreeCPUCount int64
|
|
TotalMemorySize int64
|
|
FreeMemorySize int64
|
|
FreeStorageSizeAnyType int64
|
|
QuotaKeys *models.SComputeResourceKeys
|
|
FreeGroupCount int
|
|
Skus []string
|
|
}
|
|
|
|
func buildGetter(ctrl *gomock.Controller, param sGetterParams) *mock.MockCandidatePropertyGetter {
|
|
cg := mock.NewMockCandidatePropertyGetter(ctrl)
|
|
cg.EXPECT().Id().AnyTimes().Return(param.HostId)
|
|
cg.EXPECT().Name().AnyTimes().Return(param.HostName)
|
|
cg.EXPECT().Zone().AnyTimes().Return(param.Zone)
|
|
if param.IsPublic == nil {
|
|
cg.EXPECT().IsPublic().AnyTimes().Return(true)
|
|
} else {
|
|
cg.EXPECT().IsPublic().AnyTimes().Return(*param.IsPublic)
|
|
}
|
|
if param.Enabled == nil {
|
|
cg.EXPECT().Enabled().AnyTimes().Return(true)
|
|
} else {
|
|
cg.EXPECT().Enabled().AnyTimes().Return(*param.Enabled)
|
|
}
|
|
cg.EXPECT().DomainId().AnyTimes().Return(param.Domain)
|
|
cg.EXPECT().PublicScope().AnyTimes().Return(param.PublicScope)
|
|
cg.EXPECT().Region().AnyTimes().Return(param.CloudRegion)
|
|
cg.EXPECT().Cloudprovider().AnyTimes().Return(param.CloudProvider)
|
|
cg.EXPECT().HostType().AnyTimes().Return(param.HostType)
|
|
cg.EXPECT().Storages().AnyTimes().Return(param.Storages)
|
|
cg.EXPECT().Networks().AnyTimes().Return(param.Networks)
|
|
cg.EXPECT().Sku(gomock.Any()).AnyTimes().DoAndReturn(func(instanceType string) *sku.ServerSku {
|
|
for _, t := range param.Skus {
|
|
if t != instanceType {
|
|
continue
|
|
}
|
|
return &sku.ServerSku{
|
|
Id: fmt.Sprintf("%s-%s", param.Zone.Id, instanceType),
|
|
ZoneId: param.Zone.Id,
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if param.OvnCapable == nil {
|
|
cg.EXPECT().OvnCapable().AnyTimes().Return(false)
|
|
} else {
|
|
cg.EXPECT().OvnCapable().AnyTimes().Return(*param.OvnCapable)
|
|
}
|
|
if len(param.Status) == 0 {
|
|
cg.EXPECT().Status().AnyTimes().Return(computeapi.HOST_HEALTH_STATUS_RUNNING)
|
|
} else {
|
|
cg.EXPECT().Status().AnyTimes().Return(param.Status)
|
|
}
|
|
if len(param.HostStatus) == 0 {
|
|
cg.EXPECT().HostStatus().AnyTimes().Return(computeapi.HOST_ONLINE)
|
|
} else {
|
|
cg.EXPECT().HostStatus().AnyTimes().Return(param.HostStatus)
|
|
}
|
|
if len(param.ResourceType) == 0 {
|
|
cg.EXPECT().ResourceType().AnyTimes().Return(computeapi.HostResourceTypeDefault)
|
|
} else {
|
|
cg.EXPECT().ResourceType().AnyTimes().Return(param.ResourceType)
|
|
}
|
|
cg.EXPECT().TotalCPUCount(gomock.Any()).AnyTimes().Return(param.TotalCPUCount)
|
|
cg.EXPECT().FreeCPUCount(gomock.Any()).AnyTimes().Return(param.FreeCPUCount)
|
|
cg.EXPECT().TotalMemorySize(gomock.Any()).AnyTimes().Return(param.TotalMemorySize)
|
|
cg.EXPECT().FreeMemorySize(gomock.Any()).AnyTimes().Return(param.FreeMemorySize)
|
|
cg.EXPECT().GetFreeStorageSizeOfType(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(param.FreeStorageSizeAnyType, int64(0), nil)
|
|
if param.QuotaKeys != nil {
|
|
cg.EXPECT().GetQuotaKeys(gomock.Any()).AnyTimes().Return(param.QuotaKeys)
|
|
}
|
|
cg.EXPECT().GetFreeGroupCount(gomock.Any()).AnyTimes().Return(param.FreeGroupCount, nil)
|
|
cg.EXPECT().GetPendingUsage().AnyTimes().Return(&schmodels.SPendingUsage{
|
|
NetUsage: schmodels.NewResourcePendingUsage(map[string]int{}),
|
|
})
|
|
return cg
|
|
}
|
|
|
|
func buildScheduler(ctrl *gomock.Controller, networkNicCount map[string]int, predicates ...sPredicateName) core.Scheduler {
|
|
pres := sets.NewString()
|
|
for _, pre := range predicates {
|
|
pres.Insert(string(pre))
|
|
}
|
|
algorithmProvider, _ := factory.GetAlgorithmProvider(factory.DefaultProvider)
|
|
mockScheduler := mock.NewMockScheduler(ctrl)
|
|
mockScheduler.EXPECT().BeforePredicate().AnyTimes().Return(nil)
|
|
networkNicGetter := mock.NewMockINetworkNicCountGetter(ctrl)
|
|
networkNicGetter.EXPECT().GetTotalNicCount(gomock.AssignableToTypeOf([]string{})).AnyTimes().DoAndReturn(func(netIds []string) (map[string]int, error) {
|
|
return networkNicCount, nil
|
|
})
|
|
mockScheduler.EXPECT().Predicates().AnyTimes().DoAndReturn(func() (map[string]core.FitPredicate, error) {
|
|
ret, err := factory.GetPredicates(pres)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if networkNicGetter == nil {
|
|
fmt.Printf("networkNicGetter is nil")
|
|
}
|
|
ret["j-GuestNetworkFilter"] = pre.NewNetworkPredicate().WithNetworkCountGetter(networkNicGetter)
|
|
return ret, nil
|
|
})
|
|
mockScheduler.EXPECT().PriorityConfigs().AnyTimes().DoAndReturn(func() ([]core.PriorityConfig, error) {
|
|
return factory.GetPriorityConfigs(algorithmProvider.PriorityKeys)
|
|
})
|
|
return mockScheduler
|
|
}
|
|
|
|
func buildZone(id, name string) *models.SZone {
|
|
zone := &models.SZone{}
|
|
zone.Id = id
|
|
zone.Name = name
|
|
zone.Status = "enable"
|
|
return zone
|
|
}
|
|
|
|
func buildCloudregion(id, name, provider string) *models.SCloudregion {
|
|
if len(provider) == 0 {
|
|
provider = computeapi.CLOUD_PROVIDER_ONECLOUD
|
|
}
|
|
return &models.SCloudregion{
|
|
SEnabledStatusStandaloneResourceBase: db.SEnabledStatusStandaloneResourceBase{
|
|
SStatusStandaloneResourceBase: db.SStatusStandaloneResourceBase{
|
|
SStandaloneResourceBase: db.SStandaloneResourceBase{
|
|
SStandaloneAnonResourceBase: db.SStandaloneAnonResourceBase{
|
|
Id: id,
|
|
},
|
|
Name: name,
|
|
},
|
|
SStatusResourceBase: db.SStatusResourceBase{
|
|
Status: "inservice",
|
|
},
|
|
},
|
|
SEnabledResourceBase: db.SEnabledResourceBase{
|
|
Enabled: "true",
|
|
},
|
|
},
|
|
Provider: provider,
|
|
}
|
|
}
|
|
|
|
func buildStorage(id, name string, capacity int64) *api.CandidateStorage {
|
|
storage := &models.SStorage{}
|
|
storage.Id, storage.Name = id, name
|
|
storage.DomainId = GlobalDoamin
|
|
storage.IsPublic = true
|
|
storage.PublicScope = "system"
|
|
storage.Status = computeapi.STORAGE_ONLINE
|
|
storage.Enabled = "true"
|
|
storage.ZoneId = GlobalZone.GetId()
|
|
storage.Capacity = capacity
|
|
storage.StorageType = computeapi.STORAGE_LOCAL
|
|
storage.MediumType = computeapi.DISK_TYPE_ROTATE
|
|
storage.Cmtbound = 1.0
|
|
storage.IsSysDiskStore = "true"
|
|
return &api.CandidateStorage{
|
|
SStorage: storage,
|
|
}
|
|
}
|
|
|
|
func buildNetwork(id, name string, cidr string) *api.CandidateNetwork {
|
|
network := &models.SNetwork{}
|
|
network.Id, network.Name = id, name
|
|
network.Status = computeapi.NETWORK_STATUS_AVAILABLE
|
|
network.DomainId = GlobalDoamin
|
|
network.ProjectId = GlobalProject
|
|
network.WireId = GlobalWire
|
|
network.ServerType = computeapi.NETWORK_TYPE_GUEST
|
|
prefix, err := netutils.NewIPV4Prefix(cidr)
|
|
if err == nil {
|
|
network.GuestIpMask = prefix.MaskLen
|
|
ipRange := prefix.ToIPRange()
|
|
network.GuestIpStart = ipRange.StartIp().String()
|
|
network.GuestIpEnd = ipRange.EndIp().String()
|
|
}
|
|
return &api.CandidateNetwork{
|
|
SNetwork: network,
|
|
VpcId: GlobaleVPC,
|
|
}
|
|
}
|
|
|
|
func buildInstanceGroup(id string, granularity int, force bool) *models.SGroup {
|
|
group := &models.SGroup{}
|
|
group.Id = id
|
|
group.Status = "ready"
|
|
group.DomainId = GlobalDoamin
|
|
group.ProjectId = GlobalProject
|
|
group.Granularity = granularity
|
|
group.ForceDispersion = tristate.NewFromBool(force)
|
|
return nil
|
|
}
|
|
|
|
func preSchedule(info *api.SchedInfo, candidates []core.Candidater, isForcast bool) (context.Context, *core.Unit, []core.Candidater, core.IResultHelper) {
|
|
resultHelper := core.SResultHelperFunc(core.ResultHelp)
|
|
if isForcast {
|
|
resultHelper = core.SResultHelperFunc(core.ResultHelpForForcast)
|
|
info.Suggestion = true
|
|
info.IsSuggestion = true
|
|
info.SuggestionAll = true
|
|
info.ShowSuggestionDetails = true
|
|
info.SuggestionLimit = 100
|
|
}
|
|
return context.Background(), core.NewScheduleUnit(info, nil), candidates, resultHelper
|
|
}
|
|
|
|
func deepCopy(info *api.SchedInfo) *api.SchedInfo {
|
|
serverConfigs := *info.ServerConfigs
|
|
// disks
|
|
disks := make([]*compute.DiskConfig, len(info.Disks))
|
|
for i := range disks {
|
|
disk := *info.Disks[i]
|
|
disks[i] = &disk
|
|
}
|
|
// network
|
|
networks := make([]*compute.NetworkConfig, len(info.Networks))
|
|
for i := range networks {
|
|
network := *info.Networks[i]
|
|
networks[i] = &network
|
|
}
|
|
// baremetal_disk_config
|
|
bareConfigs := make([]*compute.BaremetalDiskConfig, len(info.BaremetalDiskConfigs))
|
|
for i := range bareConfigs {
|
|
bareConfig := *info.BaremetalDiskConfigs[i]
|
|
bareConfigs[i] = &bareConfig
|
|
}
|
|
// instancegroup
|
|
instancegroupIds := make([]string, len(info.InstanceGroupIds))
|
|
for i := range instancegroupIds {
|
|
instancegroupIds[i] = info.InstanceGroupIds[i]
|
|
}
|
|
serverConfigs.Disks = disks
|
|
serverConfigs.Networks = networks
|
|
serverConfigs.BaremetalDiskConfigs = bareConfigs
|
|
|
|
serverConfig := info.ServerConfig
|
|
serverConfig.ServerConfigs = &serverConfigs
|
|
|
|
scheduInput := *info.ScheduleInput
|
|
scheduInput.ServerConfig = serverConfig
|
|
|
|
copyInfo := *info
|
|
copyInfo.ScheduleInput = &scheduInput
|
|
preferCandidates := make([]string, len(info.PreferCandidates))
|
|
for i := range preferCandidates {
|
|
preferCandidates[i] = info.PreferCandidates[i]
|
|
}
|
|
instanceGroupDetail := make(map[string]*models.SGroup, len(info.InstanceGroupsDetail))
|
|
for k, v := range info.InstanceGroupsDetail {
|
|
// v only read
|
|
instanceGroupDetail[k] = v
|
|
}
|
|
copyInfo.PreferCandidates = preferCandidates
|
|
copyInfo.InstanceGroupsDetail = instanceGroupDetail
|
|
|
|
return ©Info
|
|
}
|