open-nomad/api/allocations.go

342 lines
9.2 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")
)
const (
AllocDesiredStatusRun = "run" // Allocation should run
AllocDesiredStatusStop = "stop" // Allocation should stop
AllocDesiredStatusEvict = "evict" // Allocation should stop, and was evicted
)
const (
AllocClientStatusPending = "pending"
AllocClientStatusRunning = "running"
AllocClientStatusComplete = "complete"
AllocClientStatusFailed = "failed"
AllocClientStatusLost = "lost"
)
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
}
func (a *Allocations) Restart(alloc *Allocation, taskName string, q *QueryOptions) error {
req := AllocationRestartRequest{
TaskName: taskName,
}
var resp struct{}
_, err := a.client.putQuery("/v1/client/allocation/"+alloc.ID+"/restart", &req, &resp, q)
return err
}
func (a *Allocations) Stop(alloc *Allocation, q *QueryOptions) (*AllocStopResponse, error) {
var resp AllocStopResponse
_, err := a.client.putQuery("/v1/allocation/"+alloc.ID+"/stop", nil, &resp, q)
return &resp, err
}
// AllocStopResponse is the response to an `AllocStopRequest`
type AllocStopResponse struct {
// EvalID is the id of the follow up evalution for the rescheduled alloc.
EvalID string
WriteMeta
}
func (a *Allocations) Signal(alloc *Allocation, q *QueryOptions, task, signal string) error {
nodeClient, err := a.client.GetNodeClient(alloc.NodeID, q)
if err != nil {
return err
}
req := AllocSignalRequest{
AllocID: alloc.ID,
Signal: signal,
Task: task,
}
var resp GenericResponse
_, err = nodeClient.putQuery("/v1/client/allocation/"+alloc.ID+"/signal", &req, &resp, q)
return err
}
2015-09-09 00:49:31 +00:00
// Allocation is used for serialization of allocations.
type Allocation struct {
ID string
Namespace string
EvalID string
Name string
NodeID string
NodeName string
JobID string
Job *Job
TaskGroup string
Resources *Resources
TaskResources map[string]*Resources
AllocatedResources *AllocatedResources
Services map[string]string
Metrics *AllocationMetric
DesiredStatus string
DesiredDescription string
DesiredTransition DesiredTransition
ClientStatus string
ClientDescription string
TaskStates map[string]*TaskState
DeploymentID string
DeploymentStatus *AllocDeploymentStatus
FollowupEvalID string
PreviousAllocation string
NextAllocation string
RescheduleTracker *RescheduleTracker
PreemptedAllocations []string
PreemptedByAllocation string
CreateIndex uint64
ModifyIndex uint64
AllocModifyIndex uint64
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
2018-08-18 01:11:07 +00:00
// Deprecated, replaced with ScoreMetaData
Scores map[string]float64
AllocationTime time.Duration
CoalescedFailures int
ScoreMetaData []*NodeScoreMeta
}
// NodeScoreMeta is used to serialize node scoring metadata
// displayed in the CLI during verbose mode
type NodeScoreMeta struct {
NodeID string
Scores map[string]float64
NormScore 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 {
ID string
EvalID string
Name string
Namespace string
NodeID string
NodeName string
JobID string
JobType string
JobVersion uint64
TaskGroup string
DesiredStatus string
DesiredDescription string
ClientStatus string
ClientDescription string
TaskStates map[string]*TaskState
DeploymentStatus *AllocDeploymentStatus
FollowupEvalID string
RescheduleTracker *RescheduleTracker
PreemptedAllocations []string
PreemptedByAllocation string
CreateIndex uint64
ModifyIndex uint64
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
}
2018-10-02 20:36:04 +00:00
type AllocatedResources struct {
Tasks map[string]*AllocatedTaskResources
Shared AllocatedSharedResources
}
type AllocatedTaskResources struct {
Cpu AllocatedCpuResources
Memory AllocatedMemoryResources
Networks []*NetworkResource
}
type AllocatedSharedResources struct {
2018-10-16 22:34:32 +00:00
DiskMB int64
2018-10-02 20:36:04 +00:00
}
type AllocatedCpuResources struct {
2018-10-16 22:34:32 +00:00
CpuShares int64
2018-10-02 20:36:04 +00:00
}
type AllocatedMemoryResources struct {
2018-10-16 22:34:32 +00:00
MemoryMB int64
2018-10-02 20:36:04 +00:00
}
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
}
type AllocationRestartRequest struct {
TaskName string
}
type AllocSignalRequest struct {
AllocID string
Task string
Signal string
}
// GenericResponse is used to respond to a request where no
// specific response information is needed.
type GenericResponse struct {
WriteMeta
}
// 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
}