From 5d1e5151129bd609742342e9bebdafea3a38e962 Mon Sep 17 00:00:00 2001 From: Ryan Uber Date: Wed, 9 Sep 2015 13:02:39 -0700 Subject: [PATCH] api: restructure client --- api/compose_test.go | 88 +++++++++++++++++++++++++ api/constraint.go | 33 ++++++++++ api/constraint_test.go | 32 ++++++++++ api/jobs.go | 142 ----------------------------------------- api/jobs_test.go | 79 ----------------------- api/resources.go | 20 ++++++ api/tasks.go | 82 ++++++++++++++++++++++++ 7 files changed, 255 insertions(+), 221 deletions(-) create mode 100644 api/compose_test.go create mode 100644 api/constraint.go create mode 100644 api/constraint_test.go create mode 100644 api/resources.go create mode 100644 api/tasks.go diff --git a/api/compose_test.go b/api/compose_test.go new file mode 100644 index 000000000..49cff536e --- /dev/null +++ b/api/compose_test.go @@ -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) + } +} diff --git a/api/constraint.go b/api/constraint.go new file mode 100644 index 000000000..1a0f3233a --- /dev/null +++ b/api/constraint.go @@ -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, + } +} diff --git a/api/constraint_test.go b/api/constraint_test.go new file mode 100644 index 000000000..a8c7b9838 --- /dev/null +++ b/api/constraint_test.go @@ -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) + } +} diff --git a/api/jobs.go b/api/jobs.go index ea3f351c8..308538a6a 100644 --- a/api/jobs.go +++ b/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 -} diff --git a/api/jobs_test.go b/api/jobs_test.go index d7756cd2a..99d5a009a 100644 --- a/api/jobs_test.go +++ b/api/jobs_test.go @@ -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) - } -} diff --git a/api/resources.go b/api/resources.go new file mode 100644 index 000000000..64739df5a --- /dev/null +++ b/api/resources.go @@ -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 +} diff --git a/api/tasks.go b/api/tasks.go new file mode 100644 index 000000000..a1858a0d0 --- /dev/null +++ b/api/tasks.go @@ -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 +}