Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / Program / Hscan.hs @ 8b5a517a

History | View | Annotate | Download (4.7 kB)

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.Environment (getArgs)
31
import System.Exit
32
import System.IO
33
import System.FilePath
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 <- 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)