Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / HTools / Program / Hscan.hs @ 2d6bdcc5

History | View | Annotate | Download (5 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
import System.Time
38

    
39
import Text.Printf (printf)
40

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

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

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

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

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

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

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

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

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

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

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

    
143
  let nlen = if null clusters
144
             then length local
145
             else maximum . map length $ clusters
146

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

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

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