github.com/hernad/nomad@v1.6.112/nomad/drainer/draining_node.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package drainer 5 6 import ( 7 "fmt" 8 "sync" 9 "time" 10 11 "github.com/hernad/nomad/nomad/state" 12 "github.com/hernad/nomad/nomad/structs" 13 ) 14 15 type drainingNode struct { 16 state *state.StateStore 17 node *structs.Node 18 l sync.RWMutex 19 } 20 21 func NewDrainingNode(node *structs.Node, state *state.StateStore) *drainingNode { 22 return &drainingNode{ 23 state: state, 24 node: node, 25 } 26 } 27 28 func (n *drainingNode) GetNode() *structs.Node { 29 n.l.Lock() 30 defer n.l.Unlock() 31 return n.node 32 } 33 34 func (n *drainingNode) Update(node *structs.Node) { 35 n.l.Lock() 36 defer n.l.Unlock() 37 n.node = node 38 } 39 40 // DeadlineTime returns if the node has a deadline and if so what it is 41 func (n *drainingNode) DeadlineTime() (bool, time.Time) { 42 n.l.RLock() 43 defer n.l.RUnlock() 44 45 // Should never happen 46 if n.node == nil || n.node.DrainStrategy == nil { 47 return false, time.Time{} 48 } 49 50 return n.node.DrainStrategy.DeadlineTime() 51 } 52 53 // IsDone returns if the node is done draining batch and service allocs. System 54 // allocs must be stopped before marking drain complete unless they're being 55 // ignored. 56 func (n *drainingNode) IsDone() (bool, error) { 57 n.l.RLock() 58 defer n.l.RUnlock() 59 60 // Should never happen 61 if n.node == nil || n.node.DrainStrategy == nil { 62 return false, fmt.Errorf("node doesn't have a drain strategy set") 63 } 64 65 // Retrieve the allocs on the node 66 allocs, err := n.state.AllocsByNode(nil, n.node.ID) 67 if err != nil { 68 return false, err 69 } 70 71 for _, alloc := range allocs { 72 // System and plugin jobs are only stopped after a node is 73 // done draining everything else, so ignore them here. 74 if alloc.Job.Type == structs.JobTypeSystem || alloc.Job.IsPlugin() { 75 continue 76 } 77 78 // If there is a non-terminal we aren't done 79 if !alloc.ClientTerminalStatus() { 80 return false, nil 81 } 82 } 83 84 return true, nil 85 } 86 87 // RemainingAllocs returns the set of allocations remaining on a node that 88 // still need to be drained. 89 func (n *drainingNode) RemainingAllocs() ([]*structs.Allocation, error) { 90 n.l.RLock() 91 defer n.l.RUnlock() 92 93 // Should never happen 94 if n.node == nil || n.node.DrainStrategy == nil { 95 return nil, fmt.Errorf("node doesn't have a drain strategy set") 96 } 97 98 // Grab the relevant drain info 99 ignoreSystem := n.node.DrainStrategy.IgnoreSystemJobs 100 101 // Retrieve the allocs on the node 102 allocs, err := n.state.AllocsByNode(nil, n.node.ID) 103 if err != nil { 104 return nil, err 105 } 106 107 var drain []*structs.Allocation 108 for _, alloc := range allocs { 109 // Nothing to do on a terminal allocation 110 if alloc.TerminalStatus() { 111 continue 112 } 113 114 // Skip system if configured to 115 if alloc.Job.Type == structs.JobTypeSystem && ignoreSystem { 116 continue 117 } 118 119 drain = append(drain, alloc) 120 } 121 122 return drain, nil 123 } 124 125 // DrainingJobs returns the set of jobs on the node that can block a drain. 126 // These include batch and service jobs. 127 func (n *drainingNode) DrainingJobs() ([]structs.NamespacedID, error) { 128 n.l.RLock() 129 defer n.l.RUnlock() 130 131 // Should never happen 132 if n.node == nil || n.node.DrainStrategy == nil { 133 return nil, fmt.Errorf("node doesn't have a drain strategy set") 134 } 135 136 // Retrieve the allocs on the node 137 allocs, err := n.state.AllocsByNode(nil, n.node.ID) 138 if err != nil { 139 return nil, err 140 } 141 142 jobIDs := make(map[structs.NamespacedID]struct{}) 143 var jobs []structs.NamespacedID 144 for _, alloc := range allocs { 145 if alloc.TerminalStatus() || alloc.Job.Type == structs.JobTypeSystem || alloc.Job.IsPlugin() { 146 continue 147 } 148 149 jns := structs.NamespacedID{Namespace: alloc.Namespace, ID: alloc.JobID} 150 if _, ok := jobIDs[jns]; ok { 151 continue 152 } 153 jobIDs[jns] = struct{}{} 154 jobs = append(jobs, jns) 155 } 156 157 return jobs, nil 158 }