1 {-| External data loader.
3 This module holds the external data loading, and thus is the only one
4 depending (via the specialized Text\/Rapi\/Luxi modules) on the actual
5 libraries implementing the low-level protocols.
11 Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 module Ganeti.HTools.ExtLoader
37 import Control.Exception
38 import Data.Maybe (isJust, fromJust)
39 import System.FilePath
41 import System.Time (getClockTime)
42 import Text.Printf (hPrintf)
44 import qualified Ganeti.HTools.Backend.Luxi as Luxi
45 import qualified Ganeti.HTools.Backend.Rapi as Rapi
46 import qualified Ganeti.HTools.Backend.Simu as Simu
47 import qualified Ganeti.HTools.Backend.Text as Text
48 import qualified Ganeti.HTools.Backend.IAlloc as IAlloc
49 import Ganeti.HTools.Loader (mergeData, checkData, ClusterData(..)
52 import Ganeti.BasicTypes
53 import Ganeti.HTools.Types
54 import Ganeti.HTools.CLI
55 import Ganeti.Utils (sepSplit, tryRead, exitIfBad, exitWhen)
57 -- | Error beautifier.
58 wrapIO :: IO (Result a) -> IO (Result a)
59 wrapIO = handle (\e -> return . Bad . show $ (e::IOException))
61 -- | Parses a user-supplied utilisation string.
62 parseUtilisation :: String -> Result (String, DynUtil)
63 parseUtilisation line =
64 case sepSplit ' ' line of
65 [name, cpu, mem, dsk, net] ->
67 rcpu <- tryRead name cpu
68 rmem <- tryRead name mem
69 rdsk <- tryRead name dsk
70 rnet <- tryRead name net
71 let du = DynUtil { cpuWeight = rcpu, memWeight = rmem
72 , dskWeight = rdsk, netWeight = rnet }
74 _ -> Bad $ "Cannot parse line " ++ line
76 -- | External tool data loader from a variety of sources.
77 loadExternalData :: Options
79 loadExternalData opts = do
80 let mhost = optMaster opts
82 tfile = optDataFile opts
83 simdata = optNodeSim opts
84 iallocsrc = optIAllocSrc opts
86 setLuxi = isJust lsock
87 setSim = (not . null) simdata
88 setFile = isJust tfile
89 setIAllocSrc = isJust iallocsrc
90 allSet = filter id [setRapi, setLuxi, setFile]
91 exTags = case optExTags opts of
93 Just etl -> map (++ ":") etl
94 selInsts = optSelInst opts
95 exInsts = optExInst opts
97 exitWhen (length allSet > 1) "Only one of the rapi, luxi, and data\
98 \ files options should be given."
100 util_contents <- maybe (return "") readFile (optDynuFile opts)
101 util_data <- exitIfBad "can't parse utilisation data" .
102 mapM parseUtilisation $ lines util_contents
105 _ | setRapi -> wrapIO $ Rapi.loadData mhost
106 | setLuxi -> wrapIO . Luxi.loadData $ fromJust lsock
107 | setSim -> Simu.loadData simdata
108 | setFile -> wrapIO . Text.loadData $ fromJust tfile
109 | setIAllocSrc -> wrapIO . IAlloc.loadData $ fromJust iallocsrc
110 | otherwise -> return $ Bad "No backend selected! Exiting."
113 let ldresult = input_data >>= mergeData util_data exTags selInsts exInsts now
114 cdata <- exitIfBad "failed to load data, aborting" ldresult
115 let (fix_msgs, nl) = checkData (cdNodes cdata) (cdInstances cdata)
117 unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
119 return cdata {cdNodes = nl}
121 -- | Function to save the cluster data to a file.
122 maybeSaveData :: Maybe FilePath -- ^ The file prefix to save to
123 -> String -- ^ The suffix (extension) to add
124 -> String -- ^ Informational message
125 -> ClusterData -- ^ The cluster data
127 maybeSaveData Nothing _ _ _ = return ()
128 maybeSaveData (Just path) ext msg cdata = do
129 let adata = Text.serializeCluster cdata
130 out_path = path <.> ext
131 writeFile out_path adata
132 hPrintf stderr "The cluster state %s has been written to file '%s'\n"