scheduler: implementing driver iterator

This commit is contained in:
Armon Dadgar
2015-08-13 10:19:46 -07:00
parent acb8370d0c
commit fff84e8487
2 changed files with 83 additions and 37 deletions

View File

@@ -1,6 +1,7 @@
package scheduler
import (
"fmt"
"math/rand"
"github.com/hashicorp/nomad/nomad/structs"
@@ -59,6 +60,53 @@ func NewRandomIterator(ctx Context, nodes []*structs.Node) *StaticIterator {
return NewStaticIterator(ctx, nodes)
}
// DriverIterator is a FeasibleIterator which returns nodes that
// have the drivers necessary to scheduler a task group.
type DriverIterator struct {
ctx Context
source FeasibleIterator
drivers map[string]struct{}
}
// NewDriverIterator creates a DriverIterator from a source and set of drivers
func NewDriverIterator(ctx Context, source FeasibleIterator, drivers map[string]struct{}) *DriverIterator {
iter := &DriverIterator{
ctx: ctx,
source: source,
drivers: drivers,
}
return iter
}
func (iter *DriverIterator) Next() *structs.Node {
for {
// Get the next option from the source
option := iter.source.Next()
if option == nil {
return nil
}
// Use this node if possible
if iter.hasDrivers(option) {
return option
}
}
}
// hasDrivers is used to check if the node has all the appropriate
// drivers for this task group. Drivers are registered as node attribute
// like "driver.docker=1" with their corresponding version.
func (iter *DriverIterator) hasDrivers(option *structs.Node) bool {
for driver := range iter.drivers {
driverStr := fmt.Sprintf("driver.%s", driver)
_, ok := option.Attributes[driverStr]
if !ok {
return false
}
}
return true
}
// ConstraintIterator is a FeasibleIterator which returns nodes
// that match a given set of constraints. This is used to filter
// on job, task group, and task constraints.
@@ -97,40 +145,3 @@ func (iter *ConstraintIterator) meetsConstraints(option *structs.Node) bool {
// TODO:
return true
}
// DriverIterator is a FeasibleIterator which returns nodes that
// have the drivers necessary to scheduler a task group.
type DriverIterator struct {
ctx Context
source FeasibleIterator
drivers map[string]struct{}
}
// NewDriverIterator creates a DriverIterator from a source and set of drivers
func NewDriverIterator(ctx Context, source FeasibleIterator, drivers map[string]struct{}) *DriverIterator {
iter := &DriverIterator{
ctx: ctx,
source: source,
drivers: drivers,
}
return iter
}
func (iter *DriverIterator) Next() *structs.Node {
for {
// Get the next option from the source
option := iter.source.Next()
if option == nil {
return nil
}
// Use this node if possible
if iter.hasDrivers(option) {
return option
}
}
}
func (iter *DriverIterator) hasDrivers(option *structs.Node) bool {
return true
}

View File

@@ -35,3 +35,38 @@ func TestRandomIterator(t *testing.T) {
t.Fatalf("same order")
}
}
func TestDriverIterator(t *testing.T) {
ctx := NewEvalContext()
nodes := []*structs.Node{
mock.Node(),
mock.Node(),
mock.Node(),
}
static := NewStaticIterator(ctx, nodes)
nodes[0].Attributes["driver.foo"] = "2"
nodes[2].Attributes["driver.foo"] = "2"
drivers := map[string]struct{}{
"docker": struct{}{},
"foo": struct{}{},
}
driver := NewDriverIterator(ctx, static, drivers)
var out []*structs.Node
for {
next := driver.Next()
if next == nil {
break
}
out = append(out, next)
}
if len(out) != 2 {
t.Fatalf("missing nodes")
}
if out[0] != nodes[0] || out[1] != nodes[2] {
t.Fatalf("bad: %#v", out)
}
}