open-nomad/api/allocations.go

237 lines
6.6 KiB
Go
Raw Normal View History

2015-09-08 22:37:07 +00:00
package api
2015-09-14 02:55:47 +00:00
import (
2016-04-29 20:03:02 +00:00
"fmt"
2015-09-17 19:40:51 +00:00
"sort"
2015-09-14 02:55:47 +00:00
"time"
)
var (
2016-10-25 18:31:09 +00:00
// NodeDownErr marks an operation as not able to complete since the node is
// down.
NodeDownErr = fmt.Errorf("node down")
)
2015-09-09 00:49:31 +00:00
// Allocations is used to query the alloc-related endpoints.
type Allocations struct {
2015-09-08 22:37:07 +00:00
client *Client
}
2015-09-09 00:49:31 +00:00
// Allocations returns a handle on the allocs endpoints.
func (c *Client) Allocations() *Allocations {
return &Allocations{client: c}
2015-09-08 22:37:07 +00:00
}
// List returns a list of all of the allocations.
2015-09-14 02:55:47 +00:00
func (a *Allocations) List(q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
var resp []*AllocationListStub
2015-09-09 20:18:50 +00:00
qm, err := a.client.query("/v1/allocations", &resp, q)
2015-09-08 22:37:07 +00:00
if err != nil {
2015-09-08 23:45:16 +00:00
return nil, nil, err
2015-09-08 22:37:07 +00:00
}
2015-09-17 19:40:51 +00:00
sort.Sort(AllocIndexSort(resp))
2015-09-08 23:45:16 +00:00
return resp, qm, nil
2015-09-08 22:37:07 +00:00
}
func (a *Allocations) PrefixList(prefix string) ([]*AllocationListStub, *QueryMeta, error) {
return a.List(&QueryOptions{Prefix: prefix})
}
2015-09-09 20:18:50 +00:00
// Info is used to retrieve a single allocation.
func (a *Allocations) Info(allocID string, q *QueryOptions) (*Allocation, *QueryMeta, error) {
var resp Allocation
qm, err := a.client.query("/v1/allocation/"+allocID, &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, qm, nil
}
func (a *Allocations) Stats(alloc *Allocation, q *QueryOptions) (*AllocResourceUsage, error) {
var resp AllocResourceUsage
path := fmt.Sprintf("/v1/client/allocation/%s/stats", alloc.ID)
_, err := a.client.query(path, &resp, q)
return &resp, err
2016-04-29 20:03:02 +00:00
}
func (a *Allocations) GC(alloc *Allocation, q *QueryOptions) error {
nodeClient, err := a.client.GetNodeClient(alloc.NodeID, q)
if err != nil {
return err
}
var resp struct{}
_, err = nodeClient.query("/v1/client/allocation/"+alloc.ID+"/gc", &resp, nil)
return err
}
2015-09-09 00:49:31 +00:00
// Allocation is used for serialization of allocations.
type Allocation struct {
2015-09-14 02:55:47 +00:00
ID string
2017-09-07 23:56:15 +00:00
Namespace string
2015-09-14 02:55:47 +00:00
EvalID string
Name string
NodeID string
JobID string
Job *Job
TaskGroup string
Resources *Resources
TaskResources map[string]*Resources
2015-12-14 22:53:49 +00:00
Services map[string]string
2015-09-14 02:55:47 +00:00
Metrics *AllocationMetric
DesiredStatus string
DesiredDescription string
DesiredTransition DesiredTransition
2015-09-14 02:55:47 +00:00
ClientStatus string
ClientDescription string
2015-11-12 23:28:22 +00:00
TaskStates map[string]*TaskState
2017-07-02 21:01:33 +00:00
DeploymentID string
2017-06-26 21:23:52 +00:00
DeploymentStatus *AllocDeploymentStatus
FollowupEvalID string
PreviousAllocation string
NextAllocation string
2018-01-23 01:58:23 +00:00
RescheduleTracker *RescheduleTracker
2015-09-14 02:55:47 +00:00
CreateIndex uint64
ModifyIndex uint64
AllocModifyIndex uint64
2016-02-09 05:58:05 +00:00
CreateTime int64
ModifyTime int64
2015-09-14 02:55:47 +00:00
}
// AllocationMetric is used to deserialize allocation metrics.
type AllocationMetric struct {
NodesEvaluated int
NodesFiltered int
2016-01-04 22:23:06 +00:00
NodesAvailable map[string]int
2015-09-14 02:55:47 +00:00
ClassFiltered map[string]int
ConstraintFiltered map[string]int
NodesExhausted int
ClassExhausted map[string]int
2015-09-18 19:06:51 +00:00
DimensionExhausted map[string]int
2017-10-13 21:36:02 +00:00
QuotaExhausted []string
2015-09-14 02:55:47 +00:00
Scores map[string]float64
AllocationTime time.Duration
CoalescedFailures int
ScoreMetaData map[string][]*NodeScoreMeta
}
// NodeScoreMeta is used to serialize node scoring metadata
// displayed in the CLI during verbose mode
type NodeScoreMeta struct {
NodeID string
Score float64
2015-09-14 02:55:47 +00:00
}
// AllocationListStub is used to return a subset of an allocation
// during list operations.
type AllocationListStub struct {
2015-09-08 22:37:07 +00:00
ID string
EvalID string
Name string
NodeID string
JobID string
2017-07-07 04:51:13 +00:00
JobVersion uint64
2015-09-08 22:37:07 +00:00
TaskGroup string
DesiredStatus string
DesiredDescription string
ClientStatus string
ClientDescription string
2015-11-12 23:28:22 +00:00
TaskStates map[string]*TaskState
2017-06-26 21:23:52 +00:00
DeploymentStatus *AllocDeploymentStatus
FollowupEvalID string
RescheduleTracker *RescheduleTracker
2015-09-14 02:55:47 +00:00
CreateIndex uint64
ModifyIndex uint64
2016-02-09 05:58:05 +00:00
CreateTime int64
ModifyTime int64
2015-09-08 22:37:07 +00:00
}
2015-09-17 19:40:51 +00:00
2017-06-26 21:23:52 +00:00
// AllocDeploymentStatus captures the status of the allocation as part of the
// deployment. This can include things like if the allocation has been marked as
// healthy.
2017-06-26 21:23:52 +00:00
type AllocDeploymentStatus struct {
Healthy *bool
Timestamp time.Time
Canary bool
2017-06-26 21:23:52 +00:00
ModifyIndex uint64
}
2015-09-17 19:40:51 +00:00
// AllocIndexSort reverse sorts allocs by CreateIndex.
type AllocIndexSort []*AllocationListStub
func (a AllocIndexSort) Len() int {
return len(a)
}
func (a AllocIndexSort) Less(i, j int) bool {
return a[i].CreateIndex > a[j].CreateIndex
}
func (a AllocIndexSort) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
// RescheduleInfo is used to calculate remaining reschedule attempts
// according to the given time and the task groups reschedule policy
func (a Allocation) RescheduleInfo(t time.Time) (int, int) {
var reschedulePolicy *ReschedulePolicy
for _, tg := range a.Job.TaskGroups {
if *tg.Name == a.TaskGroup {
reschedulePolicy = tg.ReschedulePolicy
}
}
2018-01-29 22:31:25 +00:00
if reschedulePolicy == nil {
return 0, 0
}
2018-01-29 22:31:25 +00:00
availableAttempts := *reschedulePolicy.Attempts
interval := *reschedulePolicy.Interval
attempted := 0
// Loop over reschedule tracker to find attempts within the restart policy's interval
if a.RescheduleTracker != nil && availableAttempts > 0 && interval > 0 {
for j := len(a.RescheduleTracker.Events) - 1; j >= 0; j-- {
lastAttempt := a.RescheduleTracker.Events[j].RescheduleTime
timeDiff := t.UTC().UnixNano() - lastAttempt
if timeDiff < interval.Nanoseconds() {
attempted += 1
}
}
}
2018-01-29 22:31:25 +00:00
return attempted, availableAttempts
}
// RescheduleTracker encapsulates previous reschedule events
type RescheduleTracker struct {
Events []*RescheduleEvent
}
// RescheduleEvent is used to keep track of previous attempts at rescheduling an allocation
type RescheduleEvent struct {
// RescheduleTime is the timestamp of a reschedule attempt
RescheduleTime int64
// PrevAllocID is the ID of the previous allocation being restarted
PrevAllocID string
// PrevNodeID is the node ID of the previous allocation
PrevNodeID string
}
// DesiredTransition is used to mark an allocation as having a desired state
// transition. This information can be used by the scheduler to make the
// correct decision.
type DesiredTransition struct {
// Migrate is used to indicate that this allocation should be stopped and
// migrated to another node.
Migrate *bool
2018-04-07 00:23:35 +00:00
// Reschedule is used to indicate that this allocation is eligible to be
// rescheduled.
Reschedule *bool
}
// ShouldMigrate returns whether the transition object dictates a migration.
func (d DesiredTransition) ShouldMigrate() bool {
return d.Migrate != nil && *d.Migrate
}