Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Text.hs @ 497e30a1

History | View | Annotate | Download (3.1 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/gnt-instance list.
5

    
6
-}
7

    
8
module Ganeti.HTools.Text
9
    where
10

    
11
import Control.Monad
12

    
13
import Ganeti.HTools.Utils
14
import Ganeti.HTools.Loader
15
import Ganeti.HTools.Types
16
import qualified Ganeti.HTools.Node as Node
17
import qualified Ganeti.HTools.Instance as Instance
18

    
19
-- | Safe 'read' function returning data encapsulated in a Result
20
tryRead :: (Monad m, Read a) => String -> String -> m a
21
tryRead name s =
22
    let sols = readsPrec 0 s
23
    in case sols of
24
         (v, ""):[] -> return v
25
         (_, e):[] -> fail $ name ++ ": leftover characters when parsing '"
26
                      ++ s ++ "': '" ++ e ++ "'"
27
         _ -> fail $ name ++ ": cannot parse string '" ++ s ++ "'"
28

    
29
-- | Load a node from a field list
30
loadNode :: (Monad m) => [String] -> m (String, Node.Node)
31
loadNode (name:tm:nm:fm:td:fd:fo:[]) = do
32
  new_node <-
33
      if any (== "?") [tm,nm,fm,td,fd] || fo == "Y" then
34
          return $ Node.create name 0 0 0 0 0 True
35
      else do
36
        vtm <- tryRead name tm
37
        vnm <- tryRead name nm
38
        vfm <- tryRead name fm
39
        vtd <- tryRead name td
40
        vfd <- tryRead name fd
41
        return $ Node.create name vtm vnm vfm vtd vfd False
42
  return (name, new_node)
43
loadNode s = fail $ "Invalid/incomplete node data: '" ++ (show s) ++ "'"
44

    
45
-- | Load an instance from a field list
46
loadInst :: (Monad m) =>
47
            [(String, Int)] -> [String] -> m (String, Instance.Instance)
48
loadInst ktn (name:mem:dsk:status:pnode:snode:[]) = do
49
  pidx <- lookupNode ktn name pnode
50
  sidx <- (if null snode then return Node.noSecondary
51
           else lookupNode ktn name snode)
52
  vmem <- tryRead name mem
53
  vdsk <- tryRead name dsk
54
  when (sidx == pidx) $ fail $ "Instance " ++ name ++
55
           " has same primary and secondary node - " ++ pnode
56
  let newinst = Instance.create name vmem vdsk status pidx sidx
57
  return (name, newinst)
58
loadInst _ s = fail $ "Invalid/incomplete instance data: '" ++ (show s) ++ "'"
59

    
60
{- | Convert newline and delimiter-separated text.
61

    
62
This function converts a text in tabular format as generated by
63
@gnt-instance list@ and @gnt-node list@ to a list of objects using a
64
supplied conversion function.
65

    
66
-}
67
loadTabular :: (Monad m, Element a) =>
68
               String -> ([String] -> m (String, a))
69
            -> m ([(String, Int)], [(Int, a)])
70
loadTabular text_data convert_fn = do
71
  let lines_data = lines text_data
72
      rows = map (sepSplit '|') lines_data
73
  kerows <- mapM convert_fn rows
74
  return $ assignIndices kerows
75

    
76
loadData :: String -- ^ Node data in string format
77
         -> String -- ^ Instance data in string format
78
         -> IO (Result (NameAssoc, Node.AssocList,
79
                        NameAssoc, Instance.AssocList))
80
loadData nfile ifile = do -- IO monad
81
  ndata <- readFile nfile
82
  idata <- readFile ifile
83
  return $ do
84
    {- node file: name t_mem n_mem f_mem t_disk f_disk -}
85
    (ktn, nl) <- loadTabular ndata loadNode
86
    {- instance file: name mem disk status pnode snode -}
87
    (kti, il) <- loadTabular idata (loadInst ktn)
88
    return (ktn, nl, kti, il)