1 {-| Scan clusters via RAPI and write instance/node data files.
7 Copyright (C) 2009 Google Inc.
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.
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.
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
26 module Main (main) where
30 import Data.Maybe (isJust, fromJust)
34 import System.FilePath
35 import qualified System
37 import Text.Printf (printf)
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.Instance as Instance
43 import qualified Ganeti.HTools.Rapi as Rapi
44 import qualified Ganeti.HTools.Loader as Loader
46 import Ganeti.HTools.CLI
47 import Ganeti.HTools.Types
49 -- | Options list and functions
60 -- | Serialize a single node
61 serializeNode :: String -> Node.Node -> String
62 serializeNode csf node =
63 printf "%s|%.0f|%d|%d|%.0f|%d|%.0f|%c" (Node.name node ++ csf)
64 (Node.tMem node) (Node.nMem node) (Node.fMem node)
65 (Node.tDsk node) (Node.fDsk node) (Node.tCpu node)
66 (if Node.offline node then 'Y' else 'N')
68 -- | Generate node file data from node objects
69 serializeNodes :: String -> Node.List -> String
71 unlines . map (serializeNode csf) . Container.elems
73 -- | Serialize a single instance
74 serializeInstance :: String -> Node.List -> Instance.Instance -> String
75 serializeInstance csf nl inst =
77 iname = Instance.name inst ++ csf
78 pnode = Container.nameOf nl (Instance.pNode inst) ++ csf
79 sidx = Instance.sNode inst
80 snode = (if sidx == Node.noSecondary
82 else Container.nameOf nl sidx ++ csf)
84 printf "%s|%d|%d|%d|%s|%s|%s|%s"
85 iname (Instance.mem inst) (Instance.dsk inst)
86 (Instance.vcpus inst) (Instance.runSt inst)
87 pnode snode (intercalate "," (Instance.tags inst))
89 -- | Generate instance file data from instance objects
90 serializeInstances :: String -> Node.List -> Instance.List -> String
91 serializeInstances csf nl =
92 unlines . map (serializeInstance csf nl) . Container.elems
94 -- | Return a one-line summary of cluster state
95 printCluster :: Node.List -> Instance.List
98 let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
99 ccv = Cluster.compCV nl
100 nodes = Container.elems nl
101 insts = Container.elems il
102 t_ram = sum . map Node.tMem $ nodes
103 t_dsk = sum . map Node.tDsk $ nodes
104 f_ram = sum . map Node.fMem $ nodes
105 f_dsk = sum . map Node.fDsk $ nodes
107 printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
108 (length nodes) (length insts)
109 (length bad_nodes) (length bad_instances)
111 (t_dsk / 1024) (f_dsk `div` 1024)
115 -- | Replace slashes with underscore for saving to filesystem
117 fixSlash :: String -> String
118 fixSlash = map (\x -> if x == '/' then '_' else x)
123 cmd_args <- System.getArgs
124 (opts, clusters) <- parseOpts cmd_args "hscan" options
126 let odir = optOutPath opts
127 nlen = maximum . map length $ clusters
128 shownodes = optShowNodes opts
130 unless (optNoHeaders opts) $
131 printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
132 "Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
133 "t_disk" "f_disk" "Score"
137 printf "%-*s " nlen name
139 input_data <- Rapi.loadData name
140 let ldresult = input_data >>= Loader.mergeData [] []
142 Bad err -> printf "\nError: failed to load data. \
145 let (nl, il, csf) = x
146 (_, fix_nl) = Loader.checkData nl il
147 putStrLn $ printCluster fix_nl il
148 when (isJust shownodes) $
149 putStr $ Cluster.printNodes fix_nl (fromJust shownodes)
150 let ndata = serializeNodes csf nl
151 idata = serializeInstances csf nl il
152 oname = odir </> fixSlash name
153 writeFile (oname <.> "nodes") ndata
154 writeFile (oname <.> "instances") idata)