Revision 30ce253e src/Ganeti/HTools/Program/Hroller.hs

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