Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / ExtLoader.hs @ 4892d955

History | View | Annotate | Download (4.9 kB)

1
{-| External data loader.
2

    
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.
6

    
7
-}
8

    
9
{-
10

    
11
Copyright (C) 2009, 2010, 2011 Google Inc.
12

    
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.
17

    
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.
22

    
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
26
02110-1301, USA.
27

    
28
-}
29

    
30
module Ganeti.HTools.ExtLoader
31
  ( loadExternalData
32
  , commonSuffix
33
  , maybeSaveData
34
  ) where
35

    
36
import Control.Monad
37
import Data.Maybe (isJust, fromJust)
38
import System.FilePath
39
import System.IO
40
import System.Exit
41
import Text.Printf (hPrintf)
42

    
43
import qualified Ganeti.HTools.Luxi as Luxi
44
import qualified Ganeti.HTools.Rapi as Rapi
45
import qualified Ganeti.HTools.Simu as Simu
46
import qualified Ganeti.HTools.Text as Text
47
import qualified Ganeti.HTools.IAlloc as IAlloc
48
import Ganeti.HTools.Loader (mergeData, checkData, ClusterData(..)
49
                            , commonSuffix)
50

    
51
import Ganeti.HTools.Types
52
import Ganeti.HTools.CLI
53
import Ganeti.HTools.Utils (sepSplit, tryRead)
54

    
55
-- | Error beautifier.
56
wrapIO :: IO (Result a) -> IO (Result a)
57
wrapIO = flip catch (return . Bad . show)
58

    
59
-- | Parses a user-supplied utilisation string.
60
parseUtilisation :: String -> Result (String, DynUtil)
61
parseUtilisation line =
62
  case sepSplit ' ' line of
63
    [name, cpu, mem, dsk, net] ->
64
      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 }
71
        return (name, du)
72
    _ -> Bad $ "Cannot parse line " ++ line
73

    
74
-- | External tool data loader from a variety of sources.
75
loadExternalData :: Options
76
                 -> IO ClusterData
77
loadExternalData opts = do
78
  let mhost = optMaster opts
79
      lsock = optLuxi opts
80
      tfile = optDataFile opts
81
      simdata = optNodeSim opts
82
      iallocsrc = optIAllocSrc opts
83
      setRapi = mhost /= ""
84
      setLuxi = isJust lsock
85
      setSim = (not . null) simdata
86
      setFile = isJust tfile
87
      setIAllocSrc = isJust iallocsrc
88
      allSet = filter id [setRapi, setLuxi, setFile]
89
      exTags = case optExTags opts of
90
                 Nothing -> []
91
                 Just etl -> map (++ ":") etl
92
      selInsts = optSelInst opts
93
      exInsts = optExInst opts
94

    
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
100

    
101
  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
109
  input_data <-
110
    case () of
111
      _ | setRapi -> wrapIO $ Rapi.loadData mhost
112
        | setLuxi -> wrapIO $ Luxi.loadData $ fromJust lsock
113
        | setSim -> Simu.loadData simdata
114
        | setFile -> wrapIO $ Text.loadData $ fromJust tfile
115
        | setIAllocSrc -> wrapIO $ IAlloc.loadData $ fromJust iallocsrc
116
        | otherwise -> return $ Bad "No backend selected! Exiting."
117

    
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
126
  let (fix_msgs, nl) = checkData (cdNodes cdata) (cdInstances cdata)
127

    
128
  unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
129

    
130
  return cdata {cdNodes = nl}
131

    
132
-- | Function to save the cluster data to a file.
133
maybeSaveData :: Maybe FilePath -- ^ The file prefix to save to
134
              -> String         -- ^ The suffix (extension) to add
135
              -> String         -- ^ Informational message
136
              -> ClusterData    -- ^ The cluster data
137
              -> IO ()
138
maybeSaveData Nothing _ _ _ = return ()
139
maybeSaveData (Just path) ext msg cdata = do
140
  let adata = Text.serializeCluster cdata
141
      out_path = path <.> ext
142
  writeFile out_path adata
143
  hPrintf stderr "The cluster state %s has been written to file '%s'\n"
144
          msg out_path