scheduler: merge Reserve and Unreserve plugins

Previously, separate interfaces were defined for Reserve and Unreserve
plugins. However, in nearly all cases, a plugin that allocates a
resource using Reserve will likely want to register itself for Unreserve
as well in order to free the allocated resource at the end of a failed
scheduling/binding cycle. Having separate plugins for Reserve and
Unreserve also adds unnecessary config toil. To that end, this patch
aims to merge the two plugins into a single interface called a
ReservePlugin that requires implementing both the Reserve and Unreserve
methods.
This commit is contained in:
Adhityaa Chandrasekar
2020-06-15 21:52:54 +00:00
parent 8adcd7978e
commit ec83143342
23 changed files with 243 additions and 288 deletions

View File

@@ -50,7 +50,7 @@ func (s *stateData) Clone() framework.StateData {
return copy
}
// Reserve is the functions invoked by the framework at "reserve" extension point.
// Reserve is the function invoked by the framework at "reserve" extension point.
func (mc CommunicatingPlugin) Reserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
if pod == nil {
return framework.NewStatus(framework.Error, "pod cannot be nil")
@@ -63,7 +63,20 @@ func (mc CommunicatingPlugin) Reserve(ctx context.Context, state *framework.Cycl
return nil
}
// PreBind is the functions invoked by the framework at "prebind" extension point.
// Unreserve is the function invoked by the framework when any error happens
// during "reserve" extension point or later.
func (mc CommunicatingPlugin) Unreserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) {
if pod.Name == "my-test-pod" {
state.Lock()
// The pod is at the end of its lifecycle -- let's clean up the allocated
// resources. In this case, our clean up is simply deleting the key written
// in the Reserve operation.
state.Delete(framework.StateKey(pod.Name))
state.Unlock()
}
}
// PreBind is the function invoked by the framework at "prebind" extension point.
func (mc CommunicatingPlugin) PreBind(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
if pod == nil {
return framework.NewStatus(framework.Error, "pod cannot be nil")

View File

@@ -31,9 +31,8 @@ import (
// This plugin is stateful. It receives arguments at initialization (NewMultipointPlugin)
// and changes its state when it is executed.
type MultipointExample struct {
mpState map[int]string
numRuns int
mu sync.RWMutex
executionPoints []string
mu sync.RWMutex
}
var _ framework.ReservePlugin = &MultipointExample{}
@@ -47,19 +46,35 @@ func (mp *MultipointExample) Name() string {
return Name
}
// Reserve is the functions invoked by the framework at "reserve" extension point.
// Reserve is the function invoked by the framework at "reserve" extension
// point. In this trivial example, the Reserve method allocates an array of
// strings.
func (mp *MultipointExample) Reserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
// Reserve is not called concurrently, and so we don't need to lock.
mp.numRuns++
mp.executionPoints = append(mp.executionPoints, "reserve")
return nil
}
// PreBind is the functions invoked by the framework at "prebind" extension point.
// Unreserve is the function invoked by the framework when any error happens
// during "reserve" extension point or later. In this example, the Unreserve
// method loses its reference to the string slice, allowing it to be garbage
// collected, and thereby "unallocating" the reserved resources.
func (mp *MultipointExample) Unreserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) {
// Unlike Reserve, the Unreserve method may be called concurrently since
// there is no guarantee that there will only one unreserve operation at any
// given point in time (for example, during the binding cycle).
mp.mu.Lock()
defer mp.mu.Unlock()
mp.executionPoints = nil
}
// PreBind is the function invoked by the framework at "prebind" extension
// point.
func (mp *MultipointExample) PreBind(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
// PreBind could be called concurrently for different pods.
mp.mu.Lock()
defer mp.mu.Unlock()
mp.numRuns++
mp.executionPoints = append(mp.executionPoints, "pre-bind")
if pod == nil {
return framework.NewStatus(framework.Error, "pod must not be nil")
}
@@ -72,8 +87,6 @@ func New(config *runtime.Unknown, _ framework.FrameworkHandle) (framework.Plugin
klog.Error("MultipointExample configuration cannot be empty")
return nil, fmt.Errorf("MultipointExample configuration cannot be empty")
}
mp := MultipointExample{
mpState: make(map[int]string),
}
mp := MultipointExample{}
return &mp, nil
}