rlib2: Exclude oplog/opresult from bulk job list
[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
74       printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
75                  (length nodes) (length insts)
76                  (length bad_nodes) (length bad_instances)
77                  t_ram f_ram
78                  (t_dsk / 1024) (f_dsk `div` 1024)
79                  ccv
80
81
82 -- | Replace slashes with underscore for saving to filesystem.
83 fixSlash :: String -> String
84 fixSlash = map (\x -> if x == '/' then '_' else x)
85
86
87 -- | Generates serialized data from loader input.
88 processData :: ClusterData -> Result ClusterData
89 processData input_data = do
90   cdata@(ClusterData _ nl il _) <- mergeData [] [] [] [] input_data
91   let (_, fix_nl) = checkData nl il
92   return cdata { cdNodes = fix_nl }
93
94 -- | Writes cluster data out.
95 writeData :: Int
96           -> String
97           -> Options
98           -> Result ClusterData
99           -> IO Bool
100 writeData _ name _ (Bad err) =
101   printf "\nError for %s: failed to load data. Details:\n%s\n" name err >>
102   return False
103
104 writeData nlen name opts (Ok cdata) = do
105   let fixdata = processData cdata
106   case fixdata of
107     Bad err -> printf "\nError for %s: failed to process data. Details:\n%s\n"
108                name err >> return False
109     Ok processed -> writeDataInner nlen name opts cdata processed
110
111 -- | Inner function for writing cluster data to disk.
112 writeDataInner :: Int
113                -> String
114                -> Options
115                -> ClusterData
116                -> ClusterData
117                -> IO Bool
118 writeDataInner nlen name opts cdata fixdata = do
119   let (ClusterData _ nl il _) = fixdata
120   printf "%-*s " nlen name :: IO ()
121   hFlush stdout
122   let shownodes = optShowNodes opts
123       odir = optOutPath opts
124       oname = odir </> fixSlash name
125   putStrLn $ printCluster nl il
126   hFlush stdout
127   when (isJust shownodes) $
128        putStr $ Cluster.printNodes nl (fromJust shownodes)
129   writeFile (oname <.> "data") (serializeCluster cdata)
130   return True
131
132 -- | Main function.
133 main :: IO ()
134 main = do
135   cmd_args <- System.getArgs
136   (opts, clusters) <- parseOpts cmd_args "hscan" options
137   let local = "LOCAL"
138
139   let nlen = if null clusters
140              then length local
141              else maximum . map length $ clusters
142
143   unless (optNoHeaders opts) $
144          printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
145                 "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
146                 "t_disk" "f_disk" "Score"
147
148   when (null clusters) $ do
149          let lsock = fromMaybe defaultLuxiSocket (optLuxi opts)
150          let name = local
151          input_data <- Luxi.loadData lsock
152          result <- writeData nlen name opts input_data
153          unless result $ exitWith $ ExitFailure 2
154
155   results <- mapM (\name -> Rapi.loadData name >>= writeData nlen name opts)
156              clusters
157   unless (all id results) $ exitWith (ExitFailure 2)