-{-# LANGUAGE CPP #-}
-
-{-| External data loader
+{-| External data loader.
This module holds the external data loading, and thus is the only one
depending (via the specialized Text\/Rapi\/Luxi modules) on the actual
{-
-Copyright (C) 2009, 2010 Google Inc.
+Copyright (C) 2009, 2010, 2011, 2012 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
-}
module Ganeti.HTools.ExtLoader
- ( loadExternalData
- , commonSuffix
- , maybeSaveData
- ) where
+ ( loadExternalData
+ , commonSuffix
+ , maybeSaveData
+ ) where
+import Control.Monad
+import Control.Exception
import Data.Maybe (isJust, fromJust)
-import Monad
+import Prelude hiding (catch)
import System.FilePath
import System.IO
-import System
-import Text.Printf (printf, hPrintf)
+import Text.Printf (hPrintf)
import qualified Ganeti.HTools.Luxi as Luxi
-#ifndef NO_CURL
import qualified Ganeti.HTools.Rapi as Rapi
-#endif
import qualified Ganeti.HTools.Simu as Simu
import qualified Ganeti.HTools.Text as Text
+import qualified Ganeti.HTools.IAlloc as IAlloc
import Ganeti.HTools.Loader (mergeData, checkData, ClusterData(..)
, commonSuffix)
import Ganeti.HTools.Types
import Ganeti.HTools.CLI
-import Ganeti.HTools.Utils (sepSplit, tryRead)
+import Ganeti.HTools.Utils (sepSplit, tryRead, exitIfBad, exitWhen)
--- | Error beautifier
+-- | Error beautifier.
wrapIO :: IO (Result a) -> IO (Result a)
-wrapIO = flip catch (return . Bad . show)
+wrapIO = handle (\e -> return . Bad . show $ (e::IOException))
+-- | Parses a user-supplied utilisation string.
parseUtilisation :: String -> Result (String, DynUtil)
parseUtilisation line =
- let columns = sepSplit ' ' line
- in case columns of
- [name, cpu, mem, dsk, net] -> do
- rcpu <- tryRead name cpu
- rmem <- tryRead name mem
- rdsk <- tryRead name dsk
- rnet <- tryRead name net
- let du = DynUtil { cpuWeight = rcpu, memWeight = rmem
- , dskWeight = rdsk, netWeight = rnet }
- return (name, du)
- _ -> Bad $ "Cannot parse line " ++ line
+ case sepSplit ' ' line of
+ [name, cpu, mem, dsk, net] ->
+ do
+ rcpu <- tryRead name cpu
+ rmem <- tryRead name mem
+ rdsk <- tryRead name dsk
+ rnet <- tryRead name net
+ let du = DynUtil { cpuWeight = rcpu, memWeight = rmem
+ , dskWeight = rdsk, netWeight = rnet }
+ return (name, du)
+ _ -> Bad $ "Cannot parse line " ++ line
-- | External tool data loader from a variety of sources.
loadExternalData :: Options
lsock = optLuxi opts
tfile = optDataFile opts
simdata = optNodeSim opts
+ iallocsrc = optIAllocSrc opts
setRapi = mhost /= ""
setLuxi = isJust lsock
setSim = (not . null) simdata
setFile = isJust tfile
+ setIAllocSrc = isJust iallocsrc
allSet = filter id [setRapi, setLuxi, setFile]
exTags = case optExTags opts of
Nothing -> []
Just etl -> map (++ ":") etl
+ selInsts = optSelInst opts
exInsts = optExInst opts
- when (length allSet > 1) $
- do
- hPutStrLn stderr ("Error: Only one of the rapi, luxi, and data" ++
- " files options should be given.")
- exitWith $ ExitFailure 1
-
- util_contents <- (case optDynuFile opts of
- Just path -> readFile path
- Nothing -> return "")
- let util_data = mapM parseUtilisation $ lines util_contents
- util_data' <- (case util_data of
- Ok x -> return x
- Bad y -> do
- hPutStrLn stderr ("Error: can't parse utilisation" ++
- " data: " ++ show y)
- exitWith $ ExitFailure 1)
+ exitWhen (length allSet > 1) "Only one of the rapi, luxi, and data\
+ \ files options should be given"
+
+ util_contents <- maybe (return "") readFile (optDynuFile opts)
+ util_data <- exitIfBad "can't parse utilisation data" .
+ mapM parseUtilisation $ lines util_contents
input_data <-
- case () of
- _ | setRapi ->
-#ifdef NO_CURL
- return $ Bad "RAPI/curl backend disabled at compile time"
-#else
- wrapIO $ Rapi.loadData mhost
-#endif
- | setLuxi -> wrapIO $ Luxi.loadData $ fromJust lsock
- | setSim -> Simu.loadData simdata
- | setFile -> wrapIO $ Text.loadData $ fromJust tfile
- | otherwise -> return $ Bad "No backend selected! Exiting."
-
- let ldresult = input_data >>= mergeData util_data' exTags exInsts
- cdata <-
- (case ldresult of
- Ok x -> return x
- Bad s -> do
- hPrintf stderr "Error: failed to load data. Details:\n%s\n" s
- :: IO ()
- exitWith $ ExitFailure 1
- )
+ case () of
+ _ | setRapi -> wrapIO $ Rapi.loadData mhost
+ | setLuxi -> wrapIO . Luxi.loadData $ fromJust lsock
+ | setSim -> Simu.loadData simdata
+ | setFile -> wrapIO . Text.loadData $ fromJust tfile
+ | setIAllocSrc -> wrapIO . IAlloc.loadData $ fromJust iallocsrc
+ | otherwise -> return $ Bad "No backend selected! Exiting."
+
+ let ldresult = input_data >>= mergeData util_data exTags selInsts exInsts
+ cdata <- exitIfBad "failed to load data, aborting" ldresult
let (fix_msgs, nl) = checkData (cdNodes cdata) (cdInstances cdata)
- unless (null fix_msgs || optVerbose opts == 0) $ do
- hPutStrLn stderr "Warning: cluster has inconsistent data:"
- hPutStrLn stderr . unlines . map (printf " - %s") $ fix_msgs
+ unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
return cdata {cdNodes = nl}