Remove two extraneous imports
[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, 2012 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, options) where
27
28 import Control.Monad
29 import Data.Maybe (isJust, fromJust, fromMaybe)
30 import System.Exit
31 import System.IO
32 import System.FilePath
33
34 import Text.Printf (printf)
35
36 import qualified Ganeti.HTools.Container as Container
37 import qualified Ganeti.HTools.Cluster as Cluster
38 import qualified Ganeti.HTools.Node as Node
39 import qualified Ganeti.HTools.Instance as Instance
40 import qualified Ganeti.HTools.Rapi as Rapi
41 import qualified Ganeti.HTools.Luxi as Luxi
42 import Ganeti.HTools.Loader (checkData, mergeData, ClusterData(..))
43 import Ganeti.HTools.Text (serializeCluster)
44
45 import Ganeti.HTools.CLI
46 import Ganeti.HTools.Types
47
48 -- | Options list and functions.
49 options :: [OptType]
50 options =
51   [ oPrintNodes
52   , oOutputDir
53   , oLuxiSocket
54   , oVerbose
55   , oNoHeaders
56   , oShowVer
57   , oShowHelp
58   ]
59
60 -- | Return a one-line summary of cluster state.
61 printCluster :: Node.List -> Instance.List
62              -> String
63 printCluster nl il =
64   let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
65       ccv = Cluster.compCV nl
66       nodes = Container.elems nl
67       insts = Container.elems il
68       t_ram = sum . map Node.tMem $ nodes
69       t_dsk = sum . map Node.tDsk $ nodes
70       f_ram = sum . map Node.fMem $ nodes
71       f_dsk = sum . map Node.fDsk $ nodes
72   in printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
73        (length nodes) (length insts)
74        (length bad_nodes) (length bad_instances)
75        t_ram f_ram (t_dsk / 1024) (f_dsk `div` 1024) ccv
76
77 -- | Replace slashes with underscore for saving to filesystem.
78 fixSlash :: String -> String
79 fixSlash = map (\x -> if x == '/' then '_' else x)
80
81 -- | Generates serialized data from loader input.
82 processData :: ClusterData -> Result ClusterData
83 processData input_data = do
84   cdata@(ClusterData _ nl il _ _) <- mergeData [] [] [] [] input_data
85   let (_, fix_nl) = checkData nl il
86   return cdata { cdNodes = fix_nl }
87
88 -- | Writes cluster data out.
89 writeData :: Int
90           -> String
91           -> Options
92           -> Result ClusterData
93           -> IO Bool
94 writeData _ name _ (Bad err) =
95   printf "\nError for %s: failed to load data. Details:\n%s\n" name err >>
96   return False
97
98 writeData nlen name opts (Ok cdata) = do
99   let fixdata = processData cdata
100   case fixdata of
101     Bad err -> printf "\nError for %s: failed to process data. Details:\n%s\n"
102                name err >> return False
103     Ok processed -> writeDataInner nlen name opts cdata processed
104
105 -- | Inner function for writing cluster data to disk.
106 writeDataInner :: Int
107                -> String
108                -> Options
109                -> ClusterData
110                -> ClusterData
111                -> IO Bool
112 writeDataInner nlen name opts cdata fixdata = do
113   let (ClusterData _ nl il _ _) = fixdata
114   printf "%-*s " nlen name :: IO ()
115   hFlush stdout
116   let shownodes = optShowNodes opts
117       odir = optOutPath opts
118       oname = odir </> fixSlash name
119   putStrLn $ printCluster nl il
120   hFlush stdout
121   when (isJust shownodes) $
122        putStr $ Cluster.printNodes nl (fromJust shownodes)
123   writeFile (oname <.> "data") (serializeCluster cdata)
124   return True
125
126 -- | Main function.
127 main :: Options -> [String] -> IO ()
128 main opts clusters = do
129   let local = "LOCAL"
130
131   let nlen = if null clusters
132              then length local
133              else maximum . map length $ clusters
134
135   unless (optNoHeaders opts) $
136          printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
137                 "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
138                 "t_disk" "f_disk" "Score"
139
140   when (null clusters) $ do
141          let lsock = fromMaybe defaultLuxiSocket (optLuxi opts)
142          let name = local
143          input_data <- Luxi.loadData lsock
144          result <- writeData nlen name opts input_data
145          unless result $ exitWith $ ExitFailure 2
146
147   results <- mapM (\name -> Rapi.loadData name >>= writeData nlen name opts)
148              clusters
149   unless (all id results) $ exitWith (ExitFailure 2)