1 {-| Scan clusters via RAPI or LUXI and write state data files.
7 Copyright (C) 2009, 2010, 2011 Google Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 module Ganeti.HTools.Program.Hscan (main) where
29 import Data.Maybe (isJust, fromJust, fromMaybe)
30 import System (exitWith, ExitCode(..))
32 import System.FilePath
33 import qualified System
35 import Text.Printf (printf)
37 import qualified Ganeti.HTools.Container as Container
38 import qualified Ganeti.HTools.Cluster as Cluster
39 import qualified Ganeti.HTools.Node as Node
40 import qualified Ganeti.HTools.Instance as Instance
41 import qualified Ganeti.HTools.Rapi as Rapi
42 import qualified Ganeti.HTools.Luxi as Luxi
43 import Ganeti.HTools.Loader (checkData, mergeData, ClusterData(..))
44 import Ganeti.HTools.Text (serializeCluster)
46 import Ganeti.HTools.CLI
47 import Ganeti.HTools.Types
49 -- | Options list and functions.
61 -- | Return a one-line summary of cluster state.
62 printCluster :: Node.List -> Instance.List
65 let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
66 ccv = Cluster.compCV nl
67 nodes = Container.elems nl
68 insts = Container.elems il
69 t_ram = sum . map Node.tMem $ nodes
70 t_dsk = sum . map Node.tDsk $ nodes
71 f_ram = sum . map Node.fMem $ nodes
72 f_dsk = sum . map Node.fDsk $ nodes
73 in printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
74 (length nodes) (length insts)
75 (length bad_nodes) (length bad_instances)
76 t_ram f_ram (t_dsk / 1024) (f_dsk `div` 1024) ccv
78 -- | Replace slashes with underscore for saving to filesystem.
79 fixSlash :: String -> String
80 fixSlash = map (\x -> if x == '/' then '_' else x)
82 -- | Generates serialized data from loader input.
83 processData :: ClusterData -> Result ClusterData
84 processData input_data = do
85 cdata@(ClusterData _ nl il _) <- mergeData [] [] [] [] input_data
86 let (_, fix_nl) = checkData nl il
87 return cdata { cdNodes = fix_nl }
89 -- | Writes cluster data out.
95 writeData _ name _ (Bad err) =
96 printf "\nError for %s: failed to load data. Details:\n%s\n" name err >>
99 writeData nlen name opts (Ok cdata) = do
100 let fixdata = processData cdata
102 Bad err -> printf "\nError for %s: failed to process data. Details:\n%s\n"
103 name err >> return False
104 Ok processed -> writeDataInner nlen name opts cdata processed
106 -- | Inner function for writing cluster data to disk.
107 writeDataInner :: Int
113 writeDataInner nlen name opts cdata fixdata = do
114 let (ClusterData _ nl il _) = fixdata
115 printf "%-*s " nlen name :: IO ()
117 let shownodes = optShowNodes opts
118 odir = optOutPath opts
119 oname = odir </> fixSlash name
120 putStrLn $ printCluster nl il
122 when (isJust shownodes) $
123 putStr $ Cluster.printNodes nl (fromJust shownodes)
124 writeFile (oname <.> "data") (serializeCluster cdata)
130 cmd_args <- System.getArgs
131 (opts, clusters) <- parseOpts cmd_args "hscan" options
134 let nlen = if null clusters
136 else maximum . map length $ clusters
138 unless (optNoHeaders opts) $
139 printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
140 "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
141 "t_disk" "f_disk" "Score"
143 when (null clusters) $ do
144 let lsock = fromMaybe defaultLuxiSocket (optLuxi opts)
146 input_data <- Luxi.loadData lsock
147 result <- writeData nlen name opts input_data
148 unless result $ exitWith $ ExitFailure 2
150 results <- mapM (\name -> Rapi.loadData name >>= writeData nlen name opts)
152 unless (all id results) $ exitWith (ExitFailure 2)