Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Text.hs @ f25e5aac

History | View | Annotate | Download (4 kB)

1
{-| Parsing data from text-files
2

    
3
This module holds the code for loading the cluster state from text
4
files, as produced by gnt-node and gnt-instance list.
5

    
6
-}
7

    
8
{-
9

    
10
Copyright (C) 2009 Google Inc.
11

    
12
This program is free software; you can redistribute it and/or modify
13
it under the terms of the GNU General Public License as published by
14
the Free Software Foundation; either version 2 of the License, or
15
(at your option) any later version.
16

    
17
This program is distributed in the hope that it will be useful, but
18
WITHOUT ANY WARRANTY; without even the implied warranty of
19
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20
General Public License for more details.
21

    
22
You should have received a copy of the GNU General Public License
23
along with this program; if not, write to the Free Software
24
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25
02110-1301, USA.
26

    
27
-}
28

    
29
module Ganeti.HTools.Text
30
    (
31
      loadData
32
    ) where
33

    
34
import Control.Monad
35

    
36
import Ganeti.HTools.Utils
37
import Ganeti.HTools.Loader
38
import Ganeti.HTools.Types
39
import qualified Ganeti.HTools.Node as Node
40
import qualified Ganeti.HTools.Instance as Instance
41

    
42
-- | Parse results from readsPrec
43
parseChoices :: (Monad m, Read a) => String -> String -> [(a, String)] -> m a
44
parseChoices _ _ ((v, ""):[]) = return v
45
parseChoices name s ((_, e):[]) =
46
    fail $ name ++ ": leftover characters when parsing '"
47
           ++ s ++ "': '" ++ e ++ "'"
48
parseChoices name s _ = fail $ name ++ ": cannot parse string '" ++ s ++ "'"
49

    
50
-- | Safe 'read' function returning data encapsulated in a Result.
51
tryRead :: (Monad m, Read a) => String -> String -> m a
52
tryRead name s = parseChoices name s $ reads s
53

    
54
-- | Load a node from a field list.
55
loadNode :: (Monad m) => [String] -> m (String, Node.Node)
56
loadNode (name:tm:nm:fm:td:fd:tc:fo:[]) = do
57
  new_node <-
58
      if any (== "?") [tm,nm,fm,td,fd,tc] || fo == "Y" then
59
          return $ Node.create name 0 0 0 0 0 0 True
60
      else do
61
        vtm <- tryRead name tm
62
        vnm <- tryRead name nm
63
        vfm <- tryRead name fm
64
        vtd <- tryRead name td
65
        vfd <- tryRead name fd
66
        vtc <- tryRead name tc
67
        return $ Node.create name vtm vnm vfm vtd vfd vtc False
68
  return (name, new_node)
69
loadNode s = fail $ "Invalid/incomplete node data: '" ++ show s ++ "'"
70

    
71
-- | Load an instance from a field list.
72
loadInst :: (Monad m) =>
73
            [(String, Ndx)] -> [String] -> m (String, Instance.Instance)
74
loadInst ktn (name:mem:dsk:vcpus:status:pnode:snode:[]) = do
75
  pidx <- lookupNode ktn name pnode
76
  sidx <- (if null snode then return Node.noSecondary
77
           else lookupNode ktn name snode)
78
  vmem <- tryRead name mem
79
  vdsk <- tryRead name dsk
80
  vvcpus <- tryRead name vcpus
81
  when (sidx == pidx) $ fail $ "Instance " ++ name ++
82
           " has same primary and secondary node - " ++ pnode
83
  let newinst = Instance.create name vmem vdsk vvcpus status pidx sidx
84
  return (name, newinst)
85
loadInst _ s = fail $ "Invalid/incomplete instance data: '" ++ show s ++ "'"
86

    
87
-- | Convert newline and delimiter-separated text.
88
--
89
-- This function converts a text in tabular format as generated by
90
-- @gnt-instance list@ and @gnt-node list@ to a list of objects using
91
-- a supplied conversion function.
92
loadTabular :: (Monad m, Element a) =>
93
               String -> ([String] -> m (String, a))
94
            -> m ([(String, Int)], [(Int, a)])
95
loadTabular text_data convert_fn = do
96
  let lines_data = lines text_data
97
      rows = map (sepSplit '|') lines_data
98
  kerows <- mapM convert_fn rows
99
  return $ assignIndices kerows
100

    
101
-- | Builds the cluster data from node\/instance files.
102
loadData :: String -- ^ Node data in string format
103
         -> String -- ^ Instance data in string format
104
         -> IO (Result (Node.AssocList, Instance.AssocList))
105
loadData nfile ifile = do -- IO monad
106
  ndata <- readFile nfile
107
  idata <- readFile ifile
108
  return $ do
109
    {- node file: name t_mem n_mem f_mem t_disk f_disk -}
110
    (ktn, nl) <- loadTabular ndata loadNode
111
    {- instance file: name mem disk status pnode snode -}
112
    (_, il) <- loadTabular idata (loadInst ktn)
113
    return (nl, il)