Statistics
| Branch: | Tag: | Revision:

root / hscan.hs @ 0427285d

History | View | Annotate | Download (5 kB)

1
{-| Scan clusters via RAPI and write instance/node data files.
2

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 2009 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 Main (main) where
27

    
28
import Data.List
29
import Data.Function
30
import Monad
31
import System
32
import System.IO
33
import System.FilePath
34
import qualified System
35

    
36
import Text.Printf (printf)
37

    
38
import qualified Ganeti.HTools.Container as Container
39
import qualified Ganeti.HTools.Cluster as Cluster
40
import qualified Ganeti.HTools.Node as Node
41
import qualified Ganeti.HTools.Instance as Instance
42
import qualified Ganeti.HTools.Rapi as Rapi
43
import qualified Ganeti.HTools.Loader as Loader
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
    , oVerbose
54
    , oNoHeaders
55
    , oShowVer
56
    , oShowHelp
57
    ]
58

    
59
-- | Serialize a single node
60
serializeNode :: String -> Node.Node -> String
61
serializeNode csf node =
62
    printf "%s|%.0f|%d|%d|%.0f|%d|%.0f|%c" (Node.name node ++ csf)
63
               (Node.t_mem node) (Node.n_mem node) (Node.f_mem node)
64
               (Node.t_dsk node) (Node.f_dsk node) (Node.t_cpu node)
65
               (if Node.offline node then 'Y' else 'N')
66

    
67
-- | Generate node file data from node objects
68
serializeNodes :: String -> Node.List -> String
69
serializeNodes csf =
70
    unlines . map (serializeNode csf) . Container.elems
71

    
72
-- | Serialize a single instance
73
serializeInstance :: String -> Node.List -> Instance.Instance -> String
74
serializeInstance csf nl inst =
75
    let
76
        iname = Instance.name inst ++ csf
77
        pnode = Container.nameOf nl (Instance.pnode inst) ++ csf
78
        sidx = Instance.snode inst
79
        snode = (if sidx == Node.noSecondary
80
                    then ""
81
                    else Container.nameOf nl sidx ++ csf)
82
    in
83
      printf "%s|%d|%d|%d|%s|%s|%s"
84
             iname (Instance.mem inst) (Instance.dsk inst)
85
             (Instance.vcpus inst) (Instance.run_st inst)
86
             pnode snode
87

    
88
-- | Generate instance file data from instance objects
89
serializeInstances :: String -> Node.List -> Instance.List -> String
90
serializeInstances csf nl =
91
    unlines . map (serializeInstance csf nl) . Container.elems
92

    
93
-- | Return a one-line summary of cluster state
94
printCluster :: Node.List -> Instance.List
95
             -> String
96
printCluster nl il =
97
    let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
98
        ccv = Cluster.compCV nl
99
        nodes = Container.elems nl
100
        insts = Container.elems il
101
        t_ram = sum . map Node.t_mem $ nodes
102
        t_dsk = sum . map Node.t_dsk $ nodes
103
        f_ram = sum . map Node.f_mem $ nodes
104
        f_dsk = sum . map Node.f_dsk $ nodes
105
    in
106
      printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
107
                 (length nodes) (length insts)
108
                 (length bad_nodes) (length bad_instances)
109
                 t_ram f_ram
110
                 (t_dsk / 1024) (f_dsk `div` 1024)
111
                 ccv
112

    
113

    
114
-- | Replace slashes with underscore for saving to filesystem
115

    
116
fixSlash :: String -> String
117
fixSlash = map (\x -> if x == '/' then '_' else x)
118

    
119
-- | Main function.
120
main :: IO ()
121
main = do
122
  cmd_args <- System.getArgs
123
  (opts, clusters) <- parseOpts cmd_args "hscan" options
124

    
125
  let odir = optOutPath opts
126
      nlen = maximum . map length $ clusters
127

    
128
  unless (optNoHeaders opts) $
129
         printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
130
                "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
131
                "t_disk" "f_disk" "Score"
132

    
133
  mapM_ (\ name ->
134
            do
135
              printf "%-*s " nlen name
136
              hFlush stdout
137
              input_data <- Rapi.loadData name
138
              let ldresult = input_data >>= Loader.mergeData
139
              (case ldresult of
140
                 Bad err -> printf "\nError: failed to load data. \
141
                                   \Details:\n%s\n" err
142
                 Ok x -> do
143
                   let (nl, il, csf) = x
144
                       (_, fix_nl) = Loader.checkData nl il
145
                   putStrLn $ printCluster fix_nl il
146
                   when (optShowNodes opts) $
147
                        putStr $ Cluster.printNodes fix_nl
148
                   let ndata = serializeNodes csf nl
149
                       idata = serializeInstances csf nl il
150
                       oname = odir </> fixSlash name
151
                   writeFile (oname <.> "nodes") ndata
152
                   writeFile (oname <.> "instances") idata)
153
       ) clusters