3 {-| Scan clusters via RAPI or LUXI and write state data files.
9 Copyright (C) 2009, 2010, 2011 Google Inc.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 module Main (main) where
30 import Data.Maybe (isJust, fromJust, fromMaybe)
32 import System (exitWith, ExitCode(..))
34 import System.FilePath
35 import qualified System
37 import Text.Printf (printf)
39 import qualified Ganeti.HTools.Container as Container
40 import qualified Ganeti.HTools.Cluster as Cluster
41 import qualified Ganeti.HTools.Node as Node
42 import qualified Ganeti.HTools.Instance as Instance
44 import qualified Ganeti.HTools.Rapi as Rapi
46 import qualified Ganeti.HTools.Luxi as Luxi
47 import Ganeti.HTools.Loader (checkData, mergeData, ClusterData(..))
48 import Ganeti.HTools.Text (serializeCluster)
50 import Ganeti.HTools.CLI
51 import Ganeti.HTools.Types
53 -- | Options list and functions
65 -- | Return a one-line summary of cluster state
66 printCluster :: Node.List -> Instance.List
69 let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
70 ccv = Cluster.compCV nl
71 nodes = Container.elems nl
72 insts = Container.elems il
73 t_ram = sum . map Node.tMem $ nodes
74 t_dsk = sum . map Node.tDsk $ nodes
75 f_ram = sum . map Node.fMem $ nodes
76 f_dsk = sum . map Node.fDsk $ nodes
78 printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
79 (length nodes) (length insts)
80 (length bad_nodes) (length bad_instances)
82 (t_dsk / 1024) (f_dsk `div` 1024)
86 -- | Replace slashes with underscore for saving to filesystem
87 fixSlash :: String -> String
88 fixSlash = map (\x -> if x == '/' then '_' else x)
91 -- | Generates serialized data from loader input.
92 processData :: ClusterData -> Result ClusterData
93 processData input_data = do
94 cdata@(ClusterData _ nl il _) <- mergeData [] [] [] input_data
95 let (_, fix_nl) = checkData nl il
96 return cdata { cdNodes = fix_nl }
98 -- | Writes cluster data out
102 -> Result ClusterData
104 writeData _ name _ (Bad err) =
105 printf "\nError for %s: failed to load data. Details:\n%s\n" name err >>
108 writeData nlen name opts (Ok cdata) = do
109 let fixdata = processData cdata
111 Bad err -> printf "\nError for %s: failed to process data. Details:\n%s\n"
112 name err >> return False
113 Ok processed -> writeDataInner nlen name opts cdata processed
115 writeDataInner :: Int
121 writeDataInner nlen name opts cdata fixdata = do
122 let (ClusterData _ nl il _) = fixdata
123 printf "%-*s " nlen name :: IO ()
125 let shownodes = optShowNodes opts
126 odir = optOutPath opts
127 oname = odir </> fixSlash name
128 putStrLn $ printCluster nl il
130 when (isJust shownodes) $
131 putStr $ Cluster.printNodes nl (fromJust shownodes)
132 writeFile (oname <.> "data") (serializeCluster cdata)
138 cmd_args <- System.getArgs
139 (opts, clusters) <- parseOpts cmd_args "hscan" options
142 let nlen = if null clusters
144 else maximum . map length $ clusters
146 unless (optNoHeaders opts) $
147 printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
148 "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
149 "t_disk" "f_disk" "Score"
151 when (null clusters) $ do
152 let lsock = fromMaybe defaultLuxiSocket (optLuxi opts)
154 input_data <- Luxi.loadData lsock
155 result <- writeData nlen name opts input_data
156 unless result $ exitWith $ ExitFailure 2
159 results <- mapM (\name -> Rapi.loadData name >>= writeData nlen name opts)
161 unless (all id results) $ exitWith (ExitFailure 2)
163 when (not $ null clusters) $ do
164 putStrLn "RAPI/curl backend disabled at compile time, cannot scan clusters"
165 exitWith $ ExitFailure 1