hscan.hs 4.99 KB
Newer Older
Iustin Pop's avatar
Iustin Pop committed
1
2
3
4
{-| Scan clusters via RAPI and write instance/node data files.

-}

Iustin Pop's avatar
Iustin Pop committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{-

Copyright (C) 2009 Google Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

-}

Iustin Pop's avatar
Iustin Pop committed
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
module Main (main) where

import Data.List
import Data.Function
import Monad
import System
import System.IO
import System.FilePath
import qualified System

import Text.Printf (printf)

import qualified Ganeti.HTools.Container as Container
import qualified Ganeti.HTools.Cluster as Cluster
import qualified Ganeti.HTools.Node as Node
import qualified Ganeti.HTools.Instance as Instance
Iustin Pop's avatar
Iustin Pop committed
42
import qualified Ganeti.HTools.Rapi as Rapi
Iustin Pop's avatar
Iustin Pop committed
43
import qualified Ganeti.HTools.Loader as Loader
Iustin Pop's avatar
Iustin Pop committed
44

45
46
import Ganeti.HTools.CLI
import Ganeti.HTools.Types
Iustin Pop's avatar
Iustin Pop committed
47
48

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

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

Iustin Pop's avatar
Iustin Pop committed
67
-- | Generate node file data from node objects
68
69
70
71
72
73
74
75
76
serializeNodes :: String -> Node.List -> String
serializeNodes csf =
    unlines . map (serializeNode csf) . Container.elems

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

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

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


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

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

Iustin Pop's avatar
Iustin Pop committed
119
120
121
122
-- | Main function.
main :: IO ()
main = do
  cmd_args <- System.getArgs
123
  (opts, clusters) <- parseOpts cmd_args "hscan" options
Iustin Pop's avatar
Iustin Pop committed
124
125
126
127

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

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

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