1 {-| Scan clusters via RAPI and write instance/node data files.
5 module Main (main) where
9 import Data.Maybe(fromJust)
13 import System.FilePath
14 import System.Console.GetOpt
15 import qualified System
17 import Text.Printf (printf)
19 import qualified Ganeti.HTools.Container as Container
20 import qualified Ganeti.HTools.Cluster as Cluster
21 import qualified Ganeti.HTools.Node as Node
22 import qualified Ganeti.HTools.Instance as Instance
23 import qualified Ganeti.HTools.CLI as CLI
24 import Ganeti.HTools.Rapi
25 import Ganeti.HTools.Utils
27 -- | Command line options structure.
28 data Options = Options
29 { optShowNodes :: Bool -- ^ Whether to show node status
30 , optOutPath :: FilePath -- ^ Path to the output directory
31 , optVerbose :: Int -- ^ Verbosity level
32 , optNoHeader :: Bool -- ^ Do not show a header line
33 , optShowVer :: Bool -- ^ Just show the program version
34 , optShowHelp :: Bool -- ^ Just show the help
37 -- | Default values for the command line options.
38 defaultOptions :: Options
39 defaultOptions = Options
40 { optShowNodes = False
48 -- | Options list and functions
49 options :: [OptDescr (Options -> Options)]
51 [ Option ['p'] ["print-nodes"]
52 (NoArg (\ opts -> opts { optShowNodes = True }))
53 "print the final node list"
54 , Option ['d'] ["output-dir"]
55 (ReqArg (\ d opts -> opts { optOutPath = d }) "PATH")
56 "directory in which to write output files"
57 , Option ['v'] ["verbose"]
58 (NoArg (\ opts -> opts { optVerbose = (optVerbose opts) + 1 }))
59 "increase the verbosity level"
60 , Option [] ["no-headers"]
61 (NoArg (\ opts -> opts { optNoHeader = True }))
62 "do not show a header line"
63 , Option ['V'] ["version"]
64 (NoArg (\ opts -> opts { optShowVer = True}))
65 "show the version of the program"
66 , Option ['h'] ["help"]
67 (NoArg (\ opts -> opts { optShowHelp = True}))
71 -- | Generate node file data from node objects
72 serializeNodes :: Cluster.NodeList -> String -> Cluster.NameList -> String
73 serializeNodes nl csf ktn =
74 let etn = map (\(idx, name) -> (idx, name ++ csf)) ktn
75 nodes = Container.elems nl
78 let name = (fromJust $ lookup (Node.idx node) etn)
79 t_mem = (truncate $ Node.t_mem node)::Int
80 t_dsk = (truncate $ Node.t_dsk node)::Int
82 printf "%s|%d|%d|%d|%d|%d" name
83 t_mem (Node.n_mem node) (Node.f_mem node)
84 t_dsk (Node.f_dsk node))
88 -- | Generate instance file data from instance objects
89 serializeInstances :: Cluster.InstanceList -> String
90 -> Cluster.NameList -> Cluster.NameList -> String
91 serializeInstances il csf ktn kti =
92 let etn = map (\(idx, name) -> (idx, name ++ csf)) ktn
93 eti = map (\(idx, name) -> (idx, name ++ csf)) kti
94 instances = Container.elems il
98 iname = fromJust $ lookup (Instance.idx inst) eti
99 pnode = fromJust $ lookup (Instance.pnode inst) etn
100 snode = fromJust $ lookup (Instance.snode inst) etn
102 printf "%s|%d|%d|%s|%s"
103 iname (Instance.mem inst) (Instance.dsk inst)
109 -- | Return a one-line summary of cluster state
110 printCluster :: Cluster.NodeList -> Cluster.InstanceList
111 -> Cluster.NameList -> Cluster.NameList
113 printCluster nl il ktn kti =
114 let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
115 ccv = Cluster.compCV nl
116 nodes = Container.elems nl
117 t_ram = truncate . sum . map Node.t_mem $ nodes
118 t_dsk = truncate . sum . map Node.t_dsk $ nodes
119 f_ram = sum . map Node.f_mem $ nodes
120 f_dsk = sum . map Node.f_dsk $ nodes
122 printf "%5d %5d %5d %5d %6d %6d %6d %6d %.8f"
123 (length ktn) (length kti)
124 (length bad_nodes) (length bad_instances)
125 (t_ram::Integer) f_ram
126 ((t_dsk::Integer) `div` 1024) (f_dsk `div` 1024)
133 cmd_args <- System.getArgs
134 (opts, clusters) <- CLI.parseOpts cmd_args "hscan" options
135 defaultOptions optShowHelp
137 when (optShowVer opts) $ do
138 putStr $ CLI.showVersion "hscan"
141 let odir = optOutPath opts
142 nlen = maximum . map length $ clusters
144 unless (optNoHeader opts) $
145 printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
146 "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
147 "t_disk" "f_disk" "Score"
151 printf "%-*s " nlen name
153 node_data <- getNodes name
154 inst_data <- getInstances name
155 (if isLeft(node_data)
156 then putStrLn $ fromLeft node_data
157 else if isLeft(inst_data)
158 then putStrLn $ fromLeft inst_data
160 let ndata = fromRight node_data
161 idata = fromRight inst_data
162 (nl, il, csf, ktn, kti) =
163 Cluster.loadData ndata idata
164 putStrLn $ printCluster nl il ktn kti
165 when (optShowNodes opts) $
166 putStr $ Cluster.printNodes ktn nl
167 let ndata = serializeNodes nl csf ktn
168 idata = serializeInstances il csf ktn kti
169 oname = odir </> name
170 writeFile (oname <.> "nodes") ndata
171 writeFile (oname <.> "instances") idata)