Revision 30ce253e
b/man/hroller.rst | ||
---|---|---|
36 | 36 |
**[ -v... | -q ]** |
37 | 37 |
**[ -S *file* ]** |
38 | 38 |
**[ --one-step-only ]** |
39 |
**[ --print-moves ]** |
|
39 | 40 |
|
40 | 41 |
DESCRIPTION |
41 | 42 |
----------- |
... | ... | |
88 | 89 |
\--one-step-only |
89 | 90 |
Restrict to the first reboot group. Output the group one node per line. |
90 | 91 |
|
92 |
\--print-moves |
|
93 |
After each group list for each affected non-redundant instance a node |
|
94 |
where it can be evacuated to. |
|
95 |
|
|
91 | 96 |
|
92 | 97 |
BUGS |
93 | 98 |
---- |
... | ... | |
140 | 145 |
node8.example.com,node6.example.com,node2.example.com |
141 | 146 |
node7.example.com,node4.example.com |
142 | 147 |
|
148 |
Rolling reboots with non-redundant instances |
|
149 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
150 |
|
|
151 |
By default, hroller plans capacity to move the non-redundant instances |
|
152 |
out of the nodes to be rebooted. If requested, apropriate locations for |
|
153 |
the non-redundant instances can be shown. The assumption is that instances |
|
154 |
are moved back to their original node after each reboot; these back moves |
|
155 |
are not part of the output. |
|
156 |
:: |
|
157 |
|
|
158 |
$ hroller --print-moves -L |
|
159 |
'Node Reboot Groups' |
|
160 |
node-01-002,node-01-003 |
|
161 |
inst-20 node-01-001 |
|
162 |
inst-21 node-01-000 |
|
163 |
inst-30 node-01-005 |
|
164 |
inst-31 node-01-004 |
|
165 |
node-01-004,node-01-005 |
|
166 |
inst-40 node-01-001 |
|
167 |
inst-41 node-01-000 |
|
168 |
inst-50 node-01-003 |
|
169 |
inst-51 node-01-002 |
|
170 |
node-01-001,node-01-000 |
|
171 |
inst-00 node-01-002 |
|
172 |
inst-01 node-01-003 |
|
173 |
inst-10 node-01-005 |
|
174 |
inst-11 node-01-004 |
|
175 |
|
|
176 |
|
|
177 |
|
|
143 | 178 |
.. vim: set textwidth=72 : |
144 | 179 |
.. Local Variables: |
145 | 180 |
.. mode: rst |
b/src/Ganeti/HTools/CLI.hs | ||
---|---|---|
77 | 77 |
, oOutputDir |
78 | 78 |
, oPrintCommands |
79 | 79 |
, oPrintInsts |
80 |
, oPrintMoves |
|
80 | 81 |
, oPrintNodes |
81 | 82 |
, oQuiet |
82 | 83 |
, oRapiMaster |
... | ... | |
146 | 147 |
, optOfflineMaintenance :: Bool -- ^ Pretend all instances are offline |
147 | 148 |
, optOneStepOnly :: Bool -- ^ Only do the first step |
148 | 149 |
, optOutPath :: FilePath -- ^ Path to the output directory |
150 |
, optPrintMoves :: Bool -- ^ Whether to show the instance moves |
|
149 | 151 |
, optSaveCluster :: Maybe FilePath -- ^ Save cluster state to this file |
150 | 152 |
, optShowCmds :: Maybe FilePath -- ^ Whether to show the command list |
151 | 153 |
, optShowHelp :: Bool -- ^ Just show the help |
... | ... | |
199 | 201 |
, optOfflineMaintenance = False |
200 | 202 |
, optOneStepOnly = False |
201 | 203 |
, optOutPath = "." |
204 |
, optPrintMoves = False |
|
202 | 205 |
, optSaveCluster = Nothing |
203 | 206 |
, optShowCmds = Nothing |
204 | 207 |
, optShowHelp = False |
... | ... | |
535 | 538 |
"print the final instance map", |
536 | 539 |
OptComplNone) |
537 | 540 |
|
541 |
oPrintMoves :: OptType |
|
542 |
oPrintMoves = |
|
543 |
(Option "" ["print-moves"] |
|
544 |
(NoArg (\ opts -> Ok opts { optPrintMoves = True })) |
|
545 |
"print the moves of the instances", |
|
546 |
OptComplNone) |
|
547 |
|
|
538 | 548 |
oPrintNodes :: OptType |
539 | 549 |
oPrintNodes = |
540 | 550 |
(Option "p" ["print-nodes"] |
b/src/Ganeti/HTools/Program/Hroller.hs | ||
---|---|---|
30 | 30 |
) where |
31 | 31 |
|
32 | 32 |
import Control.Applicative |
33 |
import Control.Arrow |
|
33 | 34 |
import Control.Monad |
34 | 35 |
import Data.Function |
35 | 36 |
import Data.List |
36 | 37 |
import Data.Ord |
38 |
import Text.Printf |
|
37 | 39 |
|
38 | 40 |
import qualified Data.IntMap as IntMap |
39 | 41 |
|
... | ... | |
68 | 70 |
, oNodeTags |
69 | 71 |
, oSaveCluster |
70 | 72 |
, oGroup |
73 |
, oPrintMoves |
|
71 | 74 |
, oSkipNonRedundant |
72 | 75 |
, oIgnoreNonRedundant |
73 | 76 |
, oForce |
... | ... | |
127 | 130 |
|
128 | 131 |
-- | Parition a list of nodes into chunks according cluster capacity. |
129 | 132 |
partitionNonRedundant :: [Ndx] -> [Ndx] -> (Node.List, Instance.List) |
130 |
-> Result [[Ndx]]
|
|
133 |
-> Result [([Ndx], (Node.List, Instance.List))]
|
|
131 | 134 |
partitionNonRedundant [] _ _ = return [] |
132 | 135 |
partitionNonRedundant ndxs targets conf = do |
133 |
(grp, _) <- clearNodes ndxs targets conf
|
|
136 |
(grp, conf') <- clearNodes ndxs targets conf
|
|
134 | 137 |
guard . not . null $ grp |
135 | 138 |
let remaining = ndxs \\ grp |
136 | 139 |
part <- partitionNonRedundant remaining targets conf |
137 |
return $ grp : part
|
|
140 |
return $ (grp, conf') : part
|
|
138 | 141 |
|
139 | 142 |
-- | Gather statistics for the coloring algorithms. |
140 | 143 |
-- Returns a string with a summary on how each algorithm has performed, |
... | ... | |
177 | 180 |
noNonRedundant conf = null . nonRedundant conf . Node.idx |
178 | 181 |
|
179 | 182 |
-- | Put the master node last. |
180 |
-- Reorder a list of lists of nodes such that the master node (if present)
|
|
181 |
-- is the last node of the last group. |
|
182 |
masterLast :: [[Node.Node]] -> [[Node.Node]]
|
|
183 |
-- Reorder a list groups of nodes (with additional information) such that the
|
|
184 |
-- master node (if present) is the last node of the last group.
|
|
185 |
masterLast :: [([Node.Node], a)] -> [([Node.Node], a)]
|
|
183 | 186 |
masterLast rebootgroups = |
184 |
map (uncurry (++)) . uncurry (++) . partition (null . snd) $ |
|
185 |
map (partition (not . Node.isMaster)) rebootgroups |
|
187 |
map (first $ uncurry (++)) . uncurry (++) . partition (null . snd . fst) $ |
|
188 |
map (first $ partition (not . Node.isMaster)) rebootgroups |
|
189 |
|
|
190 |
-- | From two configurations compute the list of moved instances. |
|
191 |
getMoves :: (Node.List, Instance.List) -> (Node.List, Instance.List) |
|
192 |
-> [(Instance.Instance, Node.Node)] |
|
193 |
getMoves (_, il) (nl', il') = do |
|
194 |
ix <- Container.keys il |
|
195 |
let inst = Container.find ix il |
|
196 |
inst' = Container.find ix il' |
|
197 |
guard $ Instance.pNode inst /= Instance.pNode inst' |
|
198 |
return (inst', Container.find (Instance.pNode inst') nl') |
|
186 | 199 |
|
187 | 200 |
-- | Main function. |
188 | 201 |
main :: Options -> [String] -> IO () |
... | ... | |
245 | 258 |
splitted = mapM (\ grp -> partitionNonRedundant grp allNdx (nlf,ilf)) |
246 | 259 |
smallestColoring |
247 | 260 |
rebootGroups <- if optIgnoreNonRedundant opts |
248 |
then return smallestColoring
|
|
261 |
then return $ zip smallestColoring (repeat (nlf, ilf))
|
|
249 | 262 |
else case splitted of |
250 | 263 |
Ok splitgroups -> return $ concat splitgroups |
251 | 264 |
Bad _ -> exitErr "Not enough capacity to move\ |
252 | 265 |
\ non-redundant instances" |
253 | 266 |
let idToNode = (`Container.find` nodes) |
254 | 267 |
nodesRebootGroups = |
255 |
map (map idToNode . filter (`IntMap.member` nodes)) rebootGroups |
|
268 |
map (first $ map idToNode . filter (`IntMap.member` nodes)) rebootGroups
|
|
256 | 269 |
outputRebootGroups = masterLast . |
257 |
sortBy (flip compare `on` length) $ |
|
270 |
sortBy (flip compare `on` length . fst) $
|
|
258 | 271 |
nodesRebootGroups |
259 |
outputRebootNames = map (map Node.name) outputRebootGroups |
|
272 |
confToMoveNames = map (Instance.name *** Node.name) . getMoves (nlf, ilf) |
|
273 |
namesAndMoves = map (map Node.name *** confToMoveNames) outputRebootGroups |
|
260 | 274 |
|
261 | 275 |
when (verbose > 1) . putStrLn $ getStats colorings |
262 | 276 |
|
277 |
let showGroup = if optOneStepOnly opts |
|
278 |
then mapM_ putStrLn |
|
279 |
else putStrLn . commaJoin |
|
280 |
showMoves = if optPrintMoves opts |
|
281 |
then mapM_ $ putStrLn . uncurry (printf " %s %s") |
|
282 |
else const $ return () |
|
283 |
showBoth = liftM2 (>>) (showGroup . fst) (showMoves . snd) |
|
284 |
|
|
285 |
|
|
263 | 286 |
if optOneStepOnly opts |
264 | 287 |
then do |
265 | 288 |
unless (optNoHeaders opts) $ |
266 | 289 |
putStrLn "'First Reboot Group'" |
267 |
case outputRebootNames of
|
|
290 |
case namesAndMoves of
|
|
268 | 291 |
[] -> return () |
269 |
y : _ -> mapM_ putStrLn y
|
|
292 |
y : _ -> showBoth y
|
|
270 | 293 |
else do |
271 | 294 |
unless (optNoHeaders opts) $ |
272 | 295 |
putStrLn "'Node Reboot Groups'" |
273 |
mapM_ (putStrLn . commaJoin) outputRebootNames |
|
296 |
mapM_ showBoth namesAndMoves |
Also available in: Unified diff