Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Text.hs @ d752eb39

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:vcpus: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
  vvcpus <- tryRead name vcpus
76
  when (sidx == pidx) $ fail $ "Instance " ++ name ++
77
           " has same primary and secondary node - " ++ pnode
78
  let newinst = Instance.create name vmem vdsk vvcpus status pidx sidx
79
  return (name, newinst)
80
loadInst _ s = fail $ "Invalid/incomplete instance data: '" ++ (show s) ++ "'"
81

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

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