Revision 1a9eb17e htools/Ganeti/HTools/Program/Hroller.hs

b/htools/Ganeti/HTools/Program/Hroller.hs
29 29
  , arguments
30 30
  ) where
31 31

  
32
import Control.Monad
33
import Data.List
34
import Data.Ord
35

  
36
import qualified Data.IntMap as IntMap
37

  
38
import qualified Ganeti.HTools.Container as Container
39
import qualified Ganeti.HTools.Node as Node
40

  
32 41
import Ganeti.Common
33 42
import Ganeti.HTools.CLI
43
import Ganeti.HTools.ExtLoader
44
import Ganeti.HTools.Graph
45
import Ganeti.HTools.Loader
46
import Ganeti.Utils
34 47

  
35 48
-- | Options list and functions.
36 49
options :: IO [OptType]
......
52 65
arguments :: [ArgCompletion]
53 66
arguments = []
54 67

  
68
-- | Gather statistics for the coloring algorithms.
69
-- Returns a string with a summary on how each algorithm has performed,
70
-- in order of non-decreasing effectiveness, and whether it tied or lost
71
-- with the previous one.
72
getStats :: [(String, ColorVertMap)] -> String
73
getStats colorings = snd . foldr helper (0,"") $ algBySize colorings
74
    where algostat (algo, cmap) = algo ++ ": " ++ size cmap ++ grpsizes cmap
75
          size cmap = show (IntMap.size cmap) ++ " "
76
          grpsizes cmap =
77
            "(" ++ commaJoin (map (show.length) (IntMap.elems cmap)) ++ ")"
78
          algBySize = sortBy (flip (comparing (IntMap.size.snd)))
79
          helper :: (String, ColorVertMap) -> (Int, String) -> (Int, String)
80
          helper el (0, _) = ((IntMap.size.snd) el, algostat el)
81
          helper el (old, str)
82
            | old == elsize = (elsize, str ++ " TIE " ++ algostat el)
83
            | otherwise = (elsize, str ++ " LOOSE " ++ algostat el)
84
              where elsize = (IntMap.size.snd) el
85

  
55 86
-- | Main function.
56 87
main :: Options -> [String] -> IO ()
57
main _ _ = return ()
88
main opts args = do
89
  unless (null args) $ exitErr "This program doesn't take any arguments."
90

  
91
  let verbose = optVerbose opts
92

  
93
  -- Load cluster data. The last two arguments, cluster tags and ipolicy, are
94
  -- currently not used by this tool.
95
  ini_cdata@(ClusterData _ fixed_nl ilf _ _) <- loadExternalData opts
96

  
97
  nlf <- setNodeStatus opts fixed_nl
98

  
99
  maybeSaveData (optSaveCluster opts) "original" "before hroller run" ini_cdata
100

  
101
  -- TODO: only online nodes!
102
  -- TODO: filter by node group
103
  -- TODO: fail if instances are running (with option to warn only)
104
  -- TODO: identify master node, and put it last
105

  
106
  nodeGraph <- case Node.mkNodeGraph nlf ilf of
107
                     Nothing -> exitErr "Cannot create node graph"
108
                     Just g -> return g
109

  
110
  when (verbose > 2) . putStrLn $ "Node Graph: " ++ show nodeGraph
111

  
112
  let colorAlgorithms = [ ("LF", colorLF)
113
                        , ("Dsatur", colorDsatur)
114
                        , ("Dcolor", colorDcolor)
115
                        ]
116
      colorings = map (\(v,a) -> (v,(colorVertMap.a) nodeGraph)) colorAlgorithms
117
      smallestColoring =
118
        (snd . minimumBy (comparing (IntMap.size . snd))) colorings
119
      idToName = Node.name  . (`Container.find` nlf)
120
      nodesbycoloring = map (map idToName) $ IntMap.elems smallestColoring
121

  
122
  when (verbose > 1) . putStrLn $ getStats colorings
123

  
124
  unless (optNoHeaders opts) $
125
         putStrLn "'Node Reboot Groups'"
126
  mapM_ (putStrLn . commaJoin) nodesbycoloring

Also available in: Unified diff