htools: reindent the rest of the files
[ganeti-local] / htools / Ganeti / HTools / Program / Hscan.hs
1 {-| Scan clusters via RAPI or LUXI and write state data files.
2
3 -}
4
5 {-
6
7 Copyright (C) 2009, 2010, 2011 Google Inc.
8
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.
13
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.
18
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
22 02110-1301, USA.
23
24 -}
25
26 module Ganeti.HTools.Program.Hscan (main) where
27
28 import Control.Monad
29 import Data.Maybe (isJust, fromJust, fromMaybe)
30 import System (exitWith, ExitCode(..))
31 import System.IO
32 import System.FilePath
33 import qualified System
34
35 import Text.Printf (printf)
36
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)
45
46 import Ganeti.HTools.CLI
47 import Ganeti.HTools.Types
48
49 -- | Options list and functions.
50 options :: [OptType]
51 options =
52   [ oPrintNodes
53   , oOutputDir
54   , oLuxiSocket
55   , oVerbose
56   , oNoHeaders
57   , oShowVer
58   , oShowHelp
59   ]
60
61 -- | Return a one-line summary of cluster state.
62 printCluster :: Node.List -> Instance.List
63              -> String
64 printCluster nl il =
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
77
78 -- | Replace slashes with underscore for saving to filesystem.
79 fixSlash :: String -> String
80 fixSlash = map (\x -> if x == '/' then '_' else x)
81
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 }
88
89 -- | Writes cluster data out.
90 writeData :: Int
91           -> String
92           -> Options
93           -> Result ClusterData
94           -> IO Bool
95 writeData _ name _ (Bad err) =
96   printf "\nError for %s: failed to load data. Details:\n%s\n" name err >>
97   return False
98
99 writeData nlen name opts (Ok cdata) = do
100   let fixdata = processData cdata
101   case fixdata of
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
105
106 -- | Inner function for writing cluster data to disk.
107 writeDataInner :: Int
108                -> String
109                -> Options
110                -> ClusterData
111                -> ClusterData
112                -> IO Bool
113 writeDataInner nlen name opts cdata fixdata = do
114   let (ClusterData _ nl il _) = fixdata
115   printf "%-*s " nlen name :: IO ()
116   hFlush stdout
117   let shownodes = optShowNodes opts
118       odir = optOutPath opts
119       oname = odir </> fixSlash name
120   putStrLn $ printCluster nl il
121   hFlush stdout
122   when (isJust shownodes) $
123        putStr $ Cluster.printNodes nl (fromJust shownodes)
124   writeFile (oname <.> "data") (serializeCluster cdata)
125   return True
126
127 -- | Main function.
128 main :: IO ()
129 main = do
130   cmd_args <- System.getArgs
131   (opts, clusters) <- parseOpts cmd_args "hscan" options
132   let local = "LOCAL"
133
134   let nlen = if null clusters
135              then length local
136              else maximum . map length $ clusters
137
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"
142
143   when (null clusters) $ do
144          let lsock = fromMaybe defaultLuxiSocket (optLuxi opts)
145          let name = local
146          input_data <- Luxi.loadData lsock
147          result <- writeData nlen name opts input_data
148          unless result $ exitWith $ ExitFailure 2
149
150   results <- mapM (\name -> Rapi.loadData name >>= writeData nlen name opts)
151              clusters
152   unless (all id results) $ exitWith (ExitFailure 2)