scheduler: add pending usage process

This commit is contained in:
Zexi
2019-05-29 19:57:44 +08:00
parent 4fb501859c
commit 64cca04a17
44 changed files with 1020 additions and 679 deletions
@@ -35,10 +35,12 @@ func (p *CPUPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.Pr
h := predicates.NewPredicateHelper(p, u, c)
d := u.SchedData()
freeCPUCount := h.GetInt64("FreeCPUCount", 0)
useRsvd := h.UseReserved()
getter := c.Getter()
freeCPUCount := getter.FreeCPUCount(useRsvd)
reqCPUCount := int64(d.Ncpu)
if freeCPUCount < reqCPUCount {
totalCPUCount := h.GetInt64("CPUCount", 0)
totalCPUCount := getter.TotalCPUCount(useRsvd)
h.AppendInsufficientResourceError(reqCPUCount, totalCPUCount, freeCPUCount)
h.SetCapacity(0)
} else {
@@ -35,10 +35,12 @@ func (p *MemoryPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core
h := predicates.NewPredicateHelper(p, u, c)
d := u.SchedData()
freeMemSize := h.GetInt64("FreeMemSize", 0)
useRsvd := h.UseReserved()
getter := c.Getter()
freeMemSize := getter.FreeMemorySize(useRsvd)
reqMemSize := int64(d.Memory)
if freeMemSize < reqMemSize {
totalMemSize := h.GetInt64("MemSize", 0)
totalMemSize := getter.TotalMemorySize(useRsvd)
h.AppendInsufficientResourceError(reqMemSize, totalMemSize, freeMemSize)
h.SetCapacity(0)
} else {
@@ -60,10 +60,7 @@ func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
h := predicates.NewPredicateHelper(p, u, c)
schedData := u.SchedData()
candidate, err := h.BaremetalCandidate()
if err != nil {
return false, nil, err
}
networks := c.Getter().Networks()
counters := core.NewCounters()
@@ -73,7 +70,7 @@ func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
isRandomNetworkAvailable := func(private bool, exit bool, wire string) string {
var errMsgs []string
for _, network := range candidate.Networks {
for _, network := range networks {
appendError := func(errMsg string) {
errMsgs = append(errMsgs, fmt.Sprintf("%s: %s", network.Id, errMsg))
}
@@ -118,7 +115,7 @@ func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
if network.Network == "" {
return isRandomNetworkAvailable(network.Private, network.Exit, network.Wire)
}
for _, net := range candidate.Networks {
for _, net := range networks {
if (network.Network == net.Id || network.Network == net.Name) && (net.IsPublic || net.ProjectId == schedData.Project) && (net.GetPorts() > 0 || isMigrate()) {
h.SetCapacity(1)
return ""
@@ -40,22 +40,21 @@ func (p *StatusPredicate) Clone() core.FitPredicate {
func (p *StatusPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(p, u, c)
bm, err := h.BaremetalCandidate()
if err != nil {
return false, nil, err
}
getter := c.Getter()
if !ExpectedStatus.Has(bm.Status) {
h.Exclude2("status", bm.Status, ExpectedStatus)
status := getter.Status()
enabled := getter.Enabled()
if !ExpectedStatus.Has(status) {
h.Exclude2("status", status, ExpectedStatus)
return h.GetResult()
}
if !bm.Enabled {
if !enabled {
h.Exclude2("enable_status", "disable", "enable")
return h.GetResult()
}
if bm.ServerID == "" {
if getter.IsEmpty() {
h.SetCapacity(1)
} else {
h.AppendPredicateFailMsg(predicates.ErrBaremetalHasAlreadyBeenOccupied)
@@ -57,14 +57,11 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
h := predicates.NewPredicateHelper(p, u, c)
schedData := u.SchedData()
candidate, err := h.BaremetalCandidate()
if err != nil {
return false, nil, err
}
storageInfo := c.Getter().StorageInfo()
layouts, err := baremetal.CalculateLayout(
schedData.BaremetalDiskConfigs,
candidate.StorageInfo,
storageInfo,
)
if err == nil && baremetal.CheckDisksAllocable(layouts, toBaremetalDisks(schedData.Disks)) {
@@ -50,16 +50,13 @@ func (f *CPUPredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool, err
func (f *CPUPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(f, u, c)
d := u.SchedData()
hc, err := h.HostCandidate()
if err != nil {
return false, nil, err
}
useRsvd := h.UseReserved()
freeCPUCount := hc.GetFreeCPUCount(useRsvd)
getter := c.Getter()
freeCPUCount := getter.FreeCPUCount(useRsvd)
reqCPUCount := int64(d.Ncpu)
if freeCPUCount < reqCPUCount {
totalCPUCount := hc.GetTotalCPUCount(useRsvd)
totalCPUCount := getter.TotalCPUCount(useRsvd)
h.AppendInsufficientResourceError(reqCPUCount, totalCPUCount, freeCPUCount)
}
@@ -14,7 +14,7 @@
package guest
import (
/*import (
"fmt"
"yunion.io/x/onecloud/pkg/scheduler/algorithm/plugin"
@@ -110,4 +110,4 @@ func (p *GroupPredicate) OnPriorityEnd(u *core.Unit, c core.Candidater) {
p.Name()+":prefer",
))
}
}
}*/
@@ -51,7 +51,8 @@ func hostHasContainerTag(c core.Candidater) bool {
}
func hostAllowRunContainer(c core.Candidater) bool {
hostType := c.Get("HostType")
getter := c.Getter()
hostType := getter.HostType()
if hostType == api.HostTypeKubelet {
return true
}
@@ -65,7 +66,7 @@ func hostAllowRunContainer(c core.Candidater) bool {
func (f *HypervisorPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(f, u, c)
hostType := c.Get("HostType")
hostType := c.Getter().HostType()
guestNeedType := u.SchedData().Hypervisor
if guestNeedType != hostType {
@@ -1,135 +0,0 @@
// 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 guest
import (
"reflect"
"testing"
"github.com/stretchr/testify/mock"
"yunion.io/x/jsonutils"
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
"yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates"
"yunion.io/x/onecloud/pkg/scheduler/api"
"yunion.io/x/onecloud/pkg/scheduler/core"
)
func newUnitByHypervisor(hypervisor string) *core.Unit {
info := &api.SchedInfo{
ScheduleInput: &schedapi.ScheduleInput{
ServerConfig: schedapi.ServerConfig{
ServerConfigs: &computeapi.ServerConfigs{
Hypervisor: hypervisor,
},
},
},
}
return core.NewScheduleUnit(info, nil)
}
type FakeCandidater struct {
mock.Mock
}
func (c *FakeCandidater) Getter() core.CandidatePropertyGetter {
return nil
}
func (c *FakeCandidater) IndexKey() string {
return "fake_id"
}
func (c *FakeCandidater) XGet(key string, kind core.Kind) interface{} {
args := c.Called()
return args.String(0)
}
func (c *FakeCandidater) Get(key string) interface{} {
args := c.Called(key)
return args.String(0)
}
func (c *FakeCandidater) Type() int {
return 0
}
func (c *FakeCandidater) GetSchedDesc() *jsonutils.JSONDict {
return nil
}
func (c *FakeCandidater) GetGuestCount() int64 {
return 0
}
func (c *FakeCandidater) GetResourceType() string {
return ""
}
func TestHypervisorPredicate_Execute(t *testing.T) {
type args struct {
u *core.Unit
c core.Candidater
}
aliHost := new(FakeCandidater)
aliHost.On("Get", "HostType").Return(computeapi.HOST_TYPE_ALIYUN)
tests := []struct {
name string
args args
want bool
want1 []core.PredicateFailureReason
wantErr bool
}{
{
name: "hypervisor equals host_type always fits",
args: args{
u: newUnitByHypervisor("aliyun"),
c: aliHost,
},
want: true,
want1: nil,
wantErr: false,
},
{
name: "hypervisor not equals host_type not fit",
args: args{
u: newUnitByHypervisor("kvm"),
c: aliHost,
},
want: false,
want1: []core.PredicateFailureReason{predicates.NewUnexceptedResourceError(`host_hypervisor_runtime is 'aliyun', expected 'kvm'`)},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := &HypervisorPredicate{}
got, got1, err := f.Execute(tt.args.u, tt.args.c)
if (err != nil) != tt.wantErr {
t.Errorf("HypervisorPredicate.Execute() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("HypervisorPredicate.Execute() got = %v, want %v", got, tt.want)
}
if !reflect.DeepEqual(got1, tt.want1) {
t.Errorf("HypervisorPredicate.Execute() got1 = %v, want %v", got1, tt.want1)
}
})
}
}
@@ -18,6 +18,7 @@ import (
"fmt"
"yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates"
"yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
"yunion.io/x/onecloud/pkg/scheduler/core"
)
@@ -46,9 +47,10 @@ func (f *IsolatedDevicePredicate) PreExecute(u *core.Unit, cs []core.Candidater)
func (f *IsolatedDevicePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(f, u, c)
reqIsoDevs := u.SchedData().IsolatedDevices
hc, err := h.HostCandidate()
if err != nil {
return false, nil, err
// TODO: use interface function
hc, ok := c.(*candidate.HostDesc)
if !ok {
return false, nil, fmt.Errorf("Candidater is not *candidate.HostDesc")
}
minCapacity := int64(0xFFFFFFFF)
@@ -71,7 +73,7 @@ func (f *IsolatedDevicePredicate) Execute(u *core.Unit, c core.Candidater) (bool
}
reqCount := len(reqIsoDevs)
freeCount := len(hc.UnusedIsolatedDevices())
freeCount := len(hc.UnusedIsolatedDevices()) - hc.GetPendingUsage().IsolatedDevice
totalCount := len(hc.IsolatedDevices)
// check host isolated device count
@@ -51,16 +51,13 @@ func (p *MemoryPredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool,
func (p *MemoryPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(p, u, c)
d := u.SchedData()
hc, err := h.HostCandidate()
if err != nil {
return false, nil, err
}
useRsvd := h.UseReserved()
freeMemSize := hc.GetFreeMemSize(useRsvd)
getter := c.Getter()
freeMemSize := getter.FreeMemorySize(useRsvd)
reqMemSize := int64(d.Memory)
if freeMemSize < reqMemSize {
totalMemSize := hc.GetTotalMemSize(useRsvd)
totalMemSize := getter.TotalMemorySize(useRsvd)
h.AppendInsufficientResourceError(reqMemSize, totalMemSize, freeMemSize)
}
@@ -14,7 +14,7 @@
package guest
import (
/*import (
"yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates"
"yunion.io/x/onecloud/pkg/scheduler/core"
)
@@ -51,4 +51,4 @@ func (p *NestPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.P
}
return h.GetResult()
}
}*/
@@ -60,10 +60,8 @@ func (p *NetworkPredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool,
func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(p, u, c)
hc, err := h.HostCandidate()
if err != nil {
return false, nil, err
}
getter := c.Getter()
networks := getter.Networks()
d := u.SchedData()
@@ -78,7 +76,7 @@ func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
counterOfNetwork := func(u *core.Unit, n *models.SNetwork, r int) core.Counter {
counter := u.CounterManager.GetOrCreate("net:"+n.Id, func() core.Counter {
return core.NewNormalCounter(int64(n.GetPorts() - r))
return core.NewNormalCounter(int64(getter.GetFreePort(n.Id) - r))
})
u.SharedResourceManager.Add(n.GetId(), counter)
@@ -91,7 +89,7 @@ func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
var fullErrMsgs []string
found := false
for _, n := range hc.Networks {
for _, n := range networks {
errMsgs := []string{}
appendError := func(errMsg string) {
errMsgs = append(errMsgs, errMsg)
@@ -154,13 +152,13 @@ func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
counters.Add(counters0)
return ret_msg
}
if len(hc.Networks) == 0 {
if len(networks) == 0 {
return predicates.ErrNoAvailableNetwork
}
errMsgs := make([]string, 0)
for _, net := range hc.Networks {
for _, net := range networks {
/*if !isMatchServerType(net) {
errMsgs = append(errMsgs, fmt.Sprintf("%v(%v): server type not matched", net.Name, net.ID))
continue
@@ -197,7 +195,7 @@ func (p *NetworkPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
var errMsgs []string
for _, n := range d.Networks {
if err_msg := isNetworkAvaliable(n, counters, hc.Networks); err_msg != "" {
if err_msg := isNetworkAvaliable(n, counters, networks); err_msg != "" {
errMsgs = append(errMsgs, err_msg)
}
}
@@ -44,14 +44,11 @@ func (p *StatusPredicate) Clone() core.FitPredicate {
func (p *StatusPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(p, u, c)
hc, err := h.HostCandidate()
if err != nil {
return false, nil, err
}
curStatus := hc.Status
curHostStatus := hc.HostStatus
curEnableStatus := hc.Enabled
getter := c.Getter()
curStatus := getter.Status()
curHostStatus := getter.HostStatus()
curEnableStatus := getter.Enabled()
if curStatus != ExpectedStatus {
h.Exclude2("status", curStatus, ExpectedStatus)
@@ -65,16 +62,18 @@ func (p *StatusPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core
h.Exclude2("enable_status", curEnableStatus, true)
}
if hc.Zone.Status != ExpectedEnableStatus {
h.Exclude2("zone_status", hc.Zone.Status, ExpectedEnableStatus)
zone := getter.Zone()
if zone.Status != ExpectedEnableStatus {
h.Exclude2("zone_status", zone.Status, ExpectedEnableStatus)
}
if hc.Cloudprovider != nil {
if !utils.IsInStringArray(hc.Cloudprovider.Status, api.CLOUD_PROVIDER_VALID_STATUS) {
h.Exclude2("cloud_provider_status", hc.Cloudprovider.Status, api.CLOUD_PROVIDER_VALID_STATUS)
cloudprovider := getter.Cloudprovider()
if cloudprovider != nil {
if !utils.IsInStringArray(cloudprovider.Status, api.CLOUD_PROVIDER_VALID_STATUS) {
h.Exclude2("cloud_provider_status", cloudprovider.Status, api.CLOUD_PROVIDER_VALID_STATUS)
}
if hc.Cloudprovider.HealthStatus != api.CLOUD_PROVIDER_HEALTH_NORMAL {
h.Exclude2("cloud_provider_health_status", hc.Cloudprovider.HealthStatus, api.CLOUD_PROVIDER_HEALTH_NORMAL)
if cloudprovider.HealthStatus != api.CLOUD_PROVIDER_HEALTH_NORMAL {
h.Exclude2("cloud_provider_health_status", cloudprovider.HealthStatus, api.CLOUD_PROVIDER_HEALTH_NORMAL)
}
}
@@ -50,12 +50,9 @@ func (p *StoragePredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool,
func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
h := predicates.NewPredicateHelper(p, u, c)
hc, err := h.HostCandidate()
if err != nil {
return false, nil, err
}
d := u.SchedData()
getter := c.Getter()
storages := getter.Storages()
isMigrate := func() bool {
return len(d.HostId) > 0
@@ -66,7 +63,7 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
}
isStorageAccessible := func(storage string) bool {
for _, s := range hc.Storages {
for _, s := range storages {
if storage == s.Id || storage == s.Name {
return true
}
@@ -76,7 +73,7 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
}
getStorageCapacity := func(backend string, reqMaxSize int64, reqTotalSize int64, useRsvd bool) (int64, int64) {
totalFree := hc.GetFreeStorageSizeOfType(backend, useRsvd)
totalFree := getter.GetFreeStorageSizeOfType(backend, useRsvd)
capacity := totalFree / utils.Max(reqTotalSize, 1)
return capacity, totalFree
@@ -95,7 +92,7 @@ func (p *StoragePredicate) Execute(u *core.Unit, c core.Candidater) (bool, []cor
getStorageFreeStr := func(backend string, useRsvd bool) string {
ss := []string{}
for _, s := range hc.Storages {
for _, s := range getter.Storages() {
if s.StorageType == backend {
total := int64(float32(s.Capacity) * s.Cmtbound)
used := s.GetUsedCapacity(tristate.True)
@@ -26,12 +26,9 @@ import (
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/scheduler/algorithm"
"yunion.io/x/onecloud/pkg/scheduler/algorithm/plugin"
"yunion.io/x/onecloud/pkg/scheduler/api"
"yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
"yunion.io/x/onecloud/pkg/scheduler/core"
"yunion.io/x/onecloud/pkg/scheduler/data_manager"
)
// BasePredicate is a default struct for all the predicates that will
@@ -112,7 +109,7 @@ func (h *PredicateHelper) AppendPredicateFailMsg(reason string) {
func (h *PredicateHelper) AppendInsufficientResourceError(req, total, free int64) {
h.AppendPredicateFail(
NewInsufficientResourceError(h.Candidate.Get("Name").(string), req, total, free))
NewInsufficientResourceError(h.Candidate.Getter().Name(), req, total, free))
}
// SetCapacity returns the current resource capacity calculated by a filter.
@@ -144,39 +141,6 @@ func (h *PredicateHelper) Exclude2(predicateName string, current, expected inter
h.Exclude(fmt.Sprintf("%s is '%v', expected '%v'", predicateName, current, expected))
}
func (h *PredicateHelper) Get(key string) interface{} {
return h.Candidate.Get(key)
}
func (h *PredicateHelper) GetInt64(key string, def int64) int64 {
value := h.Get(key)
if value == nil {
return def
}
return value.(int64)
}
func (h *PredicateHelper) GetGroupCounts() (*data_manager.GroupResAlgorithmResult, error) {
value := h.Get("Groups")
if value == nil {
return nil, nil
}
if r, ok := value.(*data_manager.GroupResAlgorithmResult); ok {
return r, nil
}
return nil, fmt.Errorf("type error: not *data_manager.GroupResAlgorithmResult (GetGroupCounts)")
}
func (h *PredicateHelper) HostCandidate() (*candidate.HostDesc, error) {
return algorithm.ToHostCandidate(h.Candidate)
}
func (h *PredicateHelper) BaremetalCandidate() (*candidate.BaremetalDesc, error) {
return algorithm.ToBaremetalCandidate(h.Candidate)
}
// UseReserved check whether the unit can use guest reserved resource
func (h *PredicateHelper) UseReserved() bool {
usable := false