Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Luxi.hs @ 1c474f2b

History | View | Annotate | Download (11.8 kB)

1 a0090487 Agata Murawska
{-# LANGUAGE TemplateHaskell #-}
2 a0090487 Agata Murawska
3 6583e677 Iustin Pop
{-| Implementation of the Ganeti LUXI interface.
4 6583e677 Iustin Pop
5 6583e677 Iustin Pop
-}
6 6583e677 Iustin Pop
7 6583e677 Iustin Pop
{-
8 6583e677 Iustin Pop
9 71a4c605 Petr Pudlak
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
10 6583e677 Iustin Pop
11 6583e677 Iustin Pop
This program is free software; you can redistribute it and/or modify
12 6583e677 Iustin Pop
it under the terms of the GNU General Public License as published by
13 6583e677 Iustin Pop
the Free Software Foundation; either version 2 of the License, or
14 6583e677 Iustin Pop
(at your option) any later version.
15 6583e677 Iustin Pop
16 6583e677 Iustin Pop
This program is distributed in the hope that it will be useful, but
17 6583e677 Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
18 6583e677 Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 6583e677 Iustin Pop
General Public License for more details.
20 6583e677 Iustin Pop
21 6583e677 Iustin Pop
You should have received a copy of the GNU General Public License
22 6583e677 Iustin Pop
along with this program; if not, write to the Free Software
23 6583e677 Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 6583e677 Iustin Pop
02110-1301, USA.
25 6583e677 Iustin Pop
26 6583e677 Iustin Pop
-}
27 6583e677 Iustin Pop
28 6583e677 Iustin Pop
module Ganeti.Luxi
29 ebf38064 Iustin Pop
  ( LuxiOp(..)
30 95d0d502 Iustin Pop
  , LuxiReq(..)
31 ebf38064 Iustin Pop
  , Client
32 0fbc8447 Petr Pudlak
  , Server
33 ccc817a2 Iustin Pop
  , JobId
34 c48711d5 Iustin Pop
  , fromJobId
35 c48711d5 Iustin Pop
  , makeJobId
36 0aff2293 Iustin Pop
  , RecvResult(..)
37 0aff2293 Iustin Pop
  , strOfOp
38 d605e261 Petr Pudlak
  , getLuxiClient
39 d605e261 Petr Pudlak
  , getLuxiServer
40 13f2321c Iustin Pop
  , acceptClient
41 ebf38064 Iustin Pop
  , closeClient
42 0aff2293 Iustin Pop
  , closeServer
43 ebf38064 Iustin Pop
  , callMethod
44 ebf38064 Iustin Pop
  , submitManyJobs
45 ebf38064 Iustin Pop
  , queryJobsStatus
46 cdd495ae Iustin Pop
  , buildCall
47 0aff2293 Iustin Pop
  , buildResponse
48 d79a6502 Petr Pudlak
  , decodeLuxiCall
49 13f2321c Iustin Pop
  , recvMsg
50 0aff2293 Iustin Pop
  , recvMsgExt
51 13f2321c Iustin Pop
  , sendMsg
52 471b6c46 Iustin Pop
  , allLuxiCalls
53 ebf38064 Iustin Pop
  ) where
54 6583e677 Iustin Pop
55 ed7f7fd9 Petr Pudlak
import Control.Applicative (optional)
56 6583e677 Iustin Pop
import Control.Monad
57 71a4c605 Petr Pudlak
import qualified Data.ByteString.UTF8 as UTF8
58 0903280b Iustin Pop
import Text.JSON (encodeStrict, decodeStrict)
59 6583e677 Iustin Pop
import qualified Text.JSON as J
60 7adb7dff Iustin Pop
import Text.JSON.Pretty (pp_value)
61 6583e677 Iustin Pop
import Text.JSON.Types
62 6583e677 Iustin Pop
63 4cd79ca8 Iustin Pop
import Ganeti.BasicTypes
64 92678b3c Iustin Pop
import Ganeti.Constants
65 7adb7dff Iustin Pop
import Ganeti.Errors
66 7adb7dff Iustin Pop
import Ganeti.JSON
67 71a4c605 Petr Pudlak
import Ganeti.UDSServer
68 fa10983e Iustin Pop
import Ganeti.OpParams (pTagsObject)
69 367c4241 Dato Simó
import Ganeti.OpCodes
70 4cab6703 Iustin Pop
import qualified Ganeti.Query.Language as Qlang
71 0fbc8447 Petr Pudlak
import Ganeti.Runtime (GanetiDaemon(..))
72 a0090487 Agata Murawska
import Ganeti.THH
73 72375ff8 Petr Pudlak
import Ganeti.THH.Field
74 c48711d5 Iustin Pop
import Ganeti.Types
75 6583e677 Iustin Pop
76 0aff2293 Iustin Pop
77 a0090487 Agata Murawska
-- | Currently supported Luxi operations and JSON serialization.
78 a0090487 Agata Murawska
$(genLuxiOp "LuxiOp"
79 72295708 Iustin Pop
  [ (luxiReqQuery,
80 88609f00 Iustin Pop
    [ simpleField "what"    [t| Qlang.ItemType |]
81 88609f00 Iustin Pop
    , simpleField "fields"  [t| [String]  |]
82 88609f00 Iustin Pop
    , simpleField "qfilter" [t| Qlang.Filter Qlang.FilterField |]
83 ebf38064 Iustin Pop
    ])
84 72295708 Iustin Pop
  , (luxiReqQueryFields,
85 88609f00 Iustin Pop
    [ simpleField "what"    [t| Qlang.ItemType |]
86 88609f00 Iustin Pop
    , simpleField "fields"  [t| [String]  |]
87 72295708 Iustin Pop
    ])
88 fae980e5 Iustin Pop
  , (luxiReqQueryNodes,
89 88609f00 Iustin Pop
     [ simpleField "names"  [t| [String] |]
90 88609f00 Iustin Pop
     , simpleField "fields" [t| [String] |]
91 88609f00 Iustin Pop
     , simpleField "lock"   [t| Bool     |]
92 ebf38064 Iustin Pop
     ])
93 fae980e5 Iustin Pop
  , (luxiReqQueryGroups,
94 88609f00 Iustin Pop
     [ simpleField "names"  [t| [String] |]
95 88609f00 Iustin Pop
     , simpleField "fields" [t| [String] |]
96 88609f00 Iustin Pop
     , simpleField "lock"   [t| Bool     |]
97 ebf38064 Iustin Pop
     ])
98 795d035d Klaus Aehlig
  , (luxiReqQueryNetworks,
99 795d035d Klaus Aehlig
     [ simpleField "names"  [t| [String] |]
100 795d035d Klaus Aehlig
     , simpleField "fields" [t| [String] |]
101 795d035d Klaus Aehlig
     , simpleField "lock"   [t| Bool     |]
102 795d035d Klaus Aehlig
     ])
103 fae980e5 Iustin Pop
  , (luxiReqQueryInstances,
104 88609f00 Iustin Pop
     [ simpleField "names"  [t| [String] |]
105 88609f00 Iustin Pop
     , simpleField "fields" [t| [String] |]
106 88609f00 Iustin Pop
     , simpleField "lock"   [t| Bool     |]
107 ebf38064 Iustin Pop
     ])
108 fae980e5 Iustin Pop
  , (luxiReqQueryJobs,
109 c48711d5 Iustin Pop
     [ simpleField "ids"    [t| [JobId]  |]
110 88609f00 Iustin Pop
     , simpleField "fields" [t| [String] |]
111 ebf38064 Iustin Pop
     ])
112 fae980e5 Iustin Pop
  , (luxiReqQueryExports,
113 88609f00 Iustin Pop
     [ simpleField "nodes" [t| [String] |]
114 88609f00 Iustin Pop
     , simpleField "lock"  [t| Bool     |]
115 ebf38064 Iustin Pop
     ])
116 fae980e5 Iustin Pop
  , (luxiReqQueryConfigValues,
117 88609f00 Iustin Pop
     [ simpleField "fields" [t| [String] |] ]
118 ebf38064 Iustin Pop
    )
119 fae980e5 Iustin Pop
  , (luxiReqQueryClusterInfo, [])
120 fae980e5 Iustin Pop
  , (luxiReqQueryTags,
121 9131274c Jose A. Lopes
     [ pTagsObject
122 34af39e8 Jose A. Lopes
     , simpleField "name" [t| String |]
123 34af39e8 Jose A. Lopes
     ])
124 fae980e5 Iustin Pop
  , (luxiReqSubmitJob,
125 7e723913 Iustin Pop
     [ simpleField "job" [t| [MetaOpCode] |] ]
126 ebf38064 Iustin Pop
    )
127 346c3037 Klaus Aehlig
  , (luxiReqSubmitJobToDrainedQueue,
128 346c3037 Klaus Aehlig
     [ simpleField "job" [t| [MetaOpCode] |] ]
129 346c3037 Klaus Aehlig
    )
130 fae980e5 Iustin Pop
  , (luxiReqSubmitManyJobs,
131 7e723913 Iustin Pop
     [ simpleField "ops" [t| [[MetaOpCode]] |] ]
132 ebf38064 Iustin Pop
    )
133 fae980e5 Iustin Pop
  , (luxiReqWaitForJobChange,
134 c48711d5 Iustin Pop
     [ simpleField "job"      [t| JobId   |]
135 88609f00 Iustin Pop
     , simpleField "fields"   [t| [String]|]
136 88609f00 Iustin Pop
     , simpleField "prev_job" [t| JSValue |]
137 88609f00 Iustin Pop
     , simpleField "prev_log" [t| JSValue |]
138 88609f00 Iustin Pop
     , simpleField "tmout"    [t| Int     |]
139 ebf38064 Iustin Pop
     ])
140 d9d1e541 Klaus Aehlig
  , (luxiReqPickupJob,
141 d9d1e541 Klaus Aehlig
     [ simpleField "job" [t| JobId |] ]
142 d9d1e541 Klaus Aehlig
    )
143 fae980e5 Iustin Pop
  , (luxiReqArchiveJob,
144 c48711d5 Iustin Pop
     [ simpleField "job" [t| JobId |] ]
145 ebf38064 Iustin Pop
    )
146 fae980e5 Iustin Pop
  , (luxiReqAutoArchiveJobs,
147 88609f00 Iustin Pop
     [ simpleField "age"   [t| Int |]
148 88609f00 Iustin Pop
     , simpleField "tmout" [t| Int |]
149 ebf38064 Iustin Pop
     ])
150 fae980e5 Iustin Pop
  , (luxiReqCancelJob,
151 c48711d5 Iustin Pop
     [ simpleField "job" [t| JobId |] ]
152 ebf38064 Iustin Pop
    )
153 f63ffb37 Michael Hanselmann
  , (luxiReqChangeJobPriority,
154 c48711d5 Iustin Pop
     [ simpleField "job"      [t| JobId |]
155 f63ffb37 Michael Hanselmann
     , simpleField "priority" [t| Int |] ]
156 f63ffb37 Michael Hanselmann
    )
157 fae980e5 Iustin Pop
  , (luxiReqSetDrainFlag,
158 88609f00 Iustin Pop
     [ simpleField "flag" [t| Bool |] ]
159 ebf38064 Iustin Pop
    )
160 fae980e5 Iustin Pop
  , (luxiReqSetWatcherPause,
161 d819aba6 Klaus Aehlig
     [ optionalNullSerField
162 ed7f7fd9 Petr Pudlak
         $ timeAsDoubleField "duration" ]
163 ebf38064 Iustin Pop
    )
164 a0090487 Agata Murawska
  ])
165 6583e677 Iustin Pop
166 95d0d502 Iustin Pop
$(makeJSONInstance ''LuxiReq)
167 95d0d502 Iustin Pop
168 471b6c46 Iustin Pop
-- | List of all defined Luxi calls.
169 471b6c46 Iustin Pop
$(genAllConstr (drop 3) ''LuxiReq "allLuxiCalls")
170 471b6c46 Iustin Pop
171 6583e677 Iustin Pop
-- | The serialisation of LuxiOps into strings in messages.
172 a0090487 Agata Murawska
$(genStrOfOp ''LuxiOp "strOfOp")
173 6583e677 Iustin Pop
174 cdd495ae Iustin Pop
175 0fbc8447 Petr Pudlak
luxiConnectConfig :: ConnectConfig
176 0fbc8447 Petr Pudlak
luxiConnectConfig = ConnectConfig { connDaemon = GanetiLuxid
177 0fbc8447 Petr Pudlak
                                  , recvTmo    = luxiDefRwto
178 0fbc8447 Petr Pudlak
                                  , sendTmo    = luxiDefRwto
179 0fbc8447 Petr Pudlak
                                  }
180 0fbc8447 Petr Pudlak
181 0fbc8447 Petr Pudlak
-- | Connects to the master daemon and returns a luxi Client.
182 0fbc8447 Petr Pudlak
getLuxiClient :: String -> IO Client
183 0fbc8447 Petr Pudlak
getLuxiClient = connectClient luxiConnectConfig luxiDefCtmo
184 0fbc8447 Petr Pudlak
185 0fbc8447 Petr Pudlak
-- | Creates and returns a server endpoint.
186 0fbc8447 Petr Pudlak
getLuxiServer :: Bool -> FilePath -> IO Server
187 0fbc8447 Petr Pudlak
getLuxiServer = connectServer luxiConnectConfig
188 0fbc8447 Petr Pudlak
189 6583e677 Iustin Pop
-- | Serialize a request to String.
190 6583e677 Iustin Pop
buildCall :: LuxiOp  -- ^ The method
191 6583e677 Iustin Pop
          -> String  -- ^ The serialized form
192 683b1ca7 Iustin Pop
buildCall lo =
193 2cdaf225 Iustin Pop
  let ja = [ (strOfKey Method, J.showJSON $ strOfOp lo)
194 2cdaf225 Iustin Pop
           , (strOfKey Args, opToArgs lo)
195 ebf38064 Iustin Pop
           ]
196 ebf38064 Iustin Pop
      jo = toJSObject ja
197 ebf38064 Iustin Pop
  in encodeStrict jo
198 6583e677 Iustin Pop
199 cdd495ae Iustin Pop
200 cdd495ae Iustin Pop
-- | Converts Luxi call arguments into a 'LuxiOp' data structure.
201 d79a6502 Petr Pudlak
-- This is used for building a Luxi 'Handler'.
202 cdd495ae Iustin Pop
--
203 cdd495ae Iustin Pop
-- This is currently hand-coded until we make it more uniform so that
204 cdd495ae Iustin Pop
-- it can be generated using TH.
205 d79a6502 Petr Pudlak
decodeLuxiCall :: JSValue -> JSValue -> Result LuxiOp
206 d79a6502 Petr Pudlak
decodeLuxiCall method args = do
207 d79a6502 Petr Pudlak
  call <- fromJResult "Unable to parse LUXI request method" $ J.readJSON method
208 cdd495ae Iustin Pop
  case call of
209 cdd495ae Iustin Pop
    ReqQueryJobs -> do
210 c48711d5 Iustin Pop
              (jids, jargs) <- fromJVal args
211 d2970809 Iustin Pop
              jids' <- case jids of
212 d2970809 Iustin Pop
                         JSNull -> return []
213 d2970809 Iustin Pop
                         _ -> fromJVal jids
214 d2970809 Iustin Pop
              return $ QueryJobs jids' jargs
215 cdd495ae Iustin Pop
    ReqQueryInstances -> do
216 cdd495ae Iustin Pop
              (names, fields, locking) <- fromJVal args
217 cdd495ae Iustin Pop
              return $ QueryInstances names fields locking
218 cdd495ae Iustin Pop
    ReqQueryNodes -> do
219 cdd495ae Iustin Pop
              (names, fields, locking) <- fromJVal args
220 cdd495ae Iustin Pop
              return $ QueryNodes names fields locking
221 cdd495ae Iustin Pop
    ReqQueryGroups -> do
222 cdd495ae Iustin Pop
              (names, fields, locking) <- fromJVal args
223 cdd495ae Iustin Pop
              return $ QueryGroups names fields locking
224 5b11f8db Iustin Pop
    ReqQueryClusterInfo ->
225 cdd495ae Iustin Pop
              return QueryClusterInfo
226 795d035d Klaus Aehlig
    ReqQueryNetworks -> do
227 795d035d Klaus Aehlig
              (names, fields, locking) <- fromJVal args
228 795d035d Klaus Aehlig
              return $ QueryNetworks names fields locking
229 cdd495ae Iustin Pop
    ReqQuery -> do
230 9a94c848 Iustin Pop
              (what, fields, qfilter) <- fromJVal args
231 9a94c848 Iustin Pop
              return $ Query what fields qfilter
232 72295708 Iustin Pop
    ReqQueryFields -> do
233 72295708 Iustin Pop
              (what, fields) <- fromJVal args
234 72295708 Iustin Pop
              fields' <- case fields of
235 72295708 Iustin Pop
                           JSNull -> return []
236 72295708 Iustin Pop
                           _ -> fromJVal fields
237 72295708 Iustin Pop
              return $ QueryFields what fields'
238 cdd495ae Iustin Pop
    ReqSubmitJob -> do
239 cdd495ae Iustin Pop
              [ops1] <- fromJVal args
240 cdd495ae Iustin Pop
              ops2 <- mapM (fromJResult (luxiReqToRaw call) . J.readJSON) ops1
241 cdd495ae Iustin Pop
              return $ SubmitJob ops2
242 346c3037 Klaus Aehlig
    ReqSubmitJobToDrainedQueue -> do
243 346c3037 Klaus Aehlig
              [ops1] <- fromJVal args
244 346c3037 Klaus Aehlig
              ops2 <- mapM (fromJResult (luxiReqToRaw call) . J.readJSON) ops1
245 346c3037 Klaus Aehlig
              return $ SubmitJobToDrainedQueue ops2
246 cdd495ae Iustin Pop
    ReqSubmitManyJobs -> do
247 cdd495ae Iustin Pop
              [ops1] <- fromJVal args
248 cdd495ae Iustin Pop
              ops2 <- mapM (fromJResult (luxiReqToRaw call) . J.readJSON) ops1
249 cdd495ae Iustin Pop
              return $ SubmitManyJobs ops2
250 cdd495ae Iustin Pop
    ReqWaitForJobChange -> do
251 cdd495ae Iustin Pop
              (jid, fields, pinfo, pidx, wtmout) <-
252 cdd495ae Iustin Pop
                -- No instance for 5-tuple, code copied from the
253 cdd495ae Iustin Pop
                -- json sources and adapted
254 cdd495ae Iustin Pop
                fromJResult "Parsing WaitForJobChange message" $
255 cdd495ae Iustin Pop
                case args of
256 cdd495ae Iustin Pop
                  JSArray [a, b, c, d, e] ->
257 cdd495ae Iustin Pop
                    (,,,,) `fmap`
258 cdd495ae Iustin Pop
                    J.readJSON a `ap`
259 cdd495ae Iustin Pop
                    J.readJSON b `ap`
260 cdd495ae Iustin Pop
                    J.readJSON c `ap`
261 cdd495ae Iustin Pop
                    J.readJSON d `ap`
262 cdd495ae Iustin Pop
                    J.readJSON e
263 cdd495ae Iustin Pop
                  _ -> J.Error "Not enough values"
264 c48711d5 Iustin Pop
              return $ WaitForJobChange jid fields pinfo pidx wtmout
265 d9d1e541 Klaus Aehlig
    ReqPickupJob -> do
266 d9d1e541 Klaus Aehlig
              [jid] <- fromJVal args
267 d9d1e541 Klaus Aehlig
              return $ PickupJob jid
268 cdd495ae Iustin Pop
    ReqArchiveJob -> do
269 cdd495ae Iustin Pop
              [jid] <- fromJVal args
270 c48711d5 Iustin Pop
              return $ ArchiveJob jid
271 cdd495ae Iustin Pop
    ReqAutoArchiveJobs -> do
272 cdd495ae Iustin Pop
              (age, tmout) <- fromJVal args
273 cdd495ae Iustin Pop
              return $ AutoArchiveJobs age tmout
274 cdd495ae Iustin Pop
    ReqQueryExports -> do
275 cdd495ae Iustin Pop
              (nodes, lock) <- fromJVal args
276 cdd495ae Iustin Pop
              return $ QueryExports nodes lock
277 cdd495ae Iustin Pop
    ReqQueryConfigValues -> do
278 cdd495ae Iustin Pop
              [fields] <- fromJVal args
279 cdd495ae Iustin Pop
              return $ QueryConfigValues fields
280 cdd495ae Iustin Pop
    ReqQueryTags -> do
281 cdd495ae Iustin Pop
              (kind, name) <- fromJVal args
282 34af39e8 Jose A. Lopes
              return $ QueryTags kind name
283 cdd495ae Iustin Pop
    ReqCancelJob -> do
284 c48711d5 Iustin Pop
              [jid] <- fromJVal args
285 c48711d5 Iustin Pop
              return $ CancelJob jid
286 f63ffb37 Michael Hanselmann
    ReqChangeJobPriority -> do
287 c48711d5 Iustin Pop
              (jid, priority) <- fromJVal args
288 c48711d5 Iustin Pop
              return $ ChangeJobPriority jid priority
289 cdd495ae Iustin Pop
    ReqSetDrainFlag -> do
290 cdd495ae Iustin Pop
              [flag] <- fromJVal args
291 cdd495ae Iustin Pop
              return $ SetDrainFlag flag
292 cdd495ae Iustin Pop
    ReqSetWatcherPause -> do
293 ed7f7fd9 Petr Pudlak
              duration <- optional $ do
294 ed7f7fd9 Petr Pudlak
                [x] <- fromJVal args
295 ed7f7fd9 Petr Pudlak
                liftM unTimeAsDoubleJSON $ fromJVal x
296 cdd495ae Iustin Pop
              return $ SetWatcherPause duration
297 cdd495ae Iustin Pop
298 6583e677 Iustin Pop
-- | Check that luxi responses contain the required keys and that the
299 6583e677 Iustin Pop
-- call was successful.
300 7adb7dff Iustin Pop
validateResult :: String -> ErrorResult JSValue
301 6583e677 Iustin Pop
validateResult s = do
302 e821050d Iustin Pop
  when (UTF8.replacement_char `elem` s) $
303 e821050d Iustin Pop
       fail "Failed to decode UTF-8, detected replacement char after decoding"
304 7adb7dff Iustin Pop
  oarr <- fromJResult "Parsing LUXI response" (decodeStrict s)
305 262f3e6c Iustin Pop
  let arr = J.fromJSObject oarr
306 7adb7dff Iustin Pop
  status <- fromObj arr (strOfKey Success)
307 7adb7dff Iustin Pop
  result <- fromObj arr (strOfKey Result)
308 3603605a Iustin Pop
  if status
309 7adb7dff Iustin Pop
    then return result
310 7adb7dff Iustin Pop
    else decodeError result
311 7adb7dff Iustin Pop
312 7adb7dff Iustin Pop
-- | Try to decode an error from the server response. This function
313 7adb7dff Iustin Pop
-- will always fail, since it's called only on the error path (when
314 7adb7dff Iustin Pop
-- status is False).
315 7adb7dff Iustin Pop
decodeError :: JSValue -> ErrorResult JSValue
316 7adb7dff Iustin Pop
decodeError val =
317 7adb7dff Iustin Pop
  case fromJVal val of
318 7adb7dff Iustin Pop
    Ok e -> Bad e
319 7adb7dff Iustin Pop
    Bad msg -> Bad $ GenericError msg
320 6583e677 Iustin Pop
321 6583e677 Iustin Pop
-- | Generic luxi method call.
322 7adb7dff Iustin Pop
callMethod :: LuxiOp -> Client -> IO (ErrorResult JSValue)
323 683b1ca7 Iustin Pop
callMethod method s = do
324 683b1ca7 Iustin Pop
  sendMsg s $ buildCall method
325 6583e677 Iustin Pop
  result <- recvMsg s
326 6583e677 Iustin Pop
  let rval = validateResult result
327 6583e677 Iustin Pop
  return rval
328 9a2ff880 Iustin Pop
329 619e89c8 Iustin Pop
-- | Parse job submission result.
330 7adb7dff Iustin Pop
parseSubmitJobResult :: JSValue -> ErrorResult JobId
331 7adb7dff Iustin Pop
parseSubmitJobResult (JSArray [JSBool True, v]) =
332 c48711d5 Iustin Pop
  case J.readJSON v of
333 c48711d5 Iustin Pop
    J.Error msg -> Bad $ LuxiError msg
334 c48711d5 Iustin Pop
    J.Ok v' -> Ok v'
335 619e89c8 Iustin Pop
parseSubmitJobResult (JSArray [JSBool False, JSString x]) =
336 7adb7dff Iustin Pop
  Bad . LuxiError $ fromJSString x
337 7adb7dff Iustin Pop
parseSubmitJobResult v =
338 7adb7dff Iustin Pop
  Bad . LuxiError $ "Unknown result from the master daemon: " ++
339 7adb7dff Iustin Pop
      show (pp_value v)
340 619e89c8 Iustin Pop
341 9a2ff880 Iustin Pop
-- | Specialized submitManyJobs call.
342 7e723913 Iustin Pop
submitManyJobs :: Client -> [[MetaOpCode]] -> IO (ErrorResult [JobId])
343 9a2ff880 Iustin Pop
submitManyJobs s jobs = do
344 683b1ca7 Iustin Pop
  rval <- callMethod (SubmitManyJobs jobs) s
345 9a2ff880 Iustin Pop
  -- map each result (status, payload) pair into a nice Result ADT
346 9a2ff880 Iustin Pop
  return $ case rval of
347 9a2ff880 Iustin Pop
             Bad x -> Bad x
348 619e89c8 Iustin Pop
             Ok (JSArray r) -> mapM parseSubmitJobResult r
349 7adb7dff Iustin Pop
             x -> Bad . LuxiError $
350 7adb7dff Iustin Pop
                  "Cannot parse response from Ganeti: " ++ show x
351 9a2ff880 Iustin Pop
352 9a2ff880 Iustin Pop
-- | Custom queryJobs call.
353 7adb7dff Iustin Pop
queryJobsStatus :: Client -> [JobId] -> IO (ErrorResult [JobStatus])
354 9a2ff880 Iustin Pop
queryJobsStatus s jids = do
355 76b62028 Iustin Pop
  rval <- callMethod (QueryJobs jids ["status"]) s
356 9a2ff880 Iustin Pop
  return $ case rval of
357 9a2ff880 Iustin Pop
             Bad x -> Bad x
358 9a2ff880 Iustin Pop
             Ok y -> case J.readJSON y::(J.Result [[JobStatus]]) of
359 9a2ff880 Iustin Pop
                       J.Ok vals -> if any null vals
360 7adb7dff Iustin Pop
                                    then Bad $
361 7adb7dff Iustin Pop
                                         LuxiError "Missing job status field"
362 9a2ff880 Iustin Pop
                                    else Ok (map head vals)
363 7adb7dff Iustin Pop
                       J.Error x -> Bad $ LuxiError x