Statistics
| Branch: | Tag: | Revision:

root / hscan.hs @ 94e05c32

History | View | Annotate | Download (5.1 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 Data.Maybe (isJust, fromJust)
31
import Monad
32
import System
33
import System.IO
34
import System.FilePath
35
import qualified System
36

    
37
import Text.Printf (printf)
38

    
39
import qualified Ganeti.HTools.Container as Container
40
import qualified Ganeti.HTools.Cluster as Cluster
41
import qualified Ganeti.HTools.Node as Node
42
import qualified Ganeti.HTools.Instance as Instance
43
import qualified Ganeti.HTools.Rapi as Rapi
44
import qualified Ganeti.HTools.Loader as Loader
45

    
46
import Ganeti.HTools.CLI
47
import Ganeti.HTools.Types
48

    
49
-- | Options list and functions
50
options :: [OptType]
51
options =
52
    [ oPrintNodes
53
    , oOutputDir
54
    , oVerbose
55
    , oNoHeaders
56
    , oShowVer
57
    , oShowHelp
58
    ]
59

    
60
-- | Serialize a single node
61
serializeNode :: String -> Node.Node -> String
62
serializeNode csf node =
63
    printf "%s|%.0f|%d|%d|%.0f|%d|%.0f|%c" (Node.name node ++ csf)
64
               (Node.tMem node) (Node.nMem node) (Node.fMem node)
65
               (Node.tDsk node) (Node.fDsk node) (Node.tCpu node)
66
               (if Node.offline node then 'Y' else 'N')
67

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

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

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

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

    
114

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

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

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

    
126
  let odir = optOutPath opts
127
      nlen = maximum . map length $ clusters
128
      shownodes = optShowNodes opts
129

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

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