Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / HTools / ExtLoader.hs @ 3b170ad4

History | View | Annotate | Download (4.8 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, clearDynU)
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 ignoreDynU = optIgnoreDynu opts
114
      eff_u = if ignoreDynU then [] else util_data
115
      ldresult = input_data >>= (if ignoreDynU then clearDynU else return)
116
                            >>= mergeData eff_u exTags selInsts exInsts now
117
  cdata <- exitIfBad "failed to load data, aborting" ldresult
118
  let (fix_msgs, nl) = checkData (cdNodes cdata) (cdInstances cdata)
119

    
120
  unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
121

    
122
  return cdata {cdNodes = nl}
123

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