Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / HTools / Program / Hscan.hs @ 7ec2f76b

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

    
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 = do
57
  luxi <- oLuxiSocket
58
  return
59
    [ oPrintNodes
60
    , oOutputDir
61
    , luxi
62
    , oVerbose
63
    , oNoHeaders
64
    ]
65

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

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

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

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

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

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

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

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

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

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

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

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