Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / Program / Hscan.hs @ d66aa238

History | View | Annotate | Download (4.9 kB)

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
27
  ( main
28
  , options
29
  , arguments
30
  ) where
31

    
32
import Control.Monad
33
import Data.Maybe (isJust, fromJust, fromMaybe)
34
import System.Exit
35
import System.IO
36
import System.FilePath
37

    
38
import Text.Printf (printf)
39

    
40
import Ganeti.BasicTypes
41
import qualified Ganeti.HTools.Container as Container
42
import qualified Ganeti.HTools.Cluster as Cluster
43
import qualified Ganeti.HTools.Node as Node
44
import qualified Ganeti.HTools.Instance as Instance
45
import qualified Ganeti.HTools.Backend.Rapi as Rapi
46
import qualified Ganeti.HTools.Backend.Luxi as Luxi
47
import qualified Ganeti.Path as Path
48
import Ganeti.HTools.Loader (checkData, mergeData, ClusterData(..))
49
import Ganeti.HTools.Backend.Text (serializeCluster)
50

    
51
import Ganeti.Common
52
import Ganeti.HTools.CLI
53

    
54
-- | Options list and functions.
55
options :: IO [OptType]
56
options =
57
  return
58
    [ oPrintNodes
59
    , oOutputDir
60
    , oLuxiSocket
61
    , oVerbose
62
    , oNoHeaders
63
    ]
64

    
65
-- | The list of arguments supported by the program.
66
arguments :: [ArgCompletion]
67
arguments = [ArgCompletion OptComplHost 0 Nothing]
68

    
69
-- | Return a one-line summary of cluster state.
70
printCluster :: Node.List -> Instance.List
71
             -> String
72
printCluster nl il =
73
  let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
74
      ccv = Cluster.compCV nl
75
      nodes = Container.elems nl
76
      insts = Container.elems il
77
      t_ram = sum . map Node.tMem $ nodes
78
      t_dsk = sum . map Node.tDsk $ nodes
79
      f_ram = sum . map Node.fMem $ nodes
80
      f_dsk = sum . map Node.fDsk $ nodes
81
  in printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
82
       (length nodes) (length insts)
83
       (length bad_nodes) (length bad_instances)
84
       t_ram f_ram (t_dsk / 1024) (f_dsk `div` 1024) ccv
85

    
86
-- | Replace slashes with underscore for saving to filesystem.
87
fixSlash :: String -> String
88
fixSlash = map (\x -> if x == '/' then '_' else x)
89

    
90
-- | Generates serialized data from loader input.
91
processData :: ClusterData -> Result ClusterData
92
processData input_data = do
93
  cdata@(ClusterData _ nl il _ _) <- mergeData [] [] [] [] input_data
94
  let (_, fix_nl) = checkData nl il
95
  return cdata { cdNodes = fix_nl }
96

    
97
-- | Writes cluster data out.
98
writeData :: Int
99
          -> String
100
          -> Options
101
          -> Result ClusterData
102
          -> IO Bool
103
writeData _ name _ (Bad err) =
104
  printf "\nError for %s: failed to load data. Details:\n%s\n" name err >>
105
  return False
106

    
107
writeData nlen name opts (Ok cdata) = do
108
  let fixdata = processData cdata
109
  case fixdata of
110
    Bad err -> printf "\nError for %s: failed to process data. Details:\n%s\n"
111
               name err >> return False
112
    Ok processed -> writeDataInner nlen name opts cdata processed
113

    
114
-- | Inner function for writing cluster data to disk.
115
writeDataInner :: Int
116
               -> String
117
               -> Options
118
               -> ClusterData
119
               -> ClusterData
120
               -> IO Bool
121
writeDataInner nlen name opts cdata fixdata = do
122
  let (ClusterData _ nl il _ _) = fixdata
123
  printf "%-*s " nlen name :: IO ()
124
  hFlush stdout
125
  let shownodes = optShowNodes opts
126
      odir = optOutPath opts
127
      oname = odir </> fixSlash name
128
  putStrLn $ printCluster nl il
129
  hFlush stdout
130
  when (isJust shownodes) .
131
       putStr $ Cluster.printNodes nl (fromJust shownodes)
132
  writeFile (oname <.> "data") (serializeCluster cdata)
133
  return True
134

    
135
-- | Main function.
136
main :: Options -> [String] -> IO ()
137
main opts clusters = do
138
  let local = "LOCAL"
139

    
140
  let nlen = if null clusters
141
             then length local
142
             else maximum . map length $ clusters
143

    
144
  unless (optNoHeaders opts) $
145
         printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
146
                "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
147
                "t_disk" "f_disk" "Score"
148

    
149
  when (null clusters) $ do
150
         let lsock = fromMaybe Path.defaultLuxiSocket (optLuxi opts)
151
         let name = local
152
         input_data <- Luxi.loadData lsock
153
         result <- writeData nlen name opts input_data
154
         unless result . exitWith $ ExitFailure 2
155

    
156
  results <- mapM (\name -> Rapi.loadData name >>= writeData nlen name opts)
157
             clusters
158
  unless (all id results) $ exitWith (ExitFailure 2)