Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Text.hs @ e2fa2baf

History | View | Annotate | Download (3.8 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
    where
31

    
32
import Control.Monad
33

    
34
import Ganeti.HTools.Utils
35
import Ganeti.HTools.Loader
36
import Ganeti.HTools.Types
37
import qualified Ganeti.HTools.Node as Node
38
import qualified Ganeti.HTools.Instance as Instance
39

    
40
-- | Safe 'read' function returning data encapsulated in a Result.
41
tryRead :: (Monad m, Read a) => String -> String -> m a
42
tryRead name s =
43
    let sols = readsPrec 0 s
44
    in case sols of
45
         (v, ""):[] -> return v
46
         (_, e):[] -> fail $ name ++ ": leftover characters when parsing '"
47
                      ++ s ++ "': '" ++ e ++ "'"
48
         _ -> fail $ name ++ ": cannot parse string '" ++ s ++ "'"
49

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

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

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

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