karmada/pkg/scheduler/framework/interface.go

161 lines
5.2 KiB
Go

package framework
import (
"context"
"errors"
"strings"
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
)
const (
// MinClusterScore is the minimum score a Score plugin is expected to return.
MinClusterScore int64 = 0
// MaxClusterScore is the maximum score a Score plugin is expected to return.
MaxClusterScore int64 = 100
)
// Framework manages the set of plugins in use by the scheduling framework.
// Configured plugins are called at specified points in a scheduling context.
type Framework interface {
// RunFilterPlugins runs the set of configured Filter plugins for resources on
// the given cluster.
RunFilterPlugins(ctx context.Context, placement *policyv1alpha1.Placement, bindingSpec *workv1alpha2.ResourceBindingSpec, clusterv1alpha1 *clusterv1alpha1.Cluster) *Result
// RunScorePlugins runs the set of configured Score plugins, it returns a map of plugin name to cores
RunScorePlugins(ctx context.Context, placement *policyv1alpha1.Placement, spec *workv1alpha2.ResourceBindingSpec, clusters []*clusterv1alpha1.Cluster) (PluginToClusterScores, error)
}
// Plugin is the parent type for all the scheduling framework plugins.
type Plugin interface {
Name() string
}
// FilterPlugin is an interface for filter plugins. These filters are used to filter out clusters
// that are not fit for the resource.
type FilterPlugin interface {
Plugin
// Filter is called by the scheduling framework.
Filter(ctx context.Context, placement *policyv1alpha1.Placement, bindingSpec *workv1alpha2.ResourceBindingSpec, clusterv1alpha1 *clusterv1alpha1.Cluster) *Result
}
// Result indicates the result of running a plugin. It consists of a code, a
// message and (optionally) an error. When the status code is not `Success`,
// the reasons should explain why.
type Result struct {
code Code
reasons []string
err error
}
// Code is the Status code/type which is returned from plugins.
type Code int
// These are predefined codes used in a Status.
const (
// Success means that plugin ran correctly and found resource schedulable.
// NOTE: A nil status is also considered as "Success".
Success Code = iota
// Unschedulable is used when a plugin finds the resource unschedulable.
// The accompanying status message should explain why the it is unschedulable.
Unschedulable
// Error is used for internal plugin errors, unexpected input, etc.
Error
)
// NewResult makes a result out of the given arguments and returns its pointer.
func NewResult(code Code, reasons ...string) *Result {
s := &Result{
code: code,
reasons: reasons,
}
if code == Error {
s.err = errors.New(strings.Join(reasons, ","))
}
return s
}
// PluginToResult maps plugin name to Result.
type PluginToResult map[string]*Result
// Merge merges the statuses in the map into one. The resulting status code have the following
// precedence: Error, Unschedulable.
func (p PluginToResult) Merge() *Result {
if len(p) == 0 {
return nil
}
finalStatus := NewResult(Success)
var hasUnschedulable bool
for _, s := range p {
if s.code == Error {
finalStatus.err = s.err
} else if s.code == Unschedulable {
hasUnschedulable = true
}
finalStatus.code = s.code
finalStatus.reasons = append(finalStatus.reasons, s.reasons...)
}
if finalStatus.err != nil {
finalStatus.code = Error
} else if hasUnschedulable {
finalStatus.code = Unschedulable
}
return finalStatus
}
// IsSuccess returns true if and only if "Result" is nil or Code is "Success".
func (s *Result) IsSuccess() bool {
return s == nil || s.code == Success
}
// AsError returns nil if the Result is a success; otherwise returns an "error" object
// with a concatenated message on reasons of the Result.
func (s *Result) AsError() error {
if s.IsSuccess() {
return nil
}
if s.err != nil {
return s.err
}
return errors.New(strings.Join(s.reasons, ", "))
}
// ScorePlugin is an interface that must be implemented by "Score" plugins to rank
// clusters that passed the filtering phase.
type ScorePlugin interface {
Plugin
// Score is called on each filtered cluster. It must return success and an integer
// indicating the rank of the cluster. All scoring plugins must return success or
// the resource will be rejected.
Score(ctx context.Context, placement *policyv1alpha1.Placement, spec *workv1alpha2.ResourceBindingSpec, cluster *clusterv1alpha1.Cluster) (int64, *Result)
// ScoreExtensions returns a ScoreExtensions interface
// if it implements one, or nil if does not.
ScoreExtensions() ScoreExtensions
}
// ScoreExtensions is an interface for Score extended functionality.
type ScoreExtensions interface {
// NormalizeScore is called for all cluster scores produced
// by the same plugin's "Score"
NormalizeScore(ctx context.Context, scores ClusterScoreList) *Result
}
// ClusterScore represent the cluster score.
type ClusterScore struct {
Cluster *clusterv1alpha1.Cluster
Score int64
}
// ClusterScoreList declares a list of clusters and their scores.
type ClusterScoreList []ClusterScore
// PluginToClusterScores declares a map from plugin name to its ClusterScoreList.
type PluginToClusterScores map[string]ClusterScoreList