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, idx, t_mem, f_mem, t_dsk, f_dsk, p_mem, p_dsk, p_rem,
10 plist, slist, offline)
13 -- ** Finalization after data loading
17 -- * Instance (re)location
29 import Text.Printf (printf)
31 import qualified Ganeti.HTools.Container as Container
32 import qualified Ganeti.HTools.Instance as Instance
33 import qualified Ganeti.HTools.PeerMap as PeerMap
35 import Ganeti.HTools.Utils
37 data Node = Node { t_mem :: Double -- ^ total memory (Mib)
38 , f_mem :: Int -- ^ free memory (MiB)
39 , t_dsk :: Double -- ^ total disk space (MiB)
40 , f_dsk :: Int -- ^ free disk space (MiB)
41 , plist :: [Int] -- ^ list of primary instance indices
42 , slist :: [Int] -- ^ list of secondary instance indices
43 , idx :: Int -- ^ internal index for book-keeping
44 , peers :: PeerMap.PeerMap -- ^ pnode to instance mapping
45 , failN1:: Bool -- ^ whether the node has failed n1
46 , r_mem :: Int -- ^ maximum memory needed for
47 -- failover by primaries of this node
48 , p_mem :: Double -- ^ percent of free memory
49 , p_dsk :: Double -- ^ percent of free disk
50 , p_rem :: Double -- ^ percent of reserved memory
51 , offline :: Bool -- ^ whether the node should not be used
52 -- for allocations and skipped from
56 {- | Create a new node.
58 The index and the peers maps are empty, and will be need to be update
59 later via the 'setIdx' and 'buildPeers' functions.
62 create :: String -> String -> String -> String -> Node
63 create mem_t_init mem_f_init dsk_t_init dsk_f_init =
64 let mem_t = read mem_t_init
65 mem_f = read mem_f_init
66 dsk_t = read dsk_t_init
67 dsk_f = read dsk_f_init
71 t_mem = read mem_t_init,
72 f_mem = read mem_f_init,
73 t_dsk = read dsk_t_init,
74 f_dsk = read dsk_f_init,
79 peers = PeerMap.empty,
81 p_mem = (fromIntegral mem_f) / (fromIntegral mem_t),
82 p_dsk = (fromIntegral dsk_f) / (fromIntegral dsk_t),
87 -- | Changes the index.
88 -- This is used only during the building of the data structures.
89 setIdx :: Node -> Int -> Node
90 setIdx t i = t {idx = i}
92 -- | Sets the offline attribute
93 setOffline :: Node -> Bool -> Node
94 setOffline t val = t { offline = val }
96 -- | Given the rmem, free memory and disk, computes the failn1 status.
97 computeFailN1 :: Int -> Int -> Int -> Bool
98 computeFailN1 new_rmem new_mem new_dsk =
99 new_mem <= new_rmem || new_dsk <= 0
101 -- | Given the new free memory and disk, fail if any of them is below zero.
102 failHealth :: Int -> Int -> Bool
103 failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
105 -- | Computes the maximum reserved memory for peers from a peer map.
106 computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
107 computeMaxRes new_peers = PeerMap.maxElem new_peers
109 -- | Builds the peer map for a given node.
110 buildPeers :: Node -> Container.Container Instance.Instance -> Int -> Node
111 buildPeers t il num_nodes =
113 (\i_idx -> let inst = Container.find i_idx il
114 in (Instance.pnode inst, Instance.mem inst))
116 pmap = PeerMap.accumArray (+) 0 (0, num_nodes - 1) mdata
117 new_rmem = computeMaxRes pmap
118 new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
119 new_prem = (fromIntegral new_rmem) / (t_mem t)
120 in t {peers=pmap, failN1 = new_failN1, r_mem = new_rmem, p_rem = new_prem}
122 -- | Removes a primary instance.
123 removePri :: Node -> Instance.Instance -> Node
125 let iname = Instance.idx inst
126 new_plist = delete iname (plist t)
127 new_mem = f_mem t + Instance.mem inst
128 new_dsk = f_dsk t + Instance.dsk inst
129 new_mp = (fromIntegral new_mem) / (t_mem t)
130 new_dp = (fromIntegral new_dsk) / (t_dsk t)
131 new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
132 in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
133 failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
135 -- | Removes a secondary instance.
136 removeSec :: Node -> Instance.Instance -> Node
138 let iname = Instance.idx inst
139 pnode = Instance.pnode inst
140 new_slist = delete iname (slist t)
141 new_dsk = f_dsk t + Instance.dsk inst
143 old_peem = PeerMap.find pnode old_peers
144 new_peem = old_peem - (Instance.mem inst)
145 new_peers = PeerMap.add pnode new_peem old_peers
147 new_rmem = if old_peem < old_rmem then
150 computeMaxRes new_peers
151 new_prem = (fromIntegral new_rmem) / (t_mem t)
152 new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
153 new_dp = (fromIntegral new_dsk) / (t_dsk t)
154 in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
155 failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
158 -- | Adds a primary instance.
159 addPri :: Node -> Instance.Instance -> Maybe Node
161 let iname = Instance.idx inst
162 new_mem = f_mem t - Instance.mem inst
163 new_dsk = f_dsk t - Instance.dsk inst
164 new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
165 if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
168 let new_plist = iname:(plist t)
169 new_mp = (fromIntegral new_mem) / (t_mem t)
170 new_dp = (fromIntegral new_dsk) / (t_dsk t)
172 Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
173 failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
175 -- | Adds a secondary instance.
176 addSec :: Node -> Instance.Instance -> Int -> Maybe Node
178 let iname = Instance.idx inst
181 new_dsk = f_dsk t - Instance.dsk inst
182 new_peem = PeerMap.find pdx old_peers + Instance.mem inst
183 new_peers = PeerMap.add pdx new_peem old_peers
184 new_rmem = max (r_mem t) new_peem
185 new_prem = (fromIntegral new_rmem) / (t_mem t)
186 new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
187 if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
190 let new_slist = iname:(slist t)
191 new_dp = (fromIntegral new_dsk) / (t_dsk t)
193 Just t {slist = new_slist, f_dsk = new_dsk,
194 peers = new_peers, failN1 = new_failn1,
195 r_mem = new_rmem, p_dsk = new_dp,
198 -- | Add a primary instance to a node without other updates
199 setPri :: Node -> Int -> Node
200 setPri t idx = t { plist = idx:(plist t) }
202 -- | Add a secondary instance to a node without other updates
203 setSec :: Node -> Int -> Node
204 setSec t idx = t { slist = idx:(slist t) }
206 -- | Simple converter to string.
207 str :: Node -> String
209 printf ("Node %d (mem=%5d MiB, disk=%5.2f GiB)\n Primaries:" ++
210 " %s\nSecondaries: %s")
211 (idx t) (f_mem t) ((f_dsk t) `div` 1024)
212 (commaJoin (map show (plist t)))
213 (commaJoin (map show (slist t)))
215 -- | String converter for the node list functionality.
216 list :: Int -> String -> Node -> String
225 printf " %c %-*s %5.0f %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
226 (if off then '-' else if fn then '*' else ' ')
227 mname n (t_mem t) (f_mem t) (r_mem t)
228 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
229 (length pl) (length sl)