open-nomad/nomad/drainer/draining_node.go

151 lines
3.3 KiB
Go
Raw Normal View History

2018-03-08 23:08:23 +00:00
package drainer
2018-03-02 00:37:19 +00:00
import (
2018-03-06 22:37:37 +00:00
"fmt"
2018-03-02 00:37:19 +00:00
"sync"
"time"
"github.com/hashicorp/nomad/nomad/state"
"github.com/hashicorp/nomad/nomad/structs"
)
type drainingNode struct {
2018-03-06 22:37:37 +00:00
state *state.StateStore
node *structs.Node
l sync.RWMutex
2018-03-02 00:37:19 +00:00
}
2018-03-06 22:37:37 +00:00
func NewDrainingNode(node *structs.Node, state *state.StateStore) *drainingNode {
2018-03-02 00:37:19 +00:00
return &drainingNode{
2018-03-06 22:37:37 +00:00
state: state,
node: node,
2018-03-02 00:37:19 +00:00
}
}
2018-03-03 01:15:38 +00:00
func (n *drainingNode) GetNode() *structs.Node {
n.l.Lock()
defer n.l.Unlock()
return n.node
}
2018-03-02 00:37:19 +00:00
func (n *drainingNode) Update(node *structs.Node) {
n.l.Lock()
defer n.l.Unlock()
n.node = node
}
// DeadlineTime returns if the node has a deadline and if so what it is
func (n *drainingNode) DeadlineTime() (bool, time.Time) {
n.l.RLock()
defer n.l.RUnlock()
// Should never happen
if n.node == nil || n.node.DrainStrategy == nil {
return false, time.Time{}
}
return n.node.DrainStrategy.DeadlineTime()
}
// IsDone returns if the node is done draining batch and service allocs. System
// allocs must be stopped before marking drain complete unless they're being
// ignored.
2018-03-06 22:37:37 +00:00
func (n *drainingNode) IsDone() (bool, error) {
n.l.RLock()
defer n.l.RUnlock()
// Should never happen
if n.node == nil || n.node.DrainStrategy == nil {
return false, fmt.Errorf("node doesn't have a drain strategy set")
}
// Retrieve the allocs on the node
allocs, err := n.state.AllocsByNode(nil, n.node.ID)
if err != nil {
return false, err
}
for _, alloc := range allocs {
// System jobs are only stopped after a node is done draining
// everything else, so ignore them here.
if alloc.Job.Type == structs.JobTypeSystem {
2018-03-06 22:37:37 +00:00
continue
}
// If there is a non-terminal we aren't done
if !alloc.TerminalStatus() {
return false, nil
}
}
return true, nil
}
2018-03-07 23:42:17 +00:00
// TODO test that we return the right thing given the strategies
// RemainingAllocs returns the set of allocations remaining on a node that
// still need to be drained.
func (n *drainingNode) RemainingAllocs() ([]*structs.Allocation, error) {
2018-03-02 00:37:19 +00:00
n.l.RLock()
defer n.l.RUnlock()
2018-03-06 22:37:37 +00:00
// Should never happen
if n.node == nil || n.node.DrainStrategy == nil {
return nil, fmt.Errorf("node doesn't have a drain strategy set")
}
// Grab the relevant drain info
ignoreSystem := n.node.DrainStrategy.IgnoreSystemJobs
// Retrieve the allocs on the node
allocs, err := n.state.AllocsByNode(nil, n.node.ID)
if err != nil {
return nil, err
}
var drain []*structs.Allocation
for _, alloc := range allocs {
// Nothing to do on a terminal allocation
if alloc.TerminalStatus() {
continue
}
// Skip system if configured to
if alloc.Job.Type == structs.JobTypeSystem && ignoreSystem {
continue
}
drain = append(drain, alloc)
}
return drain, nil
2018-03-02 00:37:19 +00:00
}
2018-03-07 22:57:35 +00:00
// RunningServices returns the set of jobs on the node
func (n *drainingNode) RunningServices() ([]structs.NamespacedID, error) {
2018-03-07 22:57:35 +00:00
n.l.RLock()
defer n.l.RUnlock()
// Retrieve the allocs on the node
allocs, err := n.state.AllocsByNode(nil, n.node.ID)
if err != nil {
return nil, err
}
jobIDs := make(map[structs.NamespacedID]struct{})
var jobs []structs.NamespacedID
2018-03-07 22:57:35 +00:00
for _, alloc := range allocs {
if alloc.TerminalStatus() || alloc.Job.Type != structs.JobTypeService {
continue
}
jns := structs.NamespacedID{Namespace: alloc.Namespace, ID: alloc.JobID}
2018-03-07 22:57:35 +00:00
if _, ok := jobIDs[jns]; ok {
continue
}
jobIDs[jns] = struct{}{}
jobs = append(jobs, jns)
}
return jobs, nil
}