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