Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Luxi.hs @ 6b20875c

History | View | Annotate | Download (5.3 kB)

1
{-| Implementation of the LUXI loader.
2

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 2009 Google Inc.
8

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

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

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

    
24
-}
25

    
26
module Ganeti.HTools.Luxi
27
    (
28
      loadData
29
    ) where
30

    
31
import Data.List
32
import qualified Control.Exception as E
33
import Control.Monad
34
import Text.JSON (JSValue, readJSON, JSON)
35
import qualified Text.JSON as J
36
import Text.JSON.Types
37

    
38
import qualified Ganeti.Luxi as L
39
import Ganeti.HTools.Loader
40
import Ganeti.HTools.Types
41
import qualified Ganeti.HTools.Node as Node
42
import qualified Ganeti.HTools.Instance as Instance
43

    
44
-- * Utility functions
45

    
46
-- | Small wrapper over readJSON.
47
fromJVal :: (Monad m, JSON a) => JSValue -> m a
48
fromJVal v =
49
    case readJSON v of
50
      J.Error s -> fail ("Cannot convert value " ++ show v ++ ", error: " ++ s)
51
      J.Ok x -> return x
52

    
53
-- | Ensure a given JSValue is actually a JSArray.
54
toArray :: (Monad m) => JSValue -> m [JSValue]
55
toArray v =
56
    case v of
57
      JSArray arr -> return arr
58
      o -> fail ("Invalid input, expected array but got " ++ show o)
59

    
60
-- * Data querying functionality
61

    
62
-- | The input data for node query.
63
queryNodesMsg :: JSValue
64
queryNodesMsg =
65
    let nnames = JSArray []
66
        fnames = ["name",
67
                  "mtotal", "mnode", "mfree",
68
                  "dtotal", "dfree",
69
                  "ctotal",
70
                  "offline", "drained"]
71
        fields = JSArray $ map (JSString . toJSString) fnames
72
        use_locking = JSBool False
73
    in JSArray [nnames, fields, use_locking]
74

    
75
-- | The input data for instance query.
76
queryInstancesMsg :: JSValue
77
queryInstancesMsg =
78
    let nnames = JSArray []
79
        fnames = ["name",
80
                  "disk_usage", "be/memory", "be/vcpus",
81
                  "status", "pnode", "snodes"]
82
        fields = JSArray $ map (JSString . toJSString) fnames
83
        use_locking = JSBool False
84
    in JSArray [nnames, fields, use_locking]
85

    
86
-- | Wraper over callMethod doing node query.
87
queryNodes :: L.Client -> IO (Result JSValue)
88
queryNodes = L.callMethod L.QueryNodes queryNodesMsg
89

    
90
-- | Wraper over callMethod doing instance query.
91
queryInstances :: L.Client -> IO (Result JSValue)
92
queryInstances = L.callMethod L.QueryInstances queryInstancesMsg
93

    
94
-- | Parse a instance list in JSON format.
95
getInstances :: NameAssoc
96
             -> JSValue
97
             -> Result [(String, Instance.Instance)]
98
getInstances ktn arr = toArray arr >>= mapM (parseInstance ktn)
99

    
100
-- | Construct an instance from a JSON object.
101
parseInstance :: [(String, Ndx)]
102
              -> JSValue
103
              -> Result (String, Instance.Instance)
104
parseInstance ktn (JSArray (name:disk:mem:vcpus:status:pnode:snodes:[])) = do
105
  xname <- fromJVal name
106
  xdisk <- fromJVal disk
107
  xmem <- fromJVal mem
108
  xvcpus <- fromJVal vcpus
109
  xpnode <- fromJVal pnode >>= lookupNode ktn xname
110
  xsnodes <- fromJVal snodes::Result [JSString]
111
  snode <- (if null xsnodes then return Node.noSecondary
112
            else lookupNode ktn xname (fromJSString $ head xsnodes))
113
  xrunning <- fromJVal status
114
  let inst = Instance.create xname xmem xdisk xvcpus xrunning xpnode snode
115
  return (xname, inst)
116

    
117
parseInstance _ v = fail ("Invalid instance query result: " ++ show v)
118

    
119
-- | Parse a node list in JSON format.
120
getNodes :: JSValue -> Result [(String, Node.Node)]
121
getNodes arr = toArray arr >>= mapM parseNode
122

    
123
-- | Construct a node from a JSON object.
124
parseNode :: JSValue -> Result (String, Node.Node)
125
parseNode (JSArray
126
           (name:mtotal:mnode:mfree:dtotal:dfree:ctotal:offline:drained:[]))
127
    = do
128
  xname <- fromJVal name
129
  xoffline <- fromJVal offline
130
  node <- (if xoffline
131
           then return $ Node.create xname 0 0 0 0 0 0 True
132
           else do
133
             xdrained <- fromJVal drained
134
             xmtotal  <- fromJVal mtotal
135
             xmnode   <- fromJVal mnode
136
             xmfree   <- fromJVal mfree
137
             xdtotal  <- fromJVal dtotal
138
             xdfree   <- fromJVal dfree
139
             xctotal  <- fromJVal ctotal
140
             return $ Node.create xname xmtotal xmnode xmfree
141
                    xdtotal xdfree xctotal (xoffline || xdrained))
142
  return (xname, node)
143

    
144
parseNode v = fail ("Invalid node query result: " ++ show v)
145

    
146
-- * Main loader functionality
147

    
148
-- | Builds the cluster data from an URL.
149
loadData :: String -- ^ Unix socket to use as source
150
         -> IO (Result (Node.AssocList, Instance.AssocList))
151
loadData master =
152
  E.bracket
153
       (L.getClient master)
154
       L.closeClient
155
       (\s -> do
156
          nodes <- queryNodes s
157
          instances <- queryInstances s
158
          return $ do -- Result monad
159
            node_data <- nodes >>= getNodes
160
            let (node_names, node_idx) = assignIndices node_data
161
            inst_data <- instances >>= getInstances node_names
162
            let (_, inst_idx) = assignIndices inst_data
163
            return (node_idx, inst_idx)
164
       )