This repository has been archived by the owner on May 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hscan.hs
169 lines (142 loc) · 5.07 KB
/
hscan.hs
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
{-# LANGUAGE CPP #-}
{-| Scan clusters via RAPI or LUXI and write state data files.
-}
{-
Copyright (C) 2009, 2010, 2011 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 Main (main) where
import Data.Maybe (isJust, fromJust, fromMaybe)
import Monad
import System (exitWith, ExitCode(..))
import System.IO
import System.FilePath
import qualified System
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
import qualified Ganeti.HTools.Instance as Instance
#ifndef NO_CURL
import qualified Ganeti.HTools.Rapi as Rapi
#endif
import qualified Ganeti.HTools.Luxi as Luxi
import Ganeti.HTools.Loader (checkData, mergeData, ClusterData(..))
import Ganeti.HTools.Text (serializeCluster)
import Ganeti.HTools.CLI
import Ganeti.HTools.Types
-- | Options list and functions
options :: [OptType]
options =
[ oPrintNodes
, oOutputDir
, oLuxiSocket
, oVerbose
, oNoHeaders
, oShowVer
, oShowHelp
]
-- | Return a one-line summary of cluster state
printCluster :: Node.List -> Instance.List
-> String
printCluster nl il =
let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
ccv = Cluster.compCV nl
nodes = Container.elems nl
insts = Container.elems il
t_ram = sum . map Node.tMem $ nodes
t_dsk = sum . map Node.tDsk $ nodes
f_ram = sum . map Node.fMem $ nodes
f_dsk = sum . map Node.fDsk $ nodes
in
printf "%5d %5d %5d %5d %6.0f %6d %6.0f %6d %.8f"
(length nodes) (length insts)
(length bad_nodes) (length bad_instances)
t_ram f_ram
(t_dsk / 1024) (f_dsk `div` 1024)
ccv
-- | Replace slashes with underscore for saving to filesystem
fixSlash :: String -> String
fixSlash = map (\x -> if x == '/' then '_' else x)
-- | Generates serialized data from loader input.
processData :: ClusterData -> Result ClusterData
processData input_data = do
cdata@(ClusterData _ nl il _) <- mergeData [] [] [] input_data
let (_, fix_nl) = checkData nl il
return cdata { cdNodes = fix_nl }
-- | Writes cluster data out
writeData :: Int
-> String
-> Options
-> Result ClusterData
-> IO Bool
writeData _ name _ (Bad err) =
printf "\nError for %s: failed to load data. Details:\n%s\n" name err >>
return False
writeData nlen name opts (Ok cdata) = do
let fixdata = processData cdata
case fixdata of
Bad err -> printf "\nError for %s: failed to process data. Details:\n%s\n"
name err >> return False
Ok processed -> writeDataInner nlen name opts cdata processed
writeDataInner :: Int
-> String
-> Options
-> ClusterData
-> ClusterData
-> IO Bool
writeDataInner nlen name opts cdata fixdata = do
let (ClusterData _ nl il _) = fixdata
printf "%-*s " nlen name :: IO ()
hFlush stdout
let shownodes = optShowNodes opts
odir = optOutPath opts
oname = odir </> fixSlash name
putStrLn $ printCluster nl il
hFlush stdout
when (isJust shownodes) $
putStr $ Cluster.printNodes nl (fromJust shownodes)
writeFile (oname <.> "data") (serializeCluster cdata)
return True
-- | Main function.
main :: IO ()
main = do
cmd_args <- System.getArgs
(opts, clusters) <- parseOpts cmd_args "hscan" options
let local = "LOCAL"
let nlen = if null clusters
then length local
else maximum . map length $ clusters
unless (optNoHeaders opts) $
printf "%-*s %5s %5s %5s %5s %6s %6s %6s %6s %10s\n" nlen
"Name" "Nodes" "Inst" "BNode" "BInst" "t_mem" "f_mem"
"t_disk" "f_disk" "Score"
when (null clusters) $ do
let lsock = fromMaybe defaultLuxiSocket (optLuxi opts)
let name = local
input_data <- Luxi.loadData lsock
result <- writeData nlen name opts input_data
when (not result) $ exitWith $ ExitFailure 2
#ifndef NO_CURL
results <- mapM (\ name ->
do
input_data <- Rapi.loadData name
writeData nlen name opts input_data
) clusters
when (not $ all id results) $ exitWith (ExitFailure 2)
#else
when (not $ null clusters) $ do
putStrLn "RAPI/curl backend disabled at compile time, cannot scan clusters"
exitWith $ ExitFailure 1
#endif