scheduler: optimize forecast filter info

This commit is contained in:
Zexi
2019-07-13 19:30:59 +08:00
parent 7b1a4f2c94
commit 9bc81fe94c
8 changed files with 183 additions and 59 deletions

View File

@@ -72,16 +72,22 @@ func (p *DiskSchedtagPredicate) GetResources(c core.Candidater) []ISchedtagCandi
return ret
}
func (p *DiskSchedtagPredicate) IsResourceFitInput(u *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) error {
func (p *DiskSchedtagPredicate) IsResourceFitInput(u *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) core.PredicateFailureReason {
storage := res.(*api.CandidateStorage)
if storage.Status == computeapi.STORAGE_OFFLINE || storage.Enabled.IsFalse() {
return fmt.Errorf("Storage status is %s, enable is %v", storage.Status, storage.Enabled)
return &FailReason{
fmt.Sprintf("Storage status is %s, enable is %v", storage.Status, storage.Enabled),
StorageEnable,
}
}
d := input.(*diskW)
if d.Storage != "" {
if storage.Id != d.Storage && storage.Name != d.Storage {
return fmt.Errorf("Storage name %s != (%s:%s)", d.Storage, storage.Name, storage.Id)
return &FailReason{
fmt.Sprintf("Storage name %s != (%s:%s)", d.Storage, storage.Name, storage.Id),
StorageMatch,
}
}
}
if c.Getter().ResourceType() == computeapi.HostResourceTypePrepaidRecycle {
@@ -89,13 +95,19 @@ func (p *DiskSchedtagPredicate) IsResourceFitInput(u *core.Unit, c core.Candidat
}
if !(len(d.Backend) == 0 || d.Backend == computeapi.STORAGE_LOCAL) {
if storage.StorageType != d.Backend {
return fmt.Errorf("Storage %s backend %s != %s", storage.Name, storage.StorageType, d.Backend)
return &FailReason{
fmt.Sprintf("Storage %s backend %s != %s", storage.Name, storage.StorageType, d.Backend),
StorageType,
}
}
}
storageTypes := p.GetHypervisorDriver().GetStorageTypes()
if len(storageTypes) != 0 && !utils.IsInStringArray(storage.StorageType, storageTypes) {
return fmt.Errorf("Storage %s storage type %s not in %v", storage.Name, storage.StorageType, storageTypes)
return &FailReason{
fmt.Sprintf("Storage %s storage type %s not in %v", storage.Name, storage.StorageType, storageTypes),
StorageType,
}
}
return nil
}

View File

@@ -94,3 +94,32 @@ func (ure *UnexceptedResourceError) Error() string {
func (ure *UnexceptedResourceError) GetReason() string {
return ure.Error()
}
type FailReason struct {
Reason string
Type string
}
func (r FailReason) GetReason() string {
return r.Reason
}
func (r FailReason) GetType() string {
return r.Type
}
const (
NetworkPrivate = "network_private"
NetworkPublic = "network_public"
NetworkTypeMatch = "network_type"
NetworkMatch = "network_match"
NetworkWire = "network_wire"
NetworkOwner = "network_owner"
NetworkDomain = "network_domain"
NetworkRange = "network_range"
NetworkFreeCount = "network_free_count"
StorageEnable = "storage_status"
StorageMatch = "storage_match"
StorageType = "storage_type"
)

View File

@@ -75,42 +75,63 @@ func (p *NetworkSchedtagPredicate) GetResources(c core.Candidater) []ISchedtagCa
return ret
}
func (p *NetworkSchedtagPredicate) IsResourceFitInput(u *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) error {
func (p *NetworkSchedtagPredicate) IsResourceFitInput(u *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) core.PredicateFailureReason {
network := res.(*api.CandidateNetwork)
net := input.(*netW)
if net.Network != "" {
if network.Id != net.Network && network.Name != net.Network {
return fmt.Errorf("Network name %s != (%s:%s)", net.Network, network.Name, network.Id)
return &FailReason{
Reason: fmt.Sprintf("Network name %s != (%s:%s)", net.Network, network.Name, network.Id),
Type: NetworkMatch,
}
}
}
if net.Wire != "" {
if network.WireId != net.Wire {
return fmt.Errorf("Wire %s != %s", net.Wire, network.WireId)
return &FailReason{
Reason: fmt.Sprintf("Wire %s != %s", net.Wire, network.WireId),
Type: NetworkWire,
}
}
}
if net.Network == "" {
netTypes := p.GetNetworkTypes(net.NetType)
if !utils.IsInStringArray(network.ServerType, netTypes) {
return fmt.Errorf("Network %s type %s not in %v", network.Name, network.ServerType, netTypes)
return &FailReason{
Reason: fmt.Sprintf("Network %s type %s not in %v", network.Name, network.ServerType, netTypes),
Type: NetworkTypeMatch,
}
}
schedData := u.SchedData()
if net.Private {
if network.IsPublic {
return fmt.Errorf("Network %s is public", network.Name)
return &FailReason{
Reason: fmt.Sprintf("Network %s is public", network.Name),
Type: NetworkPublic,
}
}
if network.ProjectId != schedData.Project && !utils.IsInStringArray(schedData.Project, network.GetSharedProjects()) {
return fmt.Errorf("Network project %s + %v not owner by %s", network.ProjectId, network.GetSharedProjects(), schedData.Project)
return &FailReason{
Reason: fmt.Sprintf("Network project %s + %v not owner by %s", network.ProjectId, network.GetSharedProjects(), schedData.Project),
Type: NetworkOwner,
}
}
} else {
if !network.IsPublic {
return fmt.Errorf("Network %s is private", network.Name)
return &FailReason{
fmt.Sprintf("Network %s is private", network.Name),
NetworkPrivate,
}
}
if rbacutils.TRbacScope(network.PublicScope) == rbacutils.ScopeDomain {
netDomain := network.DomainId
reqDomain := net.Domain
if netDomain != reqDomain {
return fmt.Errorf("Network domain scope %s not owner by %s", netDomain, reqDomain)
return &FailReason{
fmt.Sprintf("Network domain scope %s not owner by %s", netDomain, reqDomain),
NetworkDomain,
}
}
}
}
@@ -119,19 +140,31 @@ func (p *NetworkSchedtagPredicate) IsResourceFitInput(u *core.Unit, c core.Candi
if len(net.Address) > 0 {
ipAddr, err := netutils.NewIPV4Addr(net.Address)
if err != nil {
return fmt.Errorf("Invalid ip address %s: %v", net.Address, err)
return &FailReason{
fmt.Sprintf("Invalid ip address %s: %v", net.Address, err),
NetworkRange,
}
}
if !network.GetIPRange().Contains(ipAddr) {
return fmt.Errorf("Address %s not in range", net.Address)
return &FailReason{
fmt.Sprintf("Address %s not in range", net.Address),
NetworkRange,
}
}
}
free, err := network.GetFreeAddressCount()
if err != nil {
return err
return &FailReason{
Reason: fmt.Sprintf("get free address count: %v", err),
Type: NetworkFreeCount,
}
}
req := u.SchedData().Count
if free < req {
return fmt.Errorf("Network %s no free IPs, free %d, require %d", network.Name, free, req)
return &FailReason{
Reason: fmt.Sprintf("Network %s no free IPs, free %d, require %d", network.Name, free, req),
Type: NetworkFreeCount,
}
}
h := NewPredicateHelper(p, u, c)
h.SetCapacity(int64(free))

View File

@@ -1,5 +1,3 @@
// 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
@@ -103,13 +101,34 @@ func (h *PredicateHelper) AppendPredicateFail(reason core.PredicateFailureReason
h.predicateFails = append(h.predicateFails, reason)
}
type predicateFailure struct {
err core.PredicateFailureError
eType string
}
func (f predicateFailure) GetReason() string {
return f.err.GetReason()
}
func (f predicateFailure) GetType() string {
return f.eType
}
func (h *PredicateHelper) AppendPredicateFailMsg(reason string) {
h.AppendPredicateFail(NewUnexceptedResourceError(reason))
h.AppendPredicateFailMsgWithType(reason, h.predicate.Name())
}
func (h *PredicateHelper) AppendPredicateFailMsgWithType(reason string, eType string) {
err := NewUnexceptedResourceError(reason)
h.AppendPredicateFail(&predicateFailure{err: err, eType: eType})
}
func (h *PredicateHelper) AppendInsufficientResourceError(req, total, free int64) {
h.AppendPredicateFail(
NewInsufficientResourceError(h.Candidate.Getter().Name(), req, total, free))
&predicateFailure{
err: NewInsufficientResourceError(h.Candidate.Getter().Name(), req, total, free),
eType: h.predicate.Name(),
})
}
// SetCapacity returns the current resource capacity calculated by a filter.
@@ -137,6 +156,13 @@ func (h *PredicateHelper) Exclude(reason string) {
h.AppendPredicateFailMsg(reason)
}
func (h *PredicateHelper) ExcludeByErrors(errs []core.PredicateFailureReason) {
h.SetCapacity(0)
for _, err := range errs {
h.AppendPredicateFail(err)
}
}
func (h *PredicateHelper) Exclude2(predicateName string, current, expected interface{}) {
h.Exclude(fmt.Sprintf("%s is '%v', expected '%v'", predicateName, current, expected))
}
@@ -204,7 +230,7 @@ type ISchedtagPredicateInstance interface {
GetInputs(u *core.Unit) []ISchedtagCustomer
GetResources(c core.Candidater) []ISchedtagCandidateResource
IsResourceFitInput(unit *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) error
IsResourceFitInput(unit *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) core.PredicateFailureReason
DoSelect(c core.Candidater, input ISchedtagCustomer, res []ISchedtagCandidateResource) []ISchedtagCandidateResource
AddSelectResult(index int, selectRes []ISchedtagCandidateResource, output *core.AllocatedResource)
@@ -354,10 +380,10 @@ func (p *BaseSchedtagPredicate) Execute(
h := NewPredicateHelper(sp, u, c)
inputRes := p.GetInputResourcesMap(c.IndexKey())
filterErrs := make([]error, 0)
filterErrs := make([]core.PredicateFailureReason, 0)
for idx, input := range inputs {
fitResources := make([]ISchedtagCandidateResource, 0)
errs := make([]error, 0)
errs := make([]core.PredicateFailureReason, 0)
for _, res := range resources {
if err := sp.IsResourceFitInput(u, c, res, input); err == nil {
fitResources = append(fitResources, res)
@@ -366,20 +392,19 @@ func (p *BaseSchedtagPredicate) Execute(
}
}
if len(fitResources) == 0 {
h.Exclude(fmt.Sprintf("Not found available resources for %s %s: %s", input.Keyword(), input.JSON(input), errors.NewAggregate(errs)))
h.ExcludeByErrors(errs)
break
}
if len(errs) > 0 {
filterErrs = append(filterErrs, errors.NewAggregate(errs))
filterErrs = append(filterErrs, errs...)
}
matchedResources, err := p.checkResources(input, fitResources, u, c)
if err != nil {
aggErr := errors.NewAggregate(filterErrs)
errMsg := fmt.Sprintf("schedtag: %v", err.Error())
if aggErr != nil {
errMsg = fmt.Sprintf("%s; filter: %v", errMsg, aggErr.Error())
if len(filterErrs) > 0 {
h.ExcludeByErrors(filterErrs)
}
errMsg := fmt.Sprintf("schedtag: %v", err.Error())
h.Exclude(errMsg)
}
inputRes[idx] = matchedResources