Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / Program / Hinfo.hs @ 22278fa7

History | View | Annotate | Download (5.7 kB)

1
{-| Cluster information printer.
2

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 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.Hinfo
27
  ( main
28
  , options
29
  , arguments
30
  ) where
31

    
32
import Control.Monad
33
import Data.List
34
import System.Exit
35
import System.IO
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.Group as Group
43
import qualified Ganeti.HTools.Instance as Instance
44

    
45
import Ganeti.Common
46
import Ganeti.HTools.CLI
47
import Ganeti.HTools.ExtLoader
48
import Ganeti.HTools.Loader
49
import Ganeti.Utils
50

    
51
-- | Options list and functions.
52
options :: [OptType]
53
options =
54
  [ oPrintNodes
55
  , oPrintInsts
56
  , oDataFile
57
  , oRapiMaster
58
  , oLuxiSocket
59
  , oIAllocSrc
60
  , oVerbose
61
  , oQuiet
62
  , oOfflineNode
63
  ]
64

    
65
-- | The list of arguments supported by the program.
66
arguments :: [ArgCompletion]
67
arguments = []
68

    
69
-- | Group information data-type.
70
data GroupInfo = GroupInfo { giName      :: String
71
                           , giNodeCount :: Int
72
                           , giInstCount :: Int
73
                           , giBadNodes  :: Int
74
                           , giBadInsts  :: Int
75
                           , giN1Status  :: Bool
76
                           , giScore     :: Double
77
                           }
78

    
79
-- | Node group statistics.
80
calcGroupInfo :: Group.Group
81
              -> Node.List
82
              -> Instance.List
83
              -> GroupInfo
84
calcGroupInfo g nl il =
85
  let nl_size                    = Container.size nl
86
      il_size                    = Container.size il
87
      (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
88
      bn_size                    = length bad_nodes
89
      bi_size                    = length bad_instances
90
      n1h                        = bn_size == 0
91
      score                      = Cluster.compCV nl
92
  in GroupInfo (Group.name g) nl_size il_size bn_size bi_size n1h score
93

    
94
-- | Helper to format one group row result.
95
groupRowFormatHelper :: GroupInfo -> [String]
96
groupRowFormatHelper gi =
97
  [ giName gi
98
  , printf "%d" $ giNodeCount gi
99
  , printf "%d" $ giInstCount gi
100
  , printf "%d" $ giBadNodes gi
101
  , printf "%d" $ giBadInsts gi
102
  , show $ giN1Status gi
103
  , printf "%.8f" $ giScore gi
104
  ]
105

    
106
-- | Print node group information.
107
showGroupInfo :: Int -> Group.List -> Node.List -> Instance.List -> IO ()
108
showGroupInfo verbose gl nl il = do
109
  let cgrs   = map (\(gdx, (gnl, gil)) ->
110
                 calcGroupInfo (Container.find gdx gl) gnl gil) $
111
                 Cluster.splitCluster nl il
112
      cn1h   = all giN1Status cgrs
113
      grs    = map groupRowFormatHelper cgrs
114
      header = ["Group", "Nodes", "Instances", "Bad_Nodes", "Bad_Instances",
115
                "N+1", "Score"]
116

    
117
  when (verbose > 1) $
118
    printf "Node group information:\n%s"
119
           (printTable "  " header grs [False, True, True, True, True,
120
                                        False, True])
121

    
122
  printf "Cluster is N+1 %s\n" $ if cn1h then "happy" else "unhappy"
123

    
124
-- | Gather and print split instances.
125
splitInstancesInfo :: Int -> Node.List -> Instance.List -> IO ()
126
splitInstancesInfo verbose nl il = do
127
  let split_insts = Cluster.findSplitInstances nl il
128
  if null split_insts
129
    then
130
      when (verbose > 1) $
131
        putStrLn "No split instances found"::IO ()
132
    else do
133
      putStrLn "Found instances belonging to multiple node groups:"
134
      mapM_ (\i -> hPutStrLn stderr $ "  " ++ Instance.name i) split_insts
135

    
136
-- | Print common (interesting) information.
137
commonInfo :: Int -> Group.List -> Node.List -> Instance.List -> IO ()
138
commonInfo verbose gl nl il = do
139
  when (Container.null il && verbose > 1) $
140
    printf "Cluster is empty.\n"::IO ()
141

    
142
  let nl_size = Container.size nl
143
      il_size = Container.size il
144
      gl_size = Container.size gl
145
  printf "Loaded %d %s, %d %s, %d %s\n"
146
             nl_size (plural nl_size "node" "nodes")
147
             il_size (plural il_size "instance" "instances")
148
             gl_size (plural gl_size "node group" "node groups")::IO ()
149

    
150
  let csf = commonSuffix nl il
151
  when (not (null csf) && verbose > 2) $
152
       printf "Note: Stripping common suffix of '%s' from names\n" csf
153

    
154
-- | Main function.
155
main :: Options -> [String] -> IO ()
156
main opts args = do
157
  unless (null args) $ do
158
         hPutStrLn stderr "Error: this program doesn't take any arguments."
159
         exitWith $ ExitFailure 1
160

    
161
  let verbose = optVerbose opts
162
      shownodes = optShowNodes opts
163
      showinsts = optShowInsts opts
164

    
165
  (ClusterData gl fixed_nl ilf ctags ipol) <- loadExternalData opts
166

    
167
  putStrLn $ "Loaded cluster tags: " ++ intercalate "," ctags
168

    
169
  when (verbose > 2) .
170
       putStrLn $ "Loaded cluster ipolicy: " ++ show ipol
171

    
172
  nlf <- setNodeStatus opts fixed_nl
173

    
174
  commonInfo verbose gl nlf ilf
175

    
176
  splitInstancesInfo verbose nlf ilf
177

    
178
  showGroupInfo verbose gl nlf ilf
179

    
180
  maybePrintInsts showinsts "Instances" (Cluster.printInsts nlf ilf)
181

    
182
  maybePrintNodes shownodes "Cluster" (Cluster.printNodes nlf)
183

    
184
  printf "Cluster coefficients:\n%s" (Cluster.printStats "  " nlf)::IO ()
185
  printf "Cluster score: %.8f\n" (Cluster.compCV nlf)