1 {-| Module describing a node.
3 All updates are functional (copy-based) and return a new node with
7 module Ganeti.HTools.Node
9 Node(failN1, name, idx, t_mem, n_mem, f_mem, t_dsk, f_dsk,
11 plist, slist, offline)
14 -- ** Finalization after data loading
21 -- * Instance (re)location
36 import Text.Printf (printf)
38 import qualified Ganeti.HTools.Container as Container
39 import qualified Ganeti.HTools.Instance as Instance
40 import qualified Ganeti.HTools.PeerMap as PeerMap
42 data Node = Node { name :: String -- ^ the node name
43 , t_mem :: Double -- ^ total memory (MiB)
44 , n_mem :: Int -- ^ node memory (MiB)
45 , f_mem :: Int -- ^ free memory (MiB)
46 , x_mem :: Int -- ^ unaccounted memory (MiB)
47 , t_dsk :: Double -- ^ total disk space (MiB)
48 , f_dsk :: Int -- ^ free disk space (MiB)
49 , plist :: [Int] -- ^ list of primary instance indices
50 , slist :: [Int] -- ^ list of secondary instance indices
51 , idx :: Int -- ^ internal index for book-keeping
52 , peers :: PeerMap.PeerMap -- ^ pnode to instance mapping
53 , failN1:: Bool -- ^ whether the node has failed n1
54 , r_mem :: Int -- ^ maximum memory needed for
55 -- failover by primaries of this node
56 , p_mem :: Double -- ^ percent of free memory
57 , p_dsk :: Double -- ^ percent of free disk
58 , p_rem :: Double -- ^ percent of reserved memory
59 , offline :: Bool -- ^ whether the node should not be used
60 -- for allocations and skipped from
64 -- | A simple name for the int, node association list
65 type AssocList = [(Int, Node)]
67 -- | Constant node index for a non-moveable instance
71 {- | Create a new node.
73 The index and the peers maps are empty, and will be need to be update
74 later via the 'setIdx' and 'buildPeers' functions.
77 create :: String -> Double -> Int -> Int -> Double -> Int -> Bool -> Node
78 create name_init mem_t_init mem_n_init mem_f_init
79 dsk_t_init dsk_f_init offline_init =
92 peers = PeerMap.empty,
94 p_mem = (fromIntegral mem_f_init) / mem_t_init,
95 p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
97 offline = offline_init,
101 -- | Changes the index.
102 -- This is used only during the building of the data structures.
103 setIdx :: Node -> Int -> Node
104 setIdx t i = t {idx = i}
106 -- | Changes the name
107 -- This is used only during the building of the data structures.
108 setName t s = t {name = s}
110 -- | Sets the offline attribute
111 setOffline :: Node -> Bool -> Node
112 setOffline t val = t { offline = val }
114 -- | Sets the unnaccounted memory
115 setXmem :: Node -> Int -> Node
116 setXmem t val = t { x_mem = val }
118 -- | Sets the free memory
119 setFmem :: Node -> Int -> Node
121 let new_n1 = computeFailN1 (r_mem t) new_mem (f_dsk t)
122 new_mp = (fromIntegral new_mem) / (t_mem t)
124 t { f_mem = new_mem, failN1 = new_n1, p_mem = new_mp }
126 -- | Given the rmem, free memory and disk, computes the failn1 status.
127 computeFailN1 :: Int -> Int -> Int -> Bool
128 computeFailN1 new_rmem new_mem new_dsk =
129 new_mem <= new_rmem || new_dsk <= 0
131 -- | Given the new free memory and disk, fail if any of them is below zero.
132 failHealth :: Int -> Int -> Bool
133 failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
135 -- | Computes the maximum reserved memory for peers from a peer map.
136 computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
137 computeMaxRes new_peers = PeerMap.maxElem new_peers
139 -- | Builds the peer map for a given node.
140 buildPeers :: Node -> Container.Container Instance.Instance -> Int -> Node
141 buildPeers t il num_nodes =
143 (\i_idx -> let inst = Container.find i_idx il
144 in (Instance.pnode inst, Instance.mem inst))
146 pmap = PeerMap.accumArray (+) 0 (0, num_nodes - 1) mdata
147 new_rmem = computeMaxRes pmap
148 new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
149 new_prem = (fromIntegral new_rmem) / (t_mem t)
150 in t {peers=pmap, failN1 = new_failN1, r_mem = new_rmem, p_rem = new_prem}
152 -- | Removes a primary instance.
153 removePri :: Node -> Instance.Instance -> Node
155 let iname = Instance.idx inst
156 new_plist = delete iname (plist t)
157 new_mem = f_mem t + Instance.mem inst
158 new_dsk = f_dsk t + Instance.dsk inst
159 new_mp = (fromIntegral new_mem) / (t_mem t)
160 new_dp = (fromIntegral new_dsk) / (t_dsk t)
161 new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
162 in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
163 failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
165 -- | Removes a secondary instance.
166 removeSec :: Node -> Instance.Instance -> Node
168 let iname = Instance.idx inst
169 pnode = Instance.pnode inst
170 new_slist = delete iname (slist t)
171 new_dsk = f_dsk t + Instance.dsk inst
173 old_peem = PeerMap.find pnode old_peers
174 new_peem = old_peem - (Instance.mem inst)
175 new_peers = PeerMap.add pnode new_peem old_peers
177 new_rmem = if old_peem < old_rmem then
180 computeMaxRes new_peers
181 new_prem = (fromIntegral new_rmem) / (t_mem t)
182 new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
183 new_dp = (fromIntegral new_dsk) / (t_dsk t)
184 in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
185 failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
188 -- | Adds a primary instance.
189 addPri :: Node -> Instance.Instance -> Maybe Node
191 let iname = Instance.idx inst
192 new_mem = f_mem t - Instance.mem inst
193 new_dsk = f_dsk t - Instance.dsk inst
194 new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
195 if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
198 let new_plist = iname:(plist t)
199 new_mp = (fromIntegral new_mem) / (t_mem t)
200 new_dp = (fromIntegral new_dsk) / (t_dsk t)
202 Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
203 failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
205 -- | Adds a secondary instance.
206 addSec :: Node -> Instance.Instance -> Int -> Maybe Node
208 let iname = Instance.idx inst
211 new_dsk = f_dsk t - Instance.dsk inst
212 new_peem = PeerMap.find pdx old_peers + Instance.mem inst
213 new_peers = PeerMap.add pdx new_peem old_peers
214 new_rmem = max (r_mem t) new_peem
215 new_prem = (fromIntegral new_rmem) / (t_mem t)
216 new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
217 if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
220 let new_slist = iname:(slist t)
221 new_dp = (fromIntegral new_dsk) / (t_dsk t)
223 Just t {slist = new_slist, f_dsk = new_dsk,
224 peers = new_peers, failN1 = new_failn1,
225 r_mem = new_rmem, p_dsk = new_dp,
228 -- | Add a primary instance to a node without other updates
229 setPri :: Node -> Int -> Node
230 setPri t idx = t { plist = idx:(plist t) }
232 -- | Add a secondary instance to a node without other updates
233 setSec :: Node -> Int -> Node
234 setSec t idx = t { slist = idx:(slist t) }
236 -- | String converter for the node list functionality.
237 list :: Int -> Node -> String
249 imem = (truncate tmem) - nmem - xmem - fmem
251 printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
252 (if off then '-' else if fn then '*' else ' ')
253 mname (name t) tmem nmem imem xmem fmem (r_mem t)
254 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
255 (length pl) (length sl)