Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Text.hs @ 1a82215d

History | View | Annotate | Download (3.9 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:tc:fo:[]) = do
53
  new_node <-
54
      if any (== "?") [tm,nm,fm,td,fd,tc] || fo == "Y" then
55
          return $ Node.create name 0 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
        vtc <- tryRead name tc
63
        return $ Node.create name vtm vnm vfm vtd vfd vtc False
64
  return (name, new_node)
65
loadNode s = fail $ "Invalid/incomplete node data: '" ++ (show s) ++ "'"
66

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

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

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