Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / HTools / ExtLoader.hs @ 23594127

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 Text.Printf (hPrintf)
42

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

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

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

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

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

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

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

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

    
115
  unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
116

    
117
  return cdata {cdNodes = nl}
118

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