Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / HTools / Luxi.hs @ 8353b5e1

History | View | Annotate | Download (8.3 kB)

1 6583e677 Iustin Pop
{-| Implementation of the LUXI loader.
2 53ec9022 Iustin Pop
3 53ec9022 Iustin Pop
-}
4 53ec9022 Iustin Pop
5 53ec9022 Iustin Pop
{-
6 53ec9022 Iustin Pop
7 39420403 Iustin Pop
Copyright (C) 2009, 2010, 2011 Google Inc.
8 53ec9022 Iustin Pop
9 53ec9022 Iustin Pop
This program is free software; you can redistribute it and/or modify
10 53ec9022 Iustin Pop
it under the terms of the GNU General Public License as published by
11 53ec9022 Iustin Pop
the Free Software Foundation; either version 2 of the License, or
12 53ec9022 Iustin Pop
(at your option) any later version.
13 53ec9022 Iustin Pop
14 53ec9022 Iustin Pop
This program is distributed in the hope that it will be useful, but
15 53ec9022 Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
16 53ec9022 Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 53ec9022 Iustin Pop
General Public License for more details.
18 53ec9022 Iustin Pop
19 53ec9022 Iustin Pop
You should have received a copy of the GNU General Public License
20 53ec9022 Iustin Pop
along with this program; if not, write to the Free Software
21 53ec9022 Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 53ec9022 Iustin Pop
02110-1301, USA.
23 53ec9022 Iustin Pop
24 53ec9022 Iustin Pop
-}
25 53ec9022 Iustin Pop
26 53ec9022 Iustin Pop
module Ganeti.HTools.Luxi
27 53ec9022 Iustin Pop
    (
28 53ec9022 Iustin Pop
      loadData
29 b3f0710c Iustin Pop
    , parseData
30 53ec9022 Iustin Pop
    ) where
31 53ec9022 Iustin Pop
32 53ec9022 Iustin Pop
import qualified Control.Exception as E
33 53ec9022 Iustin Pop
import Text.JSON.Types
34 39420403 Iustin Pop
import qualified Text.JSON
35 53ec9022 Iustin Pop
36 6583e677 Iustin Pop
import qualified Ganeti.Luxi as L
37 53ec9022 Iustin Pop
import Ganeti.HTools.Loader
38 53ec9022 Iustin Pop
import Ganeti.HTools.Types
39 a679e9dc Iustin Pop
import qualified Ganeti.HTools.Group as Group
40 53ec9022 Iustin Pop
import qualified Ganeti.HTools.Node as Node
41 53ec9022 Iustin Pop
import qualified Ganeti.HTools.Instance as Instance
42 f5ed8632 Iustin Pop
import Ganeti.HTools.Utils (fromJVal, annotateResult, tryFromObj, asJSObject)
43 53ec9022 Iustin Pop
44 53ec9022 Iustin Pop
-- * Utility functions
45 53ec9022 Iustin Pop
46 53ec9022 Iustin Pop
-- | Ensure a given JSValue is actually a JSArray.
47 53ec9022 Iustin Pop
toArray :: (Monad m) => JSValue -> m [JSValue]
48 53ec9022 Iustin Pop
toArray v =
49 53ec9022 Iustin Pop
    case v of
50 53ec9022 Iustin Pop
      JSArray arr -> return arr
51 53ec9022 Iustin Pop
      o -> fail ("Invalid input, expected array but got " ++ show o)
52 53ec9022 Iustin Pop
53 39420403 Iustin Pop
-- | Annotate errors when converting values with owner/attribute for
54 39420403 Iustin Pop
-- better debugging.
55 39420403 Iustin Pop
genericConvert :: (Text.JSON.JSON a) =>
56 39420403 Iustin Pop
                  String     -- ^ The object type
57 39420403 Iustin Pop
               -> String     -- ^ The object name
58 39420403 Iustin Pop
               -> String     -- ^ The attribute we're trying to convert
59 39420403 Iustin Pop
               -> JSValue    -- ^ The value we try to convert
60 39420403 Iustin Pop
               -> Result a   -- ^ The annotated result
61 39420403 Iustin Pop
genericConvert otype oname oattr =
62 6a062ff9 Iustin Pop
    annotateResult (otype ++ " '" ++ oname ++
63 6a062ff9 Iustin Pop
                    "', error while reading attribute '" ++
64 39420403 Iustin Pop
                    oattr ++ "'") . fromJVal
65 39420403 Iustin Pop
66 53ec9022 Iustin Pop
-- * Data querying functionality
67 53ec9022 Iustin Pop
68 53ec9022 Iustin Pop
-- | The input data for node query.
69 683b1ca7 Iustin Pop
queryNodesMsg :: L.LuxiOp
70 53ec9022 Iustin Pop
queryNodesMsg =
71 683b1ca7 Iustin Pop
  L.QueryNodes [] ["name", "mtotal", "mnode", "mfree", "dtotal", "dfree",
72 f5ed8632 Iustin Pop
                   "ctotal", "offline", "drained", "vm_capable",
73 f5ed8632 Iustin Pop
                   "group.uuid"] False
74 53ec9022 Iustin Pop
75 53ec9022 Iustin Pop
-- | The input data for instance query.
76 683b1ca7 Iustin Pop
queryInstancesMsg :: L.LuxiOp
77 53ec9022 Iustin Pop
queryInstancesMsg =
78 683b1ca7 Iustin Pop
  L.QueryInstances [] ["name", "disk_usage", "be/memory", "be/vcpus",
79 6880526c Iustin Pop
                       "status", "pnode", "snodes", "tags", "oper_ram",
80 b3c5e8de Iustin Pop
                       "be/auto_balance", "disk_template"] False
81 53ec9022 Iustin Pop
82 a679e9dc Iustin Pop
-- | The input data for cluster query.
83 683b1ca7 Iustin Pop
queryClusterInfoMsg :: L.LuxiOp
84 683b1ca7 Iustin Pop
queryClusterInfoMsg = L.QueryClusterInfo
85 f89235f1 Iustin Pop
86 a679e9dc Iustin Pop
-- | The input data for node group query.
87 a679e9dc Iustin Pop
queryGroupsMsg :: L.LuxiOp
88 a679e9dc Iustin Pop
queryGroupsMsg =
89 c4c37257 Iustin Pop
  L.QueryGroups [] ["uuid", "name", "alloc_policy"] False
90 a679e9dc Iustin Pop
91 179c0828 Iustin Pop
-- | Wraper over 'callMethod' doing node query.
92 6583e677 Iustin Pop
queryNodes :: L.Client -> IO (Result JSValue)
93 683b1ca7 Iustin Pop
queryNodes = L.callMethod queryNodesMsg
94 53ec9022 Iustin Pop
95 179c0828 Iustin Pop
-- | Wraper over 'callMethod' doing instance query.
96 6583e677 Iustin Pop
queryInstances :: L.Client -> IO (Result JSValue)
97 683b1ca7 Iustin Pop
queryInstances = L.callMethod queryInstancesMsg
98 53ec9022 Iustin Pop
99 179c0828 Iustin Pop
-- | Wrapper over 'callMethod' doing cluster information query.
100 f89235f1 Iustin Pop
queryClusterInfo :: L.Client -> IO (Result JSValue)
101 683b1ca7 Iustin Pop
queryClusterInfo = L.callMethod queryClusterInfoMsg
102 f89235f1 Iustin Pop
103 a679e9dc Iustin Pop
-- | Wrapper over callMethod doing group query.
104 a679e9dc Iustin Pop
queryGroups :: L.Client -> IO (Result JSValue)
105 a679e9dc Iustin Pop
queryGroups = L.callMethod queryGroupsMsg
106 a679e9dc Iustin Pop
107 53ec9022 Iustin Pop
-- | Parse a instance list in JSON format.
108 53ec9022 Iustin Pop
getInstances :: NameAssoc
109 53ec9022 Iustin Pop
             -> JSValue
110 53ec9022 Iustin Pop
             -> Result [(String, Instance.Instance)]
111 53ec9022 Iustin Pop
getInstances ktn arr = toArray arr >>= mapM (parseInstance ktn)
112 53ec9022 Iustin Pop
113 53ec9022 Iustin Pop
-- | Construct an instance from a JSON object.
114 6ff78049 Iustin Pop
parseInstance :: NameAssoc
115 53ec9022 Iustin Pop
              -> JSValue
116 53ec9022 Iustin Pop
              -> Result (String, Instance.Instance)
117 27671a61 Iustin Pop
parseInstance ktn (JSArray [ name, disk, mem, vcpus
118 6880526c Iustin Pop
                           , status, pnode, snodes, tags, oram
119 b3c5e8de Iustin Pop
                           , auto_balance, disk_template ]) = do
120 117dc2d8 Iustin Pop
  xname <- annotateResult "Parsing new instance" (fromJVal name)
121 39420403 Iustin Pop
  let convert a = genericConvert "Instance" xname a
122 39420403 Iustin Pop
  xdisk <- convert "disk_usage" disk
123 6402a260 Iustin Pop
  xmem <- (case oram of
124 39420403 Iustin Pop
             JSRational _ _ -> convert "oper_ram" oram
125 39420403 Iustin Pop
             _ -> convert "be/memory" mem)
126 39420403 Iustin Pop
  xvcpus <- convert "be/vcpus" vcpus
127 39420403 Iustin Pop
  xpnode <- convert "pnode" pnode >>= lookupNode ktn xname
128 39420403 Iustin Pop
  xsnodes <- convert "snodes" snodes::Result [JSString]
129 53ec9022 Iustin Pop
  snode <- (if null xsnodes then return Node.noSecondary
130 53ec9022 Iustin Pop
            else lookupNode ktn xname (fromJSString $ head xsnodes))
131 39420403 Iustin Pop
  xrunning <- convert "status" status
132 39420403 Iustin Pop
  xtags <- convert "tags" tags
133 6880526c Iustin Pop
  xauto_balance <- convert "auto_balance" auto_balance
134 b3c5e8de Iustin Pop
  xdt <- convert "disk_template" disk_template
135 17e7af2b Iustin Pop
  let inst = Instance.create xname xmem xdisk xvcpus
136 b3c5e8de Iustin Pop
             xrunning xtags xauto_balance xpnode snode xdt
137 53ec9022 Iustin Pop
  return (xname, inst)
138 53ec9022 Iustin Pop
139 53ec9022 Iustin Pop
parseInstance _ v = fail ("Invalid instance query result: " ++ show v)
140 53ec9022 Iustin Pop
141 53ec9022 Iustin Pop
-- | Parse a node list in JSON format.
142 10ef6b4e Iustin Pop
getNodes :: NameAssoc -> JSValue -> Result [(String, Node.Node)]
143 10ef6b4e Iustin Pop
getNodes ktg arr = toArray arr >>= mapM (parseNode ktg)
144 53ec9022 Iustin Pop
145 53ec9022 Iustin Pop
-- | Construct a node from a JSON object.
146 10ef6b4e Iustin Pop
parseNode :: NameAssoc -> JSValue -> Result (String, Node.Node)
147 10ef6b4e Iustin Pop
parseNode ktg (JSArray [ name, mtotal, mnode, mfree, dtotal, dfree
148 10ef6b4e Iustin Pop
                       , ctotal, offline, drained, vm_capable, g_uuid ])
149 53ec9022 Iustin Pop
    = do
150 117dc2d8 Iustin Pop
  xname <- annotateResult "Parsing new node" (fromJVal name)
151 39420403 Iustin Pop
  let convert a = genericConvert "Node" xname a
152 39420403 Iustin Pop
  xoffline <- convert "offline" offline
153 39420403 Iustin Pop
  xdrained <- convert "drained" drained
154 39420403 Iustin Pop
  xvm_capable <- convert "vm_capable" vm_capable
155 39420403 Iustin Pop
  xgdx   <- convert "group.uuid" g_uuid >>= lookupGroup ktg xname
156 9d775204 Iustin Pop
  node <- (if xoffline || xdrained || not xvm_capable
157 10ef6b4e Iustin Pop
           then return $ Node.create xname 0 0 0 0 0 0 True xgdx
158 53ec9022 Iustin Pop
           else do
159 39420403 Iustin Pop
             xmtotal  <- convert "mtotal" mtotal
160 39420403 Iustin Pop
             xmnode   <- convert "mnode" mnode
161 39420403 Iustin Pop
             xmfree   <- convert "mfree" mfree
162 39420403 Iustin Pop
             xdtotal  <- convert "dtotal" dtotal
163 39420403 Iustin Pop
             xdfree   <- convert "dfree" dfree
164 39420403 Iustin Pop
             xctotal  <- convert "ctotal" ctotal
165 53ec9022 Iustin Pop
             return $ Node.create xname xmtotal xmnode xmfree
166 10ef6b4e Iustin Pop
                    xdtotal xdfree xctotal False xgdx)
167 53ec9022 Iustin Pop
  return (xname, node)
168 53ec9022 Iustin Pop
169 10ef6b4e Iustin Pop
parseNode _ v = fail ("Invalid node query result: " ++ show v)
170 53ec9022 Iustin Pop
171 179c0828 Iustin Pop
-- | Parses the cluster tags.
172 f89235f1 Iustin Pop
getClusterTags :: JSValue -> Result [String]
173 f89235f1 Iustin Pop
getClusterTags v = do
174 f89235f1 Iustin Pop
  let errmsg = "Parsing cluster info"
175 f89235f1 Iustin Pop
  obj <- annotateResult errmsg $ asJSObject v
176 5182e970 Iustin Pop
  tryFromObj errmsg (fromJSObject obj) "tags"
177 f89235f1 Iustin Pop
178 179c0828 Iustin Pop
-- | Parses the cluster groups.
179 a679e9dc Iustin Pop
getGroups :: JSValue -> Result [(String, Group.Group)]
180 a679e9dc Iustin Pop
getGroups arr = toArray arr >>= mapM parseGroup
181 a679e9dc Iustin Pop
182 179c0828 Iustin Pop
-- | Parses a given group information.
183 a679e9dc Iustin Pop
parseGroup :: JSValue -> Result (String, Group.Group)
184 c4c37257 Iustin Pop
parseGroup (JSArray [ uuid, name, apol ]) = do
185 a679e9dc Iustin Pop
  xname <- annotateResult "Parsing new group" (fromJVal name)
186 39420403 Iustin Pop
  let convert a = genericConvert "Group" xname a
187 39420403 Iustin Pop
  xuuid <- convert "uuid" uuid
188 39420403 Iustin Pop
  xapol <- convert "alloc_policy" apol
189 d5072e4c Iustin Pop
  return (xuuid, Group.create xname xuuid xapol)
190 a679e9dc Iustin Pop
191 a679e9dc Iustin Pop
parseGroup v = fail ("Invalid group query result: " ++ show v)
192 a679e9dc Iustin Pop
193 53ec9022 Iustin Pop
-- * Main loader functionality
194 53ec9022 Iustin Pop
195 525bfb36 Iustin Pop
-- | Builds the cluster data by querying a given socket name.
196 b3f0710c Iustin Pop
readData :: String -- ^ Unix socket to use as source
197 a679e9dc Iustin Pop
         -> IO (Result JSValue, Result JSValue, Result JSValue, Result JSValue)
198 b3f0710c Iustin Pop
readData master =
199 53ec9022 Iustin Pop
  E.bracket
200 6583e677 Iustin Pop
       (L.getClient master)
201 6583e677 Iustin Pop
       L.closeClient
202 53ec9022 Iustin Pop
       (\s -> do
203 53ec9022 Iustin Pop
          nodes <- queryNodes s
204 53ec9022 Iustin Pop
          instances <- queryInstances s
205 f89235f1 Iustin Pop
          cinfo <- queryClusterInfo s
206 a679e9dc Iustin Pop
          groups <- queryGroups s
207 a679e9dc Iustin Pop
          return (groups, nodes, instances, cinfo)
208 53ec9022 Iustin Pop
       )
209 b3f0710c Iustin Pop
210 525bfb36 Iustin Pop
-- | Converts the output of 'readData' into the internal cluster
211 525bfb36 Iustin Pop
-- representation.
212 a679e9dc Iustin Pop
parseData :: (Result JSValue, Result JSValue, Result JSValue, Result JSValue)
213 f4f6eb0b Iustin Pop
          -> Result ClusterData
214 a679e9dc Iustin Pop
parseData (groups, nodes, instances, cinfo) = do
215 a679e9dc Iustin Pop
  group_data <- groups >>= getGroups
216 10ef6b4e Iustin Pop
  let (group_names, group_idx) = assignIndices group_data
217 10ef6b4e Iustin Pop
  node_data <- nodes >>= getNodes group_names
218 b3f0710c Iustin Pop
  let (node_names, node_idx) = assignIndices node_data
219 b3f0710c Iustin Pop
  inst_data <- instances >>= getInstances node_names
220 b3f0710c Iustin Pop
  let (_, inst_idx) = assignIndices inst_data
221 b3f0710c Iustin Pop
  ctags <- cinfo >>= getClusterTags
222 f4f6eb0b Iustin Pop
  return (ClusterData group_idx node_idx inst_idx ctags)
223 b3f0710c Iustin Pop
224 525bfb36 Iustin Pop
-- | Top level function for data loading.
225 b3f0710c Iustin Pop
loadData :: String -- ^ Unix socket to use as source
226 f4f6eb0b Iustin Pop
         -> IO (Result ClusterData)
227 2a8e2dc9 Iustin Pop
loadData = fmap parseData . readData