Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / HTools / ExtLoader.hs @ 09ab9fb2

History | View | Annotate | Download (4.6 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 Control.Exception
38
import Data.Maybe (isJust, fromJust)
39
import System.FilePath
40
import System.IO
41
import System.Time (getClockTime)
42
import Text.Printf (hPrintf)
43

    
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(..)
50
                            , commonSuffix)
51

    
52
import Ganeti.BasicTypes
53
import Ganeti.HTools.Types
54
import Ganeti.HTools.CLI
55
import Ganeti.Utils (sepSplit, tryRead, exitIfBad, exitWhen)
56

    
57
-- | Error beautifier.
58
wrapIO :: IO (Result a) -> IO (Result a)
59
wrapIO = handle (\e -> return . Bad . show $ (e::IOException))
60

    
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] ->
66
      do
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 }
73
        return (name, du)
74
    _ -> Bad $ "Cannot parse line " ++ line
75

    
76
-- | External tool data loader from a variety of sources.
77
loadExternalData :: Options
78
                 -> IO ClusterData
79
loadExternalData opts = do
80
  let mhost = optMaster opts
81
      lsock = optLuxi opts
82
      tfile = optDataFile opts
83
      simdata = optNodeSim opts
84
      iallocsrc = optIAllocSrc opts
85
      setRapi = mhost /= ""
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
92
                 Nothing -> []
93
                 Just etl -> map (++ ":") etl
94
      selInsts = optSelInst opts
95
      exInsts = optExInst opts
96

    
97
  exitWhen (length allSet > 1) "Only one of the rapi, luxi, and data\
98
                               \ files options should be given."
99

    
100
  util_contents <- maybe (return "") readFile (optDynuFile opts)
101
  util_data <- exitIfBad "can't parse utilisation data" .
102
               mapM parseUtilisation $ lines util_contents
103
  input_data <-
104
    case () of
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."
111
  now <- getClockTime
112

    
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)
116

    
117
  unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
118

    
119
  return cdata {cdNodes = nl}
120

    
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
126
              -> IO ()
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"
133
          msg out_path