Revision 88a10df5
b/htools/Ganeti/BasicTypes.hs | ||
---|---|---|
26 | 26 |
, eitherToResult |
27 | 27 |
, annotateResult |
28 | 28 |
, annotateIOError |
29 |
, exitIfBad |
|
30 | 29 |
) where |
31 | 30 |
|
32 | 31 |
import Control.Monad |
33 |
import System.IO (hPutStrLn, stderr) |
|
34 |
import System.Exit |
|
35 | 32 |
|
36 | 33 |
-- | This is similar to the JSON library Result type - /very/ similar, |
37 | 34 |
-- but we want to use it in multiple places, so we abstract it into a |
... | ... | |
81 | 78 |
annotateIOError :: String -> IOError -> IO (Result a) |
82 | 79 |
annotateIOError description exc = |
83 | 80 |
return . Bad $ description ++ ": " ++ show exc |
84 |
|
|
85 |
-- | Unwraps a 'Result', exiting the program if it is a 'Bad' value, |
|
86 |
-- otherwise returning the actual contained value. |
|
87 |
exitIfBad :: Result a -> IO a |
|
88 |
exitIfBad (Bad s) = do |
|
89 |
hPutStrLn stderr $ "Failure: " ++ s |
|
90 |
exitWith (ExitFailure 1) |
|
91 |
exitIfBad (Ok v) = return v |
b/htools/Ganeti/Confd/Server.hs | ||
---|---|---|
51 | 51 |
import Ganeti.Config |
52 | 52 |
import Ganeti.Hash |
53 | 53 |
import Ganeti.Logging |
54 |
import Ganeti.BasicTypes |
|
55 | 54 |
import qualified Ganeti.Constants as C |
56 | 55 |
|
57 | 56 |
-- * Types and constants definitions |
... | ... | |
504 | 503 |
main :: DaemonOptions -> IO () |
505 | 504 |
main opts = do |
506 | 505 |
parseresult <- parseAddress opts C.defaultConfdPort |
507 |
(af_family, bindaddr) <- exitIfBad parseresult |
|
506 |
(af_family, bindaddr) <- exitIfBad "parsing bind address" parseresult
|
|
508 | 507 |
s <- S.socket af_family S.Datagram S.defaultProtocol |
509 | 508 |
S.bindSocket s bindaddr |
510 | 509 |
cref <- newIORef (Bad "Configuration not yet loaded") |
b/htools/Ganeti/Daemon.hs | ||
---|---|---|
171 | 171 |
(opt_list, args, []) -> |
172 | 172 |
do |
173 | 173 |
parsed_opts <- |
174 |
case foldM (flip id) defaultOptions opt_list of |
|
175 |
Bad msg -> do |
|
176 |
hPutStrLn stderr "Error while parsing command\ |
|
177 |
\line arguments:" |
|
178 |
hPutStrLn stderr msg |
|
179 |
exitWith $ ExitFailure 1 |
|
180 |
Ok val -> return val |
|
174 |
exitIfBad "Error while parsing command line arguments" $ |
|
175 |
foldM (flip id) defaultOptions opt_list |
|
181 | 176 |
return (parsed_opts, args) |
182 | 177 |
(_, _, errs) -> do |
183 | 178 |
hPutStrLn stderr $ "Command line error: " ++ concat errs |
... | ... | |
291 | 286 |
compilerName (Data.Version.showVersion compilerVersion) |
292 | 287 |
os arch :: IO () |
293 | 288 |
exitWith ExitSuccess |
294 |
unless (null args) $ do |
|
295 |
hPutStrLn stderr "This program doesn't take any arguments" |
|
296 |
exitWith $ ExitFailure C.exitFailure |
|
289 |
|
|
290 |
exitUnless (null args) "This program doesn't take any arguments" |
|
297 | 291 |
|
298 | 292 |
unless (optNoUserChecks opts) $ do |
299 | 293 |
runtimeEnts <- getEnts |
300 |
case runtimeEnts of |
|
301 |
Bad msg -> do |
|
302 |
hPutStrLn stderr $ "Can't find required user/groups: " ++ msg |
|
303 |
exitWith $ ExitFailure C.exitFailure |
|
304 |
Ok ents -> verifyDaemonUser daemon ents |
|
294 |
ents <- exitIfBad "Can't find required user/groups" runtimeEnts |
|
295 |
verifyDaemonUser daemon ents |
|
305 | 296 |
|
306 | 297 |
syslog <- case optSyslogUsage opts of |
307 |
Nothing -> exitIfBad $ |
|
308 |
annotateResult "Invalid cluster syslog setting" $ |
|
298 |
Nothing -> exitIfBad "Invalid cluster syslog setting" $ |
|
309 | 299 |
syslogUsageFromRaw C.syslogUsage |
310 | 300 |
Just v -> return v |
311 | 301 |
let processFn = if optDaemonize opts then daemonize else id |
... | ... | |
319 | 309 |
setupLogging (daemonLogFile daemon) (daemonName daemon) (optDebug opts) |
320 | 310 |
(not (optDaemonize opts)) False syslog |
321 | 311 |
pid_fd <- writePidFile (daemonPidFile daemon) |
322 |
case pid_fd of |
|
323 |
Bad msg -> do |
|
324 |
hPutStrLn stderr $ "Cannot write PID file; already locked? Error: " ++ |
|
325 |
msg |
|
326 |
exitWith $ ExitFailure 1 |
|
327 |
_ -> return () |
|
312 |
_ <- exitIfBad "Cannot write PID file; already locked? Error" pid_fd |
|
328 | 313 |
logNotice "starting" |
329 | 314 |
main |
b/htools/Ganeti/HTools/CLI.hs | ||
---|---|---|
88 | 88 |
import System.IO |
89 | 89 |
import System.Info |
90 | 90 |
import System.Exit |
91 |
import Text.Printf (printf, hPrintf)
|
|
91 |
import Text.Printf (printf) |
|
92 | 92 |
|
93 | 93 |
import qualified Ganeti.HTools.Version as Version(version) |
94 | 94 |
import qualified Ganeti.HTools.Container as Container |
... | ... | |
577 | 577 |
m_dsk = optMdsk opts |
578 | 578 |
|
579 | 579 |
unless (null offline_wrong) $ do |
580 |
hPrintf stderr "Error: Wrong node name(s) set as offline: %s\n" |
|
581 |
(commaJoin (map lrContent offline_wrong)) :: IO () |
|
582 |
exitWith $ ExitFailure 1 |
|
580 |
exitErr $ printf "wrong node name(s) set as offline: %s\n" |
|
581 |
(commaJoin (map lrContent offline_wrong)) |
|
583 | 582 |
let setMCpuFn = case m_cpu of |
584 | 583 |
Nothing -> id |
585 | 584 |
Just new_mcpu -> flip Node.setMcpu new_mcpu |
b/htools/Ganeti/HTools/ExtLoader.hs | ||
---|---|---|
8 | 8 |
|
9 | 9 |
{- |
10 | 10 |
|
11 |
Copyright (C) 2009, 2010, 2011 Google Inc. |
|
11 |
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
|
|
12 | 12 |
|
13 | 13 |
This program is free software; you can redistribute it and/or modify |
14 | 14 |
it under the terms of the GNU General Public License as published by |
... | ... | |
37 | 37 |
import Data.Maybe (isJust, fromJust) |
38 | 38 |
import System.FilePath |
39 | 39 |
import System.IO |
40 |
import System.Exit |
|
41 | 40 |
import Text.Printf (hPrintf) |
42 | 41 |
|
43 | 42 |
import qualified Ganeti.HTools.Luxi as Luxi |
... | ... | |
50 | 49 |
|
51 | 50 |
import Ganeti.HTools.Types |
52 | 51 |
import Ganeti.HTools.CLI |
53 |
import Ganeti.HTools.Utils (sepSplit, tryRead) |
|
52 |
import Ganeti.HTools.Utils (sepSplit, tryRead, exitIfBad, exitWhen)
|
|
54 | 53 |
|
55 | 54 |
-- | Error beautifier. |
56 | 55 |
wrapIO :: IO (Result a) -> IO (Result a) |
... | ... | |
92 | 91 |
selInsts = optSelInst opts |
93 | 92 |
exInsts = optExInst opts |
94 | 93 |
|
95 |
when (length allSet > 1) $ |
|
96 |
do |
|
97 |
hPutStrLn stderr ("Error: Only one of the rapi, luxi, and data" ++ |
|
98 |
" files options should be given.") |
|
99 |
exitWith $ ExitFailure 1 |
|
94 |
exitWhen (length allSet > 1) "Only one of the rapi, luxi, and data\ |
|
95 |
\ files options should be given" |
|
100 | 96 |
|
101 | 97 |
util_contents <- maybe (return "") readFile (optDynuFile opts) |
102 |
let util_data = mapM parseUtilisation $ lines util_contents |
|
103 |
util_data' <- case util_data of |
|
104 |
Ok x -> return x |
|
105 |
Bad y -> do |
|
106 |
hPutStrLn stderr ("Error: can't parse utilisation" ++ |
|
107 |
" data: " ++ show y) |
|
108 |
exitWith $ ExitFailure 1 |
|
98 |
util_data <- exitIfBad "can't parse utilisation data" . |
|
99 |
mapM parseUtilisation $ lines util_contents |
|
109 | 100 |
input_data <- |
110 | 101 |
case () of |
111 | 102 |
_ | setRapi -> wrapIO $ Rapi.loadData mhost |
... | ... | |
115 | 106 |
| setIAllocSrc -> wrapIO $ IAlloc.loadData $ fromJust iallocsrc |
116 | 107 |
| otherwise -> return $ Bad "No backend selected! Exiting." |
117 | 108 |
|
118 |
let ldresult = input_data >>= mergeData util_data' exTags selInsts exInsts |
|
119 |
cdata <- |
|
120 |
case ldresult of |
|
121 |
Ok x -> return x |
|
122 |
Bad s -> do |
|
123 |
hPrintf stderr |
|
124 |
"Error: failed to load data, aborting. Details:\n%s\n" s:: IO () |
|
125 |
exitWith $ ExitFailure 1 |
|
109 |
let ldresult = input_data >>= mergeData util_data exTags selInsts exInsts |
|
110 |
cdata <- exitIfBad "failed to load data, aborting" ldresult |
|
126 | 111 |
let (fix_msgs, nl) = checkData (cdNodes cdata) (cdInstances cdata) |
127 | 112 |
|
128 | 113 |
unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs |
b/htools/Ganeti/HTools/Program/Hspace.hs | ||
---|---|---|
31 | 31 |
import Data.List |
32 | 32 |
import Data.Maybe (fromMaybe) |
33 | 33 |
import Data.Ord (comparing) |
34 |
import System.Exit |
|
35 | 34 |
import System.IO |
36 | 35 |
|
37 | 36 |
import Text.Printf (printf, hPrintf) |
... | ... | |
173 | 172 |
let fin_stats = Cluster.totalResources fin_nl |
174 | 173 |
fin_instances = num_instances + allocs |
175 | 174 |
|
176 |
when (num_instances + allocs /= Cluster.csNinst fin_stats) $ |
|
177 |
do |
|
178 |
hPrintf stderr "ERROR: internal inconsistency, allocated (%d)\ |
|
179 |
\ != counted (%d)\n" (num_instances + allocs) |
|
180 |
(Cluster.csNinst fin_stats) :: IO () |
|
181 |
exitWith $ ExitFailure 1 |
|
175 |
exitWhen (num_instances + allocs /= Cluster.csNinst fin_stats) $ |
|
176 |
printf "internal inconsistency, allocated (%d)\ |
|
177 |
\ != counted (%d)\n" (num_instances + allocs) |
|
178 |
(Cluster.csNinst fin_stats) |
|
182 | 179 |
|
183 | 180 |
printKeys $ printStats PFinal fin_stats |
184 | 181 |
printKeys [ ("ALLOC_USAGE", printf "%.8f" |
... | ... | |
350 | 347 |
sortReasons :: [(FailMode, Int)] -> [(FailMode, Int)] |
351 | 348 |
sortReasons = reverse . sortBy (comparing snd) |
352 | 349 |
|
353 |
-- | Aborts the program if we get a bad value. |
|
354 |
exitIfBad :: Result a -> IO a |
|
355 |
exitIfBad (Bad s) = |
|
356 |
hPrintf stderr "Failure: %s\n" s >> exitWith (ExitFailure 1) |
|
357 |
exitIfBad (Ok v) = return v |
|
358 |
|
|
359 | 350 |
-- | Runs an allocation algorithm and saves cluster state. |
360 | 351 |
runAllocation :: ClusterData -- ^ Cluster data |
361 | 352 |
-> Maybe Cluster.AllocResult -- ^ Optional stop-allocation |
... | ... | |
369 | 360 |
(reasons, new_nl, new_il, new_ixes, _) <- |
370 | 361 |
case stop_allocation of |
371 | 362 |
Just result_noalloc -> return result_noalloc |
372 |
Nothing -> exitIfBad actual_result |
|
363 |
Nothing -> exitIfBad "failure during allocation" actual_result
|
|
373 | 364 |
|
374 | 365 |
let name = head . words . specDescription $ mode |
375 | 366 |
descr = name ++ " allocation" |
... | ... | |
395 | 386 |
-- | Main function. |
396 | 387 |
main :: Options -> [String] -> IO () |
397 | 388 |
main opts args = do |
398 |
unless (null args) $ do |
|
399 |
hPutStrLn stderr "Error: this program doesn't take any arguments." |
|
400 |
exitWith $ ExitFailure 1 |
|
389 |
exitUnless (null args) "this program doesn't take any arguments" |
|
401 | 390 |
|
402 | 391 |
let verbose = optVerbose opts |
403 | 392 |
machine_r = optMachineReadable opts |
... | ... | |
408 | 397 |
cluster_disk_template <- |
409 | 398 |
case iPolicyDiskTemplates ipol of |
410 | 399 |
first_templ:_ -> return first_templ |
411 |
_ -> do |
|
412 |
_ <- hPutStrLn stderr $ "Error: null list of disk templates\ |
|
413 |
\ received from cluster!" |
|
414 |
exitWith $ ExitFailure 1 |
|
400 |
_ -> exitErr "null list of disk templates received from cluster" |
|
415 | 401 |
|
416 | 402 |
let num_instances = Container.size il |
417 | 403 |
all_nodes = Container.elems fixed_nl |
... | ... | |
440 | 426 |
then Nothing |
441 | 427 |
else Just (optMaxLength opts) |
442 | 428 |
|
443 |
allocnodes <- exitIfBad $ Cluster.genAllocNodes gl nl req_nodes True |
|
429 |
allocnodes <- exitIfBad "failure during allocation" $ |
|
430 |
Cluster.genAllocNodes gl nl req_nodes True |
|
444 | 431 |
|
445 | 432 |
-- Run the tiered allocation |
446 | 433 |
|
b/htools/Ganeti/HTools/Utils.hs | ||
---|---|---|
36 | 36 |
, printTable |
37 | 37 |
, parseUnit |
38 | 38 |
, plural |
39 |
, exitIfBad |
|
40 |
, exitErr |
|
41 |
, exitWhen |
|
42 |
, exitUnless |
|
39 | 43 |
) where |
40 | 44 |
|
41 | 45 |
import Data.Char (toUpper) |
... | ... | |
43 | 47 |
|
44 | 48 |
import Debug.Trace |
45 | 49 |
|
50 |
import Ganeti.BasicTypes |
|
51 |
import System.IO |
|
52 |
import System.Exit |
|
53 |
|
|
46 | 54 |
-- * Debug functions |
47 | 55 |
|
48 | 56 |
-- | To be used only for debugging, breaks referential integrity. |
... | ... | |
198 | 206 |
scaling <- parseUnitValue unit |
199 | 207 |
return $ truncate (fromIntegral v * scaling) |
200 | 208 |
_ -> fail $ "Can't parse string '" ++ str ++ "'" |
209 |
|
|
210 |
-- | Unwraps a 'Result', exiting the program if it is a 'Bad' value, |
|
211 |
-- otherwise returning the actual contained value. |
|
212 |
exitIfBad :: String -> Result a -> IO a |
|
213 |
exitIfBad msg (Bad s) = do |
|
214 |
hPutStrLn stderr $ "Error: " ++ msg ++ ": " ++ s |
|
215 |
exitWith (ExitFailure 1) |
|
216 |
exitIfBad _ (Ok v) = return v |
|
217 |
|
|
218 |
-- | Exits immediately with an error message. |
|
219 |
exitErr :: String -> IO a |
|
220 |
exitErr errmsg = do |
|
221 |
hPutStrLn stderr $ "Error: " ++ errmsg ++ "." |
|
222 |
exitWith (ExitFailure 1) |
|
223 |
|
|
224 |
-- | Exits with an error message if the given boolean condition if true. |
|
225 |
exitWhen :: Bool -> String -> IO () |
|
226 |
exitWhen True msg = exitErr msg |
|
227 |
exitWhen False _ = return () |
|
228 |
|
|
229 |
-- | Exits with an error message /unless/ the given boolean condition |
|
230 |
-- if true, the opposite of 'exitWhen'. |
|
231 |
exitUnless :: Bool -> String -> IO () |
|
232 |
exitUnless cond = exitWhen (not cond) |
Also available in: Unified diff