mirror of
https://github.com/kemko/nomad.git
synced 2026-01-09 20:05:42 +03:00
api: restructure client
This commit is contained in:
88
api/compose_test.go
Normal file
88
api/compose_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompose(t *testing.T) {
|
||||
// Compose a task
|
||||
task := NewTask("mytask", "docker").
|
||||
SetConfig("foo", "bar").
|
||||
SetConfig("baz", "zip")
|
||||
|
||||
// Require some amount of resources
|
||||
task.Require(&Resources{
|
||||
CPU: 1.25,
|
||||
MemoryMB: 1024,
|
||||
DiskMB: 2048,
|
||||
IOPS: 1024,
|
||||
Networks: []*NetworkResource{
|
||||
&NetworkResource{
|
||||
CIDR: "0.0.0.0/0",
|
||||
MBits: 100,
|
||||
ReservedPorts: []int{80, 443},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Compose a task group
|
||||
grp := NewTaskGroup("mygroup", 2).
|
||||
Constrain(HardConstraint("kernel.name", "=", "linux")).
|
||||
Constrain(SoftConstraint("memory.totalbytes", ">=", "128000000", 1)).
|
||||
SetMeta("foo", "bar").
|
||||
SetMeta("baz", "zip").
|
||||
AddTask(task)
|
||||
|
||||
// Check that the composed result looks correct
|
||||
expect := &TaskGroup{
|
||||
Name: "mygroup",
|
||||
Count: 2,
|
||||
Constraints: []*Constraint{
|
||||
&Constraint{
|
||||
Hard: true,
|
||||
LTarget: "kernel.name",
|
||||
RTarget: "linux",
|
||||
Operand: "=",
|
||||
Weight: 0,
|
||||
},
|
||||
&Constraint{
|
||||
Hard: false,
|
||||
LTarget: "memory.totalbytes",
|
||||
RTarget: "128000000",
|
||||
Operand: ">=",
|
||||
Weight: 1,
|
||||
},
|
||||
},
|
||||
Tasks: []*Task{
|
||||
&Task{
|
||||
Name: "mytask",
|
||||
Driver: "docker",
|
||||
Resources: &Resources{
|
||||
CPU: 1.25,
|
||||
MemoryMB: 1024,
|
||||
DiskMB: 2048,
|
||||
IOPS: 1024,
|
||||
Networks: []*NetworkResource{
|
||||
&NetworkResource{
|
||||
CIDR: "0.0.0.0/0",
|
||||
MBits: 100,
|
||||
ReservedPorts: []int{80, 443},
|
||||
},
|
||||
},
|
||||
},
|
||||
Config: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "zip",
|
||||
},
|
||||
},
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "zip",
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(grp, expect) {
|
||||
t.Fatalf("expect: %#v, got: %#v", expect, grp)
|
||||
}
|
||||
}
|
||||
33
api/constraint.go
Normal file
33
api/constraint.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package api
|
||||
|
||||
// Constraint is used to serialize a job placement constraint.
|
||||
type Constraint struct {
|
||||
Hard bool
|
||||
LTarget string
|
||||
RTarget string
|
||||
Operand string
|
||||
Weight int
|
||||
}
|
||||
|
||||
// HardConstraint is used to create a new hard constraint.
|
||||
func HardConstraint(left, operand, right string) *Constraint {
|
||||
return constraint(left, operand, right, true, 0)
|
||||
}
|
||||
|
||||
// SoftConstraint is used to create a new soft constraint. It
|
||||
// takes an additional weight parameter to allow balancing
|
||||
// multiple soft constraints amongst eachother.
|
||||
func SoftConstraint(left, operand, right string, weight int) *Constraint {
|
||||
return constraint(left, operand, right, false, weight)
|
||||
}
|
||||
|
||||
// constraint generates a new job placement constraint.
|
||||
func constraint(left, operand, right string, hard bool, weight int) *Constraint {
|
||||
return &Constraint{
|
||||
Hard: hard,
|
||||
LTarget: left,
|
||||
RTarget: right,
|
||||
Operand: operand,
|
||||
Weight: weight,
|
||||
}
|
||||
}
|
||||
32
api/constraint_test.go
Normal file
32
api/constraint_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompose_Constraints(t *testing.T) {
|
||||
c := HardConstraint("kernel.name", "=", "darwin")
|
||||
expect := &Constraint{
|
||||
Hard: true,
|
||||
LTarget: "kernel.name",
|
||||
RTarget: "darwin",
|
||||
Operand: "=",
|
||||
Weight: 0,
|
||||
}
|
||||
if !reflect.DeepEqual(c, expect) {
|
||||
t.Fatalf("expect: %#v, got: %#v", expect, c)
|
||||
}
|
||||
|
||||
c = SoftConstraint("memory.totalbytes", ">=", "250000000", 5)
|
||||
expect = &Constraint{
|
||||
Hard: false,
|
||||
LTarget: "memory.totalbytes",
|
||||
RTarget: "250000000",
|
||||
Operand: ">=",
|
||||
Weight: 5,
|
||||
}
|
||||
if !reflect.DeepEqual(c, expect) {
|
||||
t.Fatalf("expect: %#v, got: %#v", expect, c)
|
||||
}
|
||||
}
|
||||
142
api/jobs.go
142
api/jobs.go
@@ -97,145 +97,3 @@ type registerJobRequest struct {
|
||||
type registerJobResponse struct {
|
||||
EvalID string
|
||||
}
|
||||
|
||||
// Constraint is used to serialize a job placement constraint.
|
||||
type Constraint struct {
|
||||
Hard bool
|
||||
LTarget string
|
||||
RTarget string
|
||||
Operand string
|
||||
Weight int
|
||||
}
|
||||
|
||||
// HardConstraint is used to create a new hard constraint.
|
||||
func HardConstraint(left, operand, right string) *Constraint {
|
||||
return constraint(left, operand, right, true, 0)
|
||||
}
|
||||
|
||||
// SoftConstraint is used to create a new soft constraint. It
|
||||
// takes an additional weight parameter to allow balancing
|
||||
// multiple soft constraints amongst eachother.
|
||||
func SoftConstraint(left, operand, right string, weight int) *Constraint {
|
||||
return constraint(left, operand, right, false, weight)
|
||||
}
|
||||
|
||||
// constraint generates a new job placement constraint.
|
||||
func constraint(left, operand, right string, hard bool, weight int) *Constraint {
|
||||
return &Constraint{
|
||||
Hard: hard,
|
||||
LTarget: left,
|
||||
RTarget: right,
|
||||
Operand: operand,
|
||||
Weight: weight,
|
||||
}
|
||||
}
|
||||
|
||||
// TaskGroup is the unit of scheduling.
|
||||
type TaskGroup struct {
|
||||
Name string
|
||||
Count int
|
||||
Constraints []*Constraint
|
||||
Tasks []*Task
|
||||
Meta map[string]string
|
||||
}
|
||||
|
||||
// NewTaskGroup creates a new TaskGroup.
|
||||
func NewTaskGroup(name string, count int) *TaskGroup {
|
||||
return &TaskGroup{
|
||||
Name: name,
|
||||
Count: count,
|
||||
}
|
||||
}
|
||||
|
||||
// Constrain is used to add a constraint to a task group.
|
||||
func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
|
||||
g.Constraints = append(g.Constraints, c)
|
||||
return g
|
||||
}
|
||||
|
||||
// AddMeta is used to add a meta k/v pair to a task group
|
||||
func (g *TaskGroup) AddMeta(key, val string) *TaskGroup {
|
||||
if g.Meta == nil {
|
||||
g.Meta = make(map[string]string)
|
||||
}
|
||||
g.Meta[key] = val
|
||||
return g
|
||||
}
|
||||
|
||||
// AddTask is used to add a new task to a task group.
|
||||
func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
|
||||
g.Tasks = append(g.Tasks, t)
|
||||
return g
|
||||
}
|
||||
|
||||
// Task is a single process in a task group.
|
||||
type Task struct {
|
||||
Name string
|
||||
Driver string
|
||||
Config map[string]string
|
||||
Constraints []*Constraint
|
||||
Resources *Resources
|
||||
Meta map[string]string
|
||||
}
|
||||
|
||||
// NewTask creates and initializes a new Task.
|
||||
func NewTask(name, driver string) *Task {
|
||||
return &Task{
|
||||
Name: name,
|
||||
Driver: driver,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure is used to configure a single k/v pair on
|
||||
// the task.
|
||||
func (t *Task) Configure(key, val string) *Task {
|
||||
if t.Config == nil {
|
||||
t.Config = make(map[string]string)
|
||||
}
|
||||
t.Config[key] = val
|
||||
return t
|
||||
}
|
||||
|
||||
// AddMeta is used to add metadata k/v pairs to the task.
|
||||
func (t *Task) AddMeta(key, val string) *Task {
|
||||
if t.Meta == nil {
|
||||
t.Meta = make(map[string]string)
|
||||
}
|
||||
t.Meta[key] = val
|
||||
return t
|
||||
}
|
||||
|
||||
// Require is used to add resource requirements to a task.
|
||||
// It creates and initializes the task resources.
|
||||
func (t *Task) Require(r *Resources) *Task {
|
||||
if t.Resources == nil {
|
||||
t.Resources = &Resources{}
|
||||
}
|
||||
if r == nil {
|
||||
return t
|
||||
}
|
||||
t.Resources.CPU += r.CPU
|
||||
t.Resources.MemoryMB += r.MemoryMB
|
||||
t.Resources.DiskMB += r.DiskMB
|
||||
t.Resources.IOPS += r.IOPS
|
||||
return t
|
||||
}
|
||||
|
||||
// Resources encapsulates the required resources of
|
||||
// a given task or task group.
|
||||
type Resources struct {
|
||||
CPU float64
|
||||
MemoryMB int
|
||||
DiskMB int
|
||||
IOPS int
|
||||
Networks []*NetworkResource
|
||||
}
|
||||
|
||||
// NetworkResource is used to describe required network
|
||||
// resources of a given task.
|
||||
type NetworkResource struct {
|
||||
Public bool
|
||||
CIDR string
|
||||
ReservedPorts []int
|
||||
MBits int
|
||||
}
|
||||
|
||||
@@ -178,82 +178,3 @@ func TestJobs_Delete(t *testing.T) {
|
||||
t.Fatalf("expected 0 jobs, got: %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobs_Constraints(t *testing.T) {
|
||||
{
|
||||
c := HardConstraint("kernel.name", "=", "darwin")
|
||||
expect := &Constraint{
|
||||
Hard: true,
|
||||
LTarget: "kernel.name",
|
||||
RTarget: "darwin",
|
||||
Operand: "=",
|
||||
Weight: 0,
|
||||
}
|
||||
if !reflect.DeepEqual(c, expect) {
|
||||
t.Fatalf("expect: %#v, got: %#v", expect, c)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
c := SoftConstraint("memory.totalbytes", ">=", "250000000", 5)
|
||||
expect := &Constraint{
|
||||
Hard: false,
|
||||
LTarget: "memory.totalbytes",
|
||||
RTarget: "250000000",
|
||||
Operand: ">=",
|
||||
Weight: 5,
|
||||
}
|
||||
if !reflect.DeepEqual(c, expect) {
|
||||
t.Fatalf("expect: %#v, got: %#v", expect, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobs_Compose(t *testing.T) {
|
||||
// Compose a task
|
||||
task := NewTask("mytask", "docker").
|
||||
Require(&Resources{CPU: 1.25, MemoryMB: 1024}).
|
||||
Require(&Resources{DiskMB: 2048}).
|
||||
Configure("foo", "bar").
|
||||
Configure("baz", "zip")
|
||||
|
||||
// Compose a task group
|
||||
grp := NewTaskGroup("mytask", 2).
|
||||
Constrain(HardConstraint("kernel.name", "=", "linux")).
|
||||
Constrain(SoftConstraint("memory.totalbytes", ">=", "128000000", 1)).
|
||||
AddMeta("foo", "bar").
|
||||
AddMeta("baz", "zip").
|
||||
AddTask(task)
|
||||
|
||||
// Check that the composed result looks correct
|
||||
expect := &TaskGroup{
|
||||
Name: "mytask",
|
||||
Count: 2,
|
||||
Constraints: []*Constraint{
|
||||
HardConstraint("kernel.name", "=", "linux"),
|
||||
SoftConstraint("memory.totalbytes", ">=", "128000000", 1),
|
||||
},
|
||||
Tasks: []*Task{
|
||||
&Task{
|
||||
Name: "mytask",
|
||||
Driver: "docker",
|
||||
Resources: &Resources{
|
||||
CPU: 1.25,
|
||||
MemoryMB: 1024,
|
||||
DiskMB: 2048,
|
||||
},
|
||||
Config: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "zip",
|
||||
},
|
||||
},
|
||||
},
|
||||
Meta: map[string]string{
|
||||
"foo": "bar",
|
||||
"baz": "zip",
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(grp, expect) {
|
||||
t.Fatalf("expect: %#v, got: %#v", expect, grp)
|
||||
}
|
||||
}
|
||||
|
||||
20
api/resources.go
Normal file
20
api/resources.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package api
|
||||
|
||||
// Resources encapsulates the required resources of
|
||||
// a given task or task group.
|
||||
type Resources struct {
|
||||
CPU float64
|
||||
MemoryMB int
|
||||
DiskMB int
|
||||
IOPS int
|
||||
Networks []*NetworkResource
|
||||
}
|
||||
|
||||
// NetworkResource is used to describe required network
|
||||
// resources of a given task.
|
||||
type NetworkResource struct {
|
||||
Public bool
|
||||
CIDR string
|
||||
ReservedPorts []int
|
||||
MBits int
|
||||
}
|
||||
82
api/tasks.go
Normal file
82
api/tasks.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package api
|
||||
|
||||
// TaskGroup is the unit of scheduling.
|
||||
type TaskGroup struct {
|
||||
Name string
|
||||
Count int
|
||||
Constraints []*Constraint
|
||||
Tasks []*Task
|
||||
Meta map[string]string
|
||||
}
|
||||
|
||||
// NewTaskGroup creates a new TaskGroup.
|
||||
func NewTaskGroup(name string, count int) *TaskGroup {
|
||||
return &TaskGroup{
|
||||
Name: name,
|
||||
Count: count,
|
||||
}
|
||||
}
|
||||
|
||||
// Constrain is used to add a constraint to a task group.
|
||||
func (g *TaskGroup) Constrain(c *Constraint) *TaskGroup {
|
||||
g.Constraints = append(g.Constraints, c)
|
||||
return g
|
||||
}
|
||||
|
||||
// AddMeta is used to add a meta k/v pair to a task group
|
||||
func (g *TaskGroup) SetMeta(key, val string) *TaskGroup {
|
||||
if g.Meta == nil {
|
||||
g.Meta = make(map[string]string)
|
||||
}
|
||||
g.Meta[key] = val
|
||||
return g
|
||||
}
|
||||
|
||||
// AddTask is used to add a new task to a task group.
|
||||
func (g *TaskGroup) AddTask(t *Task) *TaskGroup {
|
||||
g.Tasks = append(g.Tasks, t)
|
||||
return g
|
||||
}
|
||||
|
||||
// Task is a single process in a task group.
|
||||
type Task struct {
|
||||
Name string
|
||||
Driver string
|
||||
Config map[string]string
|
||||
Constraints []*Constraint
|
||||
Resources *Resources
|
||||
Meta map[string]string
|
||||
}
|
||||
|
||||
// NewTask creates and initializes a new Task.
|
||||
func NewTask(name, driver string) *Task {
|
||||
return &Task{
|
||||
Name: name,
|
||||
Driver: driver,
|
||||
}
|
||||
}
|
||||
|
||||
// Configure is used to configure a single k/v pair on
|
||||
// the task.
|
||||
func (t *Task) SetConfig(key, val string) *Task {
|
||||
if t.Config == nil {
|
||||
t.Config = make(map[string]string)
|
||||
}
|
||||
t.Config[key] = val
|
||||
return t
|
||||
}
|
||||
|
||||
// SetMeta is used to add metadata k/v pairs to the task.
|
||||
func (t *Task) SetMeta(key, val string) *Task {
|
||||
if t.Meta == nil {
|
||||
t.Meta = make(map[string]string)
|
||||
}
|
||||
t.Meta[key] = val
|
||||
return t
|
||||
}
|
||||
|
||||
// Require is used to add resource requirements to a task.
|
||||
func (t *Task) Require(r *Resources) *Task {
|
||||
t.Resources = r
|
||||
return t
|
||||
}
|
||||
Reference in New Issue
Block a user