Make Query operators enforce strictness
[ganeti-local] / htools / Ganeti / HTools / Program / Hinfo.hs
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.IO
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.Group as Group
42 import qualified Ganeti.HTools.Instance as Instance
43
44 import Ganeti.Common
45 import Ganeti.HTools.CLI
46 import Ganeti.HTools.ExtLoader
47 import Ganeti.HTools.Loader
48 import Ganeti.Utils
49
50 -- | Options list and functions.
51 options :: IO [OptType]
52 options = do
53   luxi <- oLuxiSocket
54   return
55     [ oPrintNodes
56     , oPrintInsts
57     , oDataFile
58     , oRapiMaster
59     , luxi
60     , oIAllocSrc
61     , oVerbose
62     , oQuiet
63     , oOfflineNode
64     ]
65
66 -- | The list of arguments supported by the program.
67 arguments :: [ArgCompletion]
68 arguments = []
69
70 -- | Group information data-type.
71 data GroupInfo = GroupInfo { giName      :: String
72                            , giNodeCount :: Int
73                            , giInstCount :: Int
74                            , giBadNodes  :: Int
75                            , giBadInsts  :: Int
76                            , giN1Status  :: Bool
77                            , giScore     :: Double
78                            }
79
80 -- | Node group statistics.
81 calcGroupInfo :: Group.Group
82               -> Node.List
83               -> Instance.List
84               -> GroupInfo
85 calcGroupInfo g nl il =
86   let nl_size                    = Container.size nl
87       il_size                    = Container.size il
88       (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
89       bn_size                    = length bad_nodes
90       bi_size                    = length bad_instances
91       n1h                        = bn_size == 0
92       score                      = Cluster.compCV nl
93   in GroupInfo (Group.name g) nl_size il_size bn_size bi_size n1h score
94
95 -- | Helper to format one group row result.
96 groupRowFormatHelper :: GroupInfo -> [String]
97 groupRowFormatHelper gi =
98   [ giName gi
99   , printf "%d" $ giNodeCount gi
100   , printf "%d" $ giInstCount gi
101   , printf "%d" $ giBadNodes gi
102   , printf "%d" $ giBadInsts gi
103   , show $ giN1Status gi
104   , printf "%.8f" $ giScore gi
105   ]
106
107 -- | Print node group information.
108 showGroupInfo :: Int -> Group.List -> Node.List -> Instance.List -> IO ()
109 showGroupInfo verbose gl nl il = do
110   let cgrs   = map (\(gdx, (gnl, gil)) ->
111                  calcGroupInfo (Container.find gdx gl) gnl gil) $
112                  Cluster.splitCluster nl il
113       cn1h   = all giN1Status cgrs
114       grs    = map groupRowFormatHelper cgrs
115       header = ["Group", "Nodes", "Instances", "Bad_Nodes", "Bad_Instances",
116                 "N+1", "Score"]
117
118   when (verbose > 1) $
119     printf "Node group information:\n%s"
120            (printTable "  " header grs [False, True, True, True, True,
121                                         False, True])
122
123   printf "Cluster is N+1 %s\n" $ if cn1h then "happy" else "unhappy"
124
125 -- | Gather and print split instances.
126 splitInstancesInfo :: Int -> Node.List -> Instance.List -> IO ()
127 splitInstancesInfo verbose nl il = do
128   let split_insts = Cluster.findSplitInstances nl il
129   if null split_insts
130     then
131       when (verbose > 1) $
132         putStrLn "No split instances found"::IO ()
133     else do
134       putStrLn "Found instances belonging to multiple node groups:"
135       mapM_ (\i -> hPutStrLn stderr $ "  " ++ Instance.name i) split_insts
136
137 -- | Print common (interesting) information.
138 commonInfo :: Int -> Group.List -> Node.List -> Instance.List -> IO ()
139 commonInfo verbose gl nl il = do
140   when (Container.null il && verbose > 1) $
141     printf "Cluster is empty.\n"::IO ()
142
143   let nl_size = Container.size nl
144       il_size = Container.size il
145       gl_size = Container.size gl
146   printf "Loaded %d %s, %d %s, %d %s\n"
147              nl_size (plural nl_size "node" "nodes")
148              il_size (plural il_size "instance" "instances")
149              gl_size (plural gl_size "node group" "node groups")::IO ()
150
151   let csf = commonSuffix nl il
152   when (not (null csf) && verbose > 2) $
153        printf "Note: Stripping common suffix of '%s' from names\n" csf
154
155 -- | Main function.
156 main :: Options -> [String] -> IO ()
157 main opts args = do
158   unless (null args) $ exitErr "This program doesn't take any arguments."
159
160   let verbose = optVerbose opts
161       shownodes = optShowNodes opts
162       showinsts = optShowInsts opts
163
164   (ClusterData gl fixed_nl ilf ctags ipol) <- loadExternalData opts
165
166   putStrLn $ "Loaded cluster tags: " ++ intercalate "," ctags
167
168   when (verbose > 2) .
169        putStrLn $ "Loaded cluster ipolicy: " ++ show ipol
170
171   nlf <- setNodeStatus opts fixed_nl
172
173   commonInfo verbose gl nlf ilf
174
175   splitInstancesInfo verbose nlf ilf
176
177   showGroupInfo verbose gl nlf ilf
178
179   maybePrintInsts showinsts "Instances" (Cluster.printInsts nlf ilf)
180
181   maybePrintNodes shownodes "Cluster" (Cluster.printNodes nlf)
182
183   printf "Cluster coefficients:\n%s" (Cluster.printStats "  " nlf)::IO ()
184   printf "Cluster score: %.8f\n" (Cluster.compCV nlf)