Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / Program / Hscan.hs @ 981bb5cf

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, 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)