Revision f2280553
b/Ganeti/HTools/Cluster.hs | ||
---|---|---|
57 | 57 |
) where |
58 | 58 |
|
59 | 59 |
import Data.List |
60 |
import Data.Maybe (isNothing, fromJust) |
|
61 | 60 |
import Text.Printf (printf) |
62 | 61 |
import Data.Function |
63 | 62 |
import Control.Monad |
... | ... | |
77 | 76 |
type Placement = (Idx, Ndx, Ndx, Score) |
78 | 77 |
|
79 | 78 |
-- | Allocation\/relocation solution. |
80 |
type AllocSolution = [(Maybe Node.List, Instance.Instance, [Node.Node])]
|
|
79 |
type AllocSolution = [(OpResult Node.List, Instance.Instance, [Node.Node])]
|
|
81 | 80 |
|
82 | 81 |
-- | An instance move definition |
83 | 82 |
data IMove = Failover -- ^ Failover the instance (f) |
... | ... | |
203 | 202 |
|
204 | 203 |
-- | Applies an instance move to a given node list and instance. |
205 | 204 |
applyMove :: Node.List -> Instance.Instance |
206 |
-> IMove -> (Maybe Node.List, Instance.Instance, Ndx, Ndx)
|
|
205 |
-> IMove -> (OpResult Node.List, Instance.Instance, Ndx, Ndx)
|
|
207 | 206 |
-- Failover (f) |
208 | 207 |
applyMove nl inst Failover = |
209 | 208 |
let old_pdx = Instance.pnode inst |
... | ... | |
284 | 283 |
|
285 | 284 |
-- | Tries to allocate an instance on one given node. |
286 | 285 |
allocateOnSingle :: Node.List -> Instance.Instance -> Node.Node |
287 |
-> (Maybe Node.List, Instance.Instance)
|
|
286 |
-> (OpResult Node.List, Instance.Instance)
|
|
288 | 287 |
allocateOnSingle nl inst p = |
289 | 288 |
let new_pdx = Node.idx p |
290 | 289 |
new_nl = Node.addPri p inst >>= \new_p -> |
... | ... | |
293 | 292 |
|
294 | 293 |
-- | Tries to allocate an instance on a given pair of nodes. |
295 | 294 |
allocateOnPair :: Node.List -> Instance.Instance -> Node.Node -> Node.Node |
296 |
-> (Maybe Node.List, Instance.Instance)
|
|
295 |
-> (OpResult Node.List, Instance.Instance)
|
|
297 | 296 |
allocateOnPair nl inst tgt_p tgt_s = |
298 | 297 |
let new_pdx = Node.idx tgt_p |
299 | 298 |
new_sdx = Node.idx tgt_s |
... | ... | |
315 | 314 |
Table ini_nl ini_il _ ini_plc = ini_tbl |
316 | 315 |
(tmp_nl, new_inst, pri_idx, sec_idx) = applyMove ini_nl target move |
317 | 316 |
in |
318 |
if isNothing tmp_nl then cur_tbl
|
|
319 |
else
|
|
320 |
let tgt_idx = Instance.idx target
|
|
321 |
upd_nl = fromJust tmp_nl
|
|
322 |
upd_cvar = compCV upd_nl |
|
323 |
upd_il = Container.add tgt_idx new_inst ini_il |
|
324 |
upd_plc = (tgt_idx, pri_idx, sec_idx, upd_cvar):ini_plc |
|
325 |
upd_tbl = Table upd_nl upd_il upd_cvar upd_plc |
|
326 |
in |
|
327 |
compareTables cur_tbl upd_tbl |
|
317 |
case tmp_nl of
|
|
318 |
OpFail _ -> cur_tbl
|
|
319 |
OpGood upd_nl ->
|
|
320 |
let tgt_idx = Instance.idx target
|
|
321 |
upd_cvar = compCV upd_nl
|
|
322 |
upd_il = Container.add tgt_idx new_inst ini_il
|
|
323 |
upd_plc = (tgt_idx, pri_idx, sec_idx, upd_cvar):ini_plc
|
|
324 |
upd_tbl = Table upd_nl upd_il upd_cvar upd_plc
|
|
325 |
in
|
|
326 |
compareTables cur_tbl upd_tbl
|
|
328 | 327 |
|
329 | 328 |
-- | Given the status of the current secondary as a valid new node |
330 | 329 |
-- and the current candidate target node, |
b/Ganeti/HTools/Node.hs | ||
---|---|---|
294 | 294 |
p_rem = new_prem} |
295 | 295 |
|
296 | 296 |
-- | Adds a primary instance. |
297 |
addPri :: Node -> Instance.Instance -> Maybe Node
|
|
297 |
addPri :: Node -> Instance.Instance -> T.OpResult Node
|
|
298 | 298 |
addPri t inst = |
299 | 299 |
let iname = Instance.idx inst |
300 | 300 |
new_mem = f_mem t - Instance.mem inst |
... | ... | |
307 | 307 |
if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) || |
308 | 308 |
(failLimits t new_dp new_pcpu) |
309 | 309 |
then |
310 |
Nothing
|
|
310 |
T.OpFail T.FailN1
|
|
311 | 311 |
else |
312 | 312 |
let new_plist = iname:(plist t) |
313 | 313 |
new_mp = (fromIntegral new_mem) / (t_mem t) |
314 | 314 |
in |
315 |
Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
|
|
316 |
failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp, |
|
317 |
u_cpu = new_ucpu, p_cpu = new_pcpu} |
|
315 |
T.OpGood t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
|
|
316 |
failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp,
|
|
317 |
u_cpu = new_ucpu, p_cpu = new_pcpu}
|
|
318 | 318 |
|
319 | 319 |
-- | Adds a secondary instance. |
320 |
addSec :: Node -> Instance.Instance -> T.Ndx -> Maybe Node
|
|
320 |
addSec :: Node -> Instance.Instance -> T.Ndx -> T.OpResult Node
|
|
321 | 321 |
addSec t inst pdx = |
322 | 322 |
let iname = Instance.idx inst |
323 | 323 |
old_peers = peers t |
... | ... | |
332 | 332 |
in if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) || |
333 | 333 |
(failLimits t new_dp noLimit) |
334 | 334 |
then |
335 |
Nothing
|
|
335 |
T.OpFail T.FailN1
|
|
336 | 336 |
else |
337 | 337 |
let new_slist = iname:(slist t) |
338 | 338 |
in |
339 |
Just t {slist = new_slist, f_dsk = new_dsk,
|
|
340 |
peers = new_peers, failN1 = new_failn1, |
|
341 |
r_mem = new_rmem, p_dsk = new_dp, |
|
342 |
p_rem = new_prem} |
|
339 |
T.OpGood t {slist = new_slist, f_dsk = new_dsk,
|
|
340 |
peers = new_peers, failN1 = new_failn1,
|
|
341 |
r_mem = new_rmem, p_dsk = new_dp,
|
|
342 |
p_rem = new_prem}
|
|
343 | 343 |
|
344 | 344 |
-- * Stats functions |
345 | 345 |
|
b/Ganeti/HTools/Types.hs | ||
---|---|---|
29 | 29 |
, NameAssoc |
30 | 30 |
, Result(..) |
31 | 31 |
, Element(..) |
32 |
, FailMode(..) |
|
33 |
, OpResult(..) |
|
32 | 34 |
) where |
33 | 35 |
|
34 | 36 |
-- | The instance index type. |
... | ... | |
58 | 60 |
return = Ok |
59 | 61 |
fail = Bad |
60 | 62 |
|
63 |
-- | Reason for an operation's falure |
|
64 |
data FailMode = FailMem -- ^ Failed due to not enough RAM |
|
65 |
| FailDisk -- ^ Failed due to not enough disk |
|
66 |
| FailCPU -- ^ Failed due to not enough CPU capacity |
|
67 |
| FailN1 -- ^ Failed due to not passing N1 checks |
|
68 |
|
|
69 |
-- | Either-like data-type customized for our failure modes |
|
70 |
data OpResult a = OpFail FailMode -- ^ Failed operation |
|
71 |
| OpGood a -- ^ Success operation |
|
72 |
|
|
73 |
instance Monad OpResult where |
|
74 |
(OpGood x) >>= fn = fn x |
|
75 |
(OpFail y) >>= _ = OpFail y |
|
76 |
return = OpGood |
|
77 |
|
|
61 | 78 |
-- | A generic class for items that have updateable names and indices. |
62 | 79 |
class Element a where |
63 | 80 |
-- | Returns the name of the element |
b/hail.hs | ||
---|---|---|
27 | 27 |
|
28 | 28 |
import Data.List |
29 | 29 |
import Data.Function |
30 |
import Data.Maybe (isJust, fromJust) |
|
31 | 30 |
import Monad |
32 | 31 |
import System |
33 | 32 |
import System.IO |
... | ... | |
43 | 42 |
import Ganeti.HTools.IAlloc |
44 | 43 |
import Ganeti.HTools.Types |
45 | 44 |
import Ganeti.HTools.Loader (RqType(..), Request(..)) |
46 |
import Ganeti.HTools.Utils |
|
47 | 45 |
|
48 | 46 |
-- | Command line options structure. |
49 | 47 |
data Options = Options |
... | ... | |
74 | 72 |
] |
75 | 73 |
|
76 | 74 |
|
77 |
filterFails :: (Monad m) => [(Maybe Node.List, Instance.Instance, [Node.Node])] |
|
75 |
filterFails :: (Monad m) => [(OpResult Node.List, |
|
76 |
Instance.Instance, [Node.Node])] |
|
78 | 77 |
-> m [(Node.List, [Node.Node])] |
79 | 78 |
filterFails sols = |
80 | 79 |
if null sols then fail "No nodes onto which to allocate at all" |
81 |
else let sols' = filter (isJust . fst3) sols |
|
82 |
in if null sols' then |
|
83 |
fail "No valid allocation solutions" |
|
84 |
else |
|
85 |
return $ map (\(x, _, y) -> (fromJust x, y)) sols' |
|
80 |
else let sols' = concat . map (\ (onl, _, nn) -> |
|
81 |
case onl of |
|
82 |
OpFail _ -> [] |
|
83 |
OpGood gnl -> [(gnl, nn)] |
|
84 |
) $ sols |
|
85 |
in |
|
86 |
if null sols' then |
|
87 |
fail "No valid allocation solutions" |
|
88 |
else |
|
89 |
return sols' |
|
86 | 90 |
|
87 | 91 |
processResults :: (Monad m) => [(Node.List, [Node.Node])] |
88 | 92 |
-> m (String, [Node.Node]) |
... | ... | |
98 | 102 |
in return (info, w) |
99 | 103 |
|
100 | 104 |
-- | Process a request and return new node lists |
101 |
processRequest :: |
|
102 |
Request |
|
103 |
-> Result [(Maybe Node.List, Instance.Instance, [Node.Node])] |
|
105 |
processRequest :: Request |
|
106 |
-> Result [(OpResult Node.List, Instance.Instance, [Node.Node])] |
|
104 | 107 |
processRequest request = |
105 | 108 |
let Request rqtype nl il _ = request |
106 | 109 |
in case rqtype of |
b/hspace.hs | ||
---|---|---|
27 | 27 |
|
28 | 28 |
import Data.List |
29 | 29 |
import Data.Function |
30 |
import Data.Maybe (isJust, fromJust, isNothing) |
|
31 | 30 |
import Monad |
32 | 31 |
import System |
33 | 32 |
import System.IO |
... | ... | |
43 | 42 |
import qualified Ganeti.HTools.CLI as CLI |
44 | 43 |
|
45 | 44 |
import Ganeti.HTools.Utils |
45 |
import Ganeti.HTools.Types |
|
46 | 46 |
|
47 | 47 |
-- | Command line options structure. |
48 | 48 |
data Options = Options |
... | ... | |
148 | 148 |
] |
149 | 149 |
|
150 | 150 |
filterFails :: Cluster.AllocSolution |
151 |
-> Maybe [(Node.List, Instance.Instance, [Node.Node])]
|
|
151 |
-> OpResult [(Node.List, Instance.Instance, [Node.Node])]
|
|
152 | 152 |
filterFails sols = |
153 |
if null sols then Nothing -- No nodes onto which to allocate at all |
|
154 |
else let sols' = filter (isJust . fst3) sols |
|
155 |
in if null sols' then |
|
156 |
Nothing -- No valid allocation solutions |
|
157 |
else |
|
158 |
return $ map (\(x, y, z) -> (fromJust x, y, z)) sols' |
|
159 |
|
|
160 |
processResults :: (Monad m) => [(Node.List, Instance.Instance, [Node.Node])] |
|
161 |
-> m (Node.List, Instance.Instance, [Node.Node]) |
|
153 |
let sols' = concat . map (\ (onl, i, nn) -> |
|
154 |
case onl of |
|
155 |
OpFail _ -> [] |
|
156 |
OpGood gnl -> [(gnl, i, nn)] |
|
157 |
) $ sols |
|
158 |
in |
|
159 |
if null sols' then |
|
160 |
OpFail FailN1 |
|
161 |
else |
|
162 |
return sols' |
|
163 |
|
|
164 |
processResults :: [(Node.List, Instance.Instance, [Node.Node])] |
|
165 |
-> (Node.List, Instance.Instance, [Node.Node]) |
|
162 | 166 |
processResults sols = |
163 | 167 |
let sols' = map (\e@(nl', _, _) -> (Cluster.compCV nl', e)) sols |
164 | 168 |
sols'' = sortBy (compare `on` fst) sols' |
165 |
in return $ snd $ head sols''
|
|
169 |
in snd $ head sols'' |
|
166 | 170 |
|
167 | 171 |
iterateDepth :: Node.List |
168 | 172 |
-> Instance.List |
... | ... | |
176 | 180 |
newidx = (length $ Container.elems il) + depth |
177 | 181 |
newi2 = Instance.setIdx (Instance.setName newinst newname) newidx |
178 | 182 |
sols = (Cluster.tryAlloc nl il newi2 nreq):: |
179 |
Maybe Cluster.AllocSolution
|
|
183 |
OpResult Cluster.AllocSolution
|
|
180 | 184 |
orig = (nl, ixes) |
181 |
in |
|
182 |
if isNothing sols then orig |
|
183 |
else let sols' = fromJust sols |
|
184 |
sols'' = filterFails sols' |
|
185 |
in if isNothing sols'' then orig |
|
186 |
else let (xnl, xi, _) = fromJust $ processResults $ |
|
187 |
fromJust sols'' |
|
188 |
in iterateDepth xnl il newinst nreq (xi:ixes) |
|
185 |
in case sols of |
|
186 |
OpFail _ -> orig |
|
187 |
OpGood sols' -> |
|
188 |
let |
|
189 |
sols'' = filterFails sols' |
|
190 |
in case sols'' of |
|
191 |
OpFail _ -> orig |
|
192 |
OpGood sols''' -> |
|
193 |
let (xnl, xi, _) = processResults sols''' |
|
194 |
in iterateDepth xnl il newinst nreq (xi:ixes) |
|
189 | 195 |
|
190 | 196 |
printStats :: String -> Cluster.CStats -> IO () |
191 | 197 |
printStats kind cs = do |
Also available in: Unified diff