Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / ExtLoader.hs @ 88a10df5

History | View | Annotate | Download (4.5 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, 2012 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 Text.Printf (hPrintf)
41

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

    
50
import Ganeti.HTools.Types
51
import Ganeti.HTools.CLI
52
import Ganeti.HTools.Utils (sepSplit, tryRead, exitIfBad, exitWhen)
53

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

    
58
-- | Parses a user-supplied utilisation string.
59
parseUtilisation :: String -> Result (String, DynUtil)
60
parseUtilisation line =
61
  case sepSplit ' ' line of
62
    [name, cpu, mem, dsk, net] ->
63
      do
64
        rcpu <- tryRead name cpu
65
        rmem <- tryRead name mem
66
        rdsk <- tryRead name dsk
67
        rnet <- tryRead name net
68
        let du = DynUtil { cpuWeight = rcpu, memWeight = rmem
69
                         , dskWeight = rdsk, netWeight = rnet }
70
        return (name, du)
71
    _ -> Bad $ "Cannot parse line " ++ line
72

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

    
94
  exitWhen (length allSet > 1) "Only one of the rapi, luxi, and data\
95
                               \ files options should be given"
96

    
97
  util_contents <- maybe (return "") readFile (optDynuFile opts)
98
  util_data <- exitIfBad "can't parse utilisation data" .
99
               mapM parseUtilisation $ lines util_contents
100
  input_data <-
101
    case () of
102
      _ | setRapi -> wrapIO $ Rapi.loadData mhost
103
        | setLuxi -> wrapIO $ Luxi.loadData $ fromJust lsock
104
        | setSim -> Simu.loadData simdata
105
        | setFile -> wrapIO $ Text.loadData $ fromJust tfile
106
        | setIAllocSrc -> wrapIO $ IAlloc.loadData $ fromJust iallocsrc
107
        | otherwise -> return $ Bad "No backend selected! Exiting."
108

    
109
  let ldresult = input_data >>= mergeData util_data exTags selInsts exInsts
110
  cdata <- exitIfBad "failed to load data, aborting" ldresult
111
  let (fix_msgs, nl) = checkData (cdNodes cdata) (cdInstances cdata)
112

    
113
  unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
114

    
115
  return cdata {cdNodes = nl}
116

    
117
-- | Function to save the cluster data to a file.
118
maybeSaveData :: Maybe FilePath -- ^ The file prefix to save to
119
              -> String         -- ^ The suffix (extension) to add
120
              -> String         -- ^ Informational message
121
              -> ClusterData    -- ^ The cluster data
122
              -> IO ()
123
maybeSaveData Nothing _ _ _ = return ()
124
maybeSaveData (Just path) ext msg cdata = do
125
  let adata = Text.serializeCluster cdata
126
      out_path = path <.> ext
127
  writeFile out_path adata
128
  hPrintf stderr "The cluster state %s has been written to file '%s'\n"
129
          msg out_path