github.com/anuvu/nomad@v0.8.7-atom1/api/allocations.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"time"
     7  )
     8  
     9  var (
    10  	// NodeDownErr marks an operation as not able to complete since the node is
    11  	// down.
    12  	NodeDownErr = fmt.Errorf("node down")
    13  )
    14  
    15  // Allocations is used to query the alloc-related endpoints.
    16  type Allocations struct {
    17  	client *Client
    18  }
    19  
    20  // Allocations returns a handle on the allocs endpoints.
    21  func (c *Client) Allocations() *Allocations {
    22  	return &Allocations{client: c}
    23  }
    24  
    25  // List returns a list of all of the allocations.
    26  func (a *Allocations) List(q *QueryOptions) ([]*AllocationListStub, *QueryMeta, error) {
    27  	var resp []*AllocationListStub
    28  	qm, err := a.client.query("/v1/allocations", &resp, q)
    29  	if err != nil {
    30  		return nil, nil, err
    31  	}
    32  	sort.Sort(AllocIndexSort(resp))
    33  	return resp, qm, nil
    34  }
    35  
    36  func (a *Allocations) PrefixList(prefix string) ([]*AllocationListStub, *QueryMeta, error) {
    37  	return a.List(&QueryOptions{Prefix: prefix})
    38  }
    39  
    40  // Info is used to retrieve a single allocation.
    41  func (a *Allocations) Info(allocID string, q *QueryOptions) (*Allocation, *QueryMeta, error) {
    42  	var resp Allocation
    43  	qm, err := a.client.query("/v1/allocation/"+allocID, &resp, q)
    44  	if err != nil {
    45  		return nil, nil, err
    46  	}
    47  	return &resp, qm, nil
    48  }
    49  
    50  func (a *Allocations) Stats(alloc *Allocation, q *QueryOptions) (*AllocResourceUsage, error) {
    51  	var resp AllocResourceUsage
    52  	path := fmt.Sprintf("/v1/client/allocation/%s/stats", alloc.ID)
    53  	_, err := a.client.query(path, &resp, q)
    54  	return &resp, err
    55  }
    56  
    57  func (a *Allocations) GC(alloc *Allocation, q *QueryOptions) error {
    58  	nodeClient, err := a.client.GetNodeClient(alloc.NodeID, q)
    59  	if err != nil {
    60  		return err
    61  	}
    62  
    63  	var resp struct{}
    64  	_, err = nodeClient.query("/v1/client/allocation/"+alloc.ID+"/gc", &resp, nil)
    65  	return err
    66  }
    67  
    68  // Allocation is used for serialization of allocations.
    69  type Allocation struct {
    70  	ID                 string
    71  	Namespace          string
    72  	EvalID             string
    73  	Name               string
    74  	NodeID             string
    75  	JobID              string
    76  	Job                *Job
    77  	TaskGroup          string
    78  	Resources          *Resources
    79  	TaskResources      map[string]*Resources
    80  	Services           map[string]string
    81  	Metrics            *AllocationMetric
    82  	DesiredStatus      string
    83  	DesiredDescription string
    84  	DesiredTransition  DesiredTransition
    85  	ClientStatus       string
    86  	ClientDescription  string
    87  	TaskStates         map[string]*TaskState
    88  	DeploymentID       string
    89  	DeploymentStatus   *AllocDeploymentStatus
    90  	FollowupEvalID     string
    91  	PreviousAllocation string
    92  	NextAllocation     string
    93  	RescheduleTracker  *RescheduleTracker
    94  	CreateIndex        uint64
    95  	ModifyIndex        uint64
    96  	AllocModifyIndex   uint64
    97  	CreateTime         int64
    98  	ModifyTime         int64
    99  }
   100  
   101  // AllocationMetric is used to deserialize allocation metrics.
   102  type AllocationMetric struct {
   103  	NodesEvaluated     int
   104  	NodesFiltered      int
   105  	NodesAvailable     map[string]int
   106  	ClassFiltered      map[string]int
   107  	ConstraintFiltered map[string]int
   108  	NodesExhausted     int
   109  	ClassExhausted     map[string]int
   110  	DimensionExhausted map[string]int
   111  	QuotaExhausted     []string
   112  	Scores             map[string]float64
   113  	AllocationTime     time.Duration
   114  	CoalescedFailures  int
   115  }
   116  
   117  // AllocationListStub is used to return a subset of an allocation
   118  // during list operations.
   119  type AllocationListStub struct {
   120  	ID                 string
   121  	EvalID             string
   122  	Name               string
   123  	NodeID             string
   124  	JobID              string
   125  	JobVersion         uint64
   126  	TaskGroup          string
   127  	DesiredStatus      string
   128  	DesiredDescription string
   129  	ClientStatus       string
   130  	ClientDescription  string
   131  	TaskStates         map[string]*TaskState
   132  	DeploymentStatus   *AllocDeploymentStatus
   133  	FollowupEvalID     string
   134  	RescheduleTracker  *RescheduleTracker
   135  	CreateIndex        uint64
   136  	ModifyIndex        uint64
   137  	CreateTime         int64
   138  	ModifyTime         int64
   139  }
   140  
   141  // AllocDeploymentStatus captures the status of the allocation as part of the
   142  // deployment. This can include things like if the allocation has been marked as
   143  // healthy.
   144  type AllocDeploymentStatus struct {
   145  	Healthy     *bool
   146  	Timestamp   time.Time
   147  	Canary      bool
   148  	ModifyIndex uint64
   149  }
   150  
   151  // AllocIndexSort reverse sorts allocs by CreateIndex.
   152  type AllocIndexSort []*AllocationListStub
   153  
   154  func (a AllocIndexSort) Len() int {
   155  	return len(a)
   156  }
   157  
   158  func (a AllocIndexSort) Less(i, j int) bool {
   159  	return a[i].CreateIndex > a[j].CreateIndex
   160  }
   161  
   162  func (a AllocIndexSort) Swap(i, j int) {
   163  	a[i], a[j] = a[j], a[i]
   164  }
   165  
   166  // RescheduleInfo is used to calculate remaining reschedule attempts
   167  // according to the given time and the task groups reschedule policy
   168  func (a Allocation) RescheduleInfo(t time.Time) (int, int) {
   169  	var reschedulePolicy *ReschedulePolicy
   170  	for _, tg := range a.Job.TaskGroups {
   171  		if *tg.Name == a.TaskGroup {
   172  			reschedulePolicy = tg.ReschedulePolicy
   173  		}
   174  	}
   175  	if reschedulePolicy == nil {
   176  		return 0, 0
   177  	}
   178  	availableAttempts := *reschedulePolicy.Attempts
   179  	interval := *reschedulePolicy.Interval
   180  	attempted := 0
   181  
   182  	// Loop over reschedule tracker to find attempts within the restart policy's interval
   183  	if a.RescheduleTracker != nil && availableAttempts > 0 && interval > 0 {
   184  		for j := len(a.RescheduleTracker.Events) - 1; j >= 0; j-- {
   185  			lastAttempt := a.RescheduleTracker.Events[j].RescheduleTime
   186  			timeDiff := t.UTC().UnixNano() - lastAttempt
   187  			if timeDiff < interval.Nanoseconds() {
   188  				attempted += 1
   189  			}
   190  		}
   191  	}
   192  	return attempted, availableAttempts
   193  }
   194  
   195  // RescheduleTracker encapsulates previous reschedule events
   196  type RescheduleTracker struct {
   197  	Events []*RescheduleEvent
   198  }
   199  
   200  // RescheduleEvent is used to keep track of previous attempts at rescheduling an allocation
   201  type RescheduleEvent struct {
   202  	// RescheduleTime is the timestamp of a reschedule attempt
   203  	RescheduleTime int64
   204  
   205  	// PrevAllocID is the ID of the previous allocation being restarted
   206  	PrevAllocID string
   207  
   208  	// PrevNodeID is the node ID of the previous allocation
   209  	PrevNodeID string
   210  }
   211  
   212  // DesiredTransition is used to mark an allocation as having a desired state
   213  // transition. This information can be used by the scheduler to make the
   214  // correct decision.
   215  type DesiredTransition struct {
   216  	// Migrate is used to indicate that this allocation should be stopped and
   217  	// migrated to another node.
   218  	Migrate *bool
   219  
   220  	// Reschedule is used to indicate that this allocation is eligible to be
   221  	// rescheduled.
   222  	Reschedule *bool
   223  }
   224  
   225  // ShouldMigrate returns whether the transition object dictates a migration.
   226  func (d DesiredTransition) ShouldMigrate() bool {
   227  	return d.Migrate != nil && *d.Migrate
   228  }