Hinfo.hs 5.11 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{-| Cluster information printer.

-}

{-

Copyright (C) 2012 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.

-}

module Ganeti.HTools.Program.Hinfo (main, options) where

import Control.Monad
import Data.List
import System.Exit
import System.IO

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
38
import qualified Ganeti.HTools.Group as Group
39
40
import qualified Ganeti.HTools.Instance as Instance

41
import Ganeti.HTools.Utils
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import Ganeti.HTools.CLI
import Ganeti.HTools.ExtLoader
import Ganeti.HTools.Loader

-- | Options list and functions.
options :: [OptType]
options =
  [ oPrintNodes
  , oPrintInsts
  , oDataFile
  , oRapiMaster
  , oLuxiSocket
  , oVerbose
  , oQuiet
  , oOfflineNode
  , oShowVer
  , oShowHelp
  ]

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
-- | Node group statistics.
calcGroupInfo :: Group.Group
              -> Node.List
              -> Instance.List
              -> (String, (Int, Int), (Int, Int), Bool)
calcGroupInfo g nl il =
  let nl_size                    = Container.size nl
      il_size                    = Container.size il
      (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
      bn_size                    = length bad_nodes
      bi_size                    = length bad_instances
      n1h                        = bn_size == 0
  in (Group.name g, (nl_size, il_size), (bn_size, bi_size), n1h)

-- | Helper to format one group row result.
groupRowFormatHelper :: (String, (Int, Int), (Int, Int), Bool) -> [String]
groupRowFormatHelper (gname, (nl_size, il_size), (bn_size, bi_size), n1h) =
  [ gname
  , printf "%d" nl_size
  , printf "%d" il_size
  , printf "%d" bn_size
  , printf "%d" bi_size
  , show n1h ]

-- | Print node group information.
showGroupInfo :: Int -> Group.List -> Node.List -> Instance.List -> IO ()
showGroupInfo verbose gl nl il = do
  let cgrs   = map (\(gdx, (gnl, gil)) ->
                 calcGroupInfo (Container.find gdx gl) gnl gil) $
                 Cluster.splitCluster nl il
      cn1h   = all (\(_, _, _, n1h) -> n1h) cgrs
      grs    = map groupRowFormatHelper cgrs
      header = ["Group", "Nodes", "Instances", "Bad_Nodes", "Bad_Instances",
                "N+1"]

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

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

-- | Gather and print split instances.
103
104
splitInstancesInfo :: Int -> Node.List -> Instance.List -> IO ()
splitInstancesInfo verbose nl il = do
105
  let split_insts = Cluster.findSplitInstances nl il
106
107
108
109
110
111
112
113
  if (null split_insts)
    then
      when (verbose > 1) $ do
        putStrLn "No split instances found"::IO ()
    else do
      putStrLn "Found instances belonging to multiple node groups:"
      mapM_ (\i -> hPutStrLn stderr $ "  " ++ Instance.name i) split_insts

114
-- | Print common (interesting) information.
115
116
117
118
119
120
121
122
123
124
125
126
commonInfo :: Int -> Group.List -> Node.List -> Instance.List -> IO ()
commonInfo verbose gl nl il = do
  when (Container.null il && verbose > 1) $ do
         printf "Cluster is empty.\n"::IO ()

  let nl_size = (Container.size nl)
      il_size = (Container.size il)
      gl_size = (Container.size gl)
  printf "Loaded %d %s, %d %s, %d %s\n"
             nl_size (plural nl_size "node" "nodes")
             il_size (plural il_size "instance" "instances")
             gl_size (plural gl_size "node group" "node groups")::IO ()
127
128

  let csf = commonSuffix nl il
René Nussbaumer's avatar
René Nussbaumer committed
129
  when (not (null csf) && verbose > 2) $
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
       printf "Note: Stripping common suffix of '%s' from names\n" csf

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

  let verbose = optVerbose opts
      shownodes = optShowNodes opts
      showinsts = optShowInsts opts

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

René Nussbaumer's avatar
René Nussbaumer committed
145
146
147
  putStrLn $ "Loaded cluster tags: " ++ intercalate "," ctags

  when (verbose > 2) $ do
148
149
150
151
       putStrLn $ "Loaded cluster ipolicy: " ++ show ipol

  nlf <- setNodeStatus opts fixed_nl

152
153
154
  commonInfo verbose gl nlf ilf

  splitInstancesInfo verbose nlf ilf
155

156
157
  showGroupInfo verbose gl nlf ilf

158
159
160
161
162
163
  maybePrintInsts showinsts "Instances" (Cluster.printInsts nlf ilf)

  maybePrintNodes shownodes "Cluster" (Cluster.printNodes nlf)

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