3 {-| External data loader
5 This module holds the external data loading, and thus is the only one
6 depending (via the specialized Text\/Rapi\/Luxi modules) on the actual
7 libraries implementing the low-level protocols.
13 Copyright (C) 2009 Google Inc.
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 module Ganeti.HTools.ExtLoader
36 import Data.Maybe (isJust, fromJust)
40 import Text.Printf (printf, hPrintf)
42 import qualified Ganeti.HTools.Luxi as Luxi
44 import qualified Ganeti.HTools.Rapi as Rapi
46 import qualified Ganeti.HTools.Simu as Simu
47 import qualified Ganeti.HTools.Text as Text
48 import qualified Ganeti.HTools.Loader as Loader
49 import qualified Ganeti.HTools.Instance as Instance
50 import qualified Ganeti.HTools.Node as Node
52 import Ganeti.HTools.Types
53 import Ganeti.HTools.CLI
54 import Ganeti.HTools.Utils (sepSplit, tryRead)
57 wrapIO :: IO (Result a) -> IO (Result a)
58 wrapIO = flip catch (return . Bad . show)
60 parseUtilisation :: String -> Result (String, DynUtil)
61 parseUtilisation line =
62 let columns = sepSplit ' ' line
64 [name, cpu, mem, dsk, net] -> do
65 rcpu <- tryRead name cpu
66 rmem <- tryRead name mem
67 rdsk <- tryRead name dsk
68 rnet <- tryRead name net
69 let du = DynUtil { cpuWeight = rcpu, memWeight = rmem
70 , dskWeight = rdsk, netWeight = rnet }
72 _ -> Bad $ "Cannot parse line " ++ line
74 -- | External tool data loader from a variety of sources.
75 loadExternalData :: Options
76 -> IO (Node.List, Instance.List, [String], String)
77 loadExternalData opts = do
78 let mhost = optMaster opts
80 tfile = optDataFile opts
81 simdata = optNodeSim opts
83 setLuxi = isJust lsock
84 setSim = isJust simdata
85 setFile = isJust tfile
86 allSet = filter id [setRapi, setLuxi, setFile]
87 exTags = case optExTags opts of
89 Just etl -> map (++ ":") etl
91 when (length allSet > 1) $
93 hPutStrLn stderr ("Error: Only one of the rapi, luxi, and data" ++
94 " files options should be given.")
95 exitWith $ ExitFailure 1
97 util_contents <- (case optDynuFile opts of
98 Just path -> readFile path
100 let util_data = mapM parseUtilisation $ lines util_contents
101 util_data' <- (case util_data of
104 hPutStrLn stderr ("Error: can't parse utilisation" ++
106 exitWith $ ExitFailure 1)
111 return $ Bad "RAPI/curl backend disabled at compile time"
113 wrapIO $ Rapi.loadData mhost
115 | setLuxi -> wrapIO $ Luxi.loadData $ fromJust lsock
116 | setSim -> Simu.loadData $ fromJust simdata
117 | setFile -> wrapIO $ Text.loadData $ fromJust tfile
118 | otherwise -> return $ Bad "No backend selected! Exiting."
120 let ldresult = input_data >>= Loader.mergeData util_data' exTags
121 (loaded_nl, il, tags, csf) <-
125 hPrintf stderr "Error: failed to load data. Details:\n%s\n" s
126 exitWith $ ExitFailure 1
128 let (fix_msgs, fixed_nl) = Loader.checkData loaded_nl il
130 unless (null fix_msgs || optVerbose opts == 0) $ do
131 hPutStrLn stderr "Warning: cluster has inconsistent data:"
132 hPutStrLn stderr . unlines . map (printf " - %s") $ fix_msgs
134 return (fixed_nl, il, tags, csf)