Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / ExtLoader.hs @ a86fbf36

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

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

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

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

    
91
  when (length allSet > 1) $
92
       do
93
         hPutStrLn stderr ("Error: Only one of the rapi, luxi, and data" ++
94
                           " files options should be given.")
95
         exitWith $ ExitFailure 1
96

    
97
  util_contents <- (case optDynuFile opts of
98
                      Just path -> readFile path
99
                      Nothing -> return "")
100
  let util_data = mapM parseUtilisation $ lines util_contents
101
  util_data' <- (case util_data of
102
                   Ok x -> return x
103
                   Bad y -> do
104
                     hPutStrLn stderr ("Error: can't parse utilisation" ++
105
                                       " data: " ++ show y)
106
                     exitWith $ ExitFailure 1)
107
  input_data <-
108
      case () of
109
        _ | setRapi -> wrapIO $ Rapi.loadData mhost
110
          | setLuxi -> wrapIO $ Luxi.loadData $ fromJust lsock
111
          | setSim -> Simu.loadData simdata
112
          | setFile -> wrapIO $ Text.loadData $ fromJust tfile
113
          | otherwise -> return $ Bad "No backend selected! Exiting."
114

    
115
  let ldresult = input_data >>= mergeData util_data' exTags selInsts exInsts
116
  cdata <-
117
      (case ldresult of
118
         Ok x -> return x
119
         Bad s -> do
120
           hPrintf stderr
121
             "Error: failed to load data, aborting. Details:\n%s\n" s:: IO ()
122
           exitWith $ ExitFailure 1
123
      )
124
  let (fix_msgs, nl) = checkData (cdNodes cdata) (cdInstances cdata)
125

    
126
  unless (optVerbose opts == 0) $ maybeShowWarnings fix_msgs
127

    
128
  return cdata {cdNodes = nl}
129

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