Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Rpc.hs @ 8920fa09

History | View | Annotate | Download (15.3 kB)

1 1ca709c1 Iustin Pop
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies,
2 96dad12d Agata Murawska
  BangPatterns, TemplateHaskell #-}
3 d4709cce Agata Murawska
4 d4709cce Agata Murawska
{-| Implementation of the RPC client.
5 d4709cce Agata Murawska
6 d4709cce Agata Murawska
-}
7 d4709cce Agata Murawska
8 d4709cce Agata Murawska
{-
9 d4709cce Agata Murawska
10 1ca709c1 Iustin Pop
Copyright (C) 2012, 2013 Google Inc.
11 d4709cce Agata Murawska
12 d4709cce Agata Murawska
This program is free software; you can redistribute it and/or modify
13 d4709cce Agata Murawska
it under the terms of the GNU General Public License as published by
14 d4709cce Agata Murawska
the Free Software Foundation; either version 2 of the License, or
15 d4709cce Agata Murawska
(at your option) any later version.
16 d4709cce Agata Murawska
17 d4709cce Agata Murawska
This program is distributed in the hope that it will be useful, but
18 d4709cce Agata Murawska
WITHOUT ANY WARRANTY; without even the implied warranty of
19 d4709cce Agata Murawska
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 d4709cce Agata Murawska
General Public License for more details.
21 d4709cce Agata Murawska
22 d4709cce Agata Murawska
You should have received a copy of the GNU General Public License
23 d4709cce Agata Murawska
along with this program; if not, write to the Free Software
24 d4709cce Agata Murawska
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 d4709cce Agata Murawska
02110-1301, USA.
26 d4709cce Agata Murawska
27 d4709cce Agata Murawska
-}
28 d4709cce Agata Murawska
29 d4709cce Agata Murawska
module Ganeti.Rpc
30 d4709cce Agata Murawska
  ( RpcCall
31 d4709cce Agata Murawska
  , Rpc
32 d4709cce Agata Murawska
  , RpcError(..)
33 599239ad Agata Murawska
  , ERpcError
34 60443f61 Agata Murawska
  , explainRpcError
35 eaed5f19 Agata Murawska
  , executeRpcCall
36 d4709cce Agata Murawska
37 d4709cce Agata Murawska
  , rpcCallName
38 d4709cce Agata Murawska
  , rpcCallTimeout
39 d4709cce Agata Murawska
  , rpcCallData
40 d4709cce Agata Murawska
  , rpcCallAcceptOffline
41 d4709cce Agata Murawska
42 d4709cce Agata Murawska
  , rpcResultFill
43 96dad12d Agata Murawska
44 96dad12d Agata Murawska
  , InstanceInfo(..)
45 5188fdb7 Agata Murawska
  , RpcCallInstanceInfo(..)
46 5188fdb7 Agata Murawska
  , RpcResultInstanceInfo(..)
47 5188fdb7 Agata Murawska
48 96dad12d Agata Murawska
  , RpcCallAllInstancesInfo(..)
49 96dad12d Agata Murawska
  , RpcResultAllInstancesInfo(..)
50 96dad12d Agata Murawska
51 c1c5aab1 Agata Murawska
  , RpcCallInstanceList(..)
52 c1c5aab1 Agata Murawska
  , RpcResultInstanceList(..)
53 c1c5aab1 Agata Murawska
54 dc623a95 Agata Murawska
  , HvInfo(..)
55 dc623a95 Agata Murawska
  , VgInfo(..)
56 dc623a95 Agata Murawska
  , RpcCallNodeInfo(..)
57 dc623a95 Agata Murawska
  , RpcResultNodeInfo(..)
58 dc623a95 Agata Murawska
59 8779d21a Agata Murawska
  , RpcCallVersion(..)
60 8779d21a Agata Murawska
  , RpcResultVersion(..)
61 8779d21a Agata Murawska
62 47163f0f Agata Murawska
  , StorageField(..)
63 47163f0f Agata Murawska
  , RpcCallStorageList(..)
64 47163f0f Agata Murawska
  , RpcResultStorageList(..)
65 47163f0f Agata Murawska
66 de2a5704 Iustin Pop
  , RpcCallTestDelay(..)
67 de2a5704 Iustin Pop
  , RpcResultTestDelay(..)
68 de2a5704 Iustin Pop
69 96dad12d Agata Murawska
  , rpcTimeoutFromRaw -- FIXME: Not used anywhere
70 d4709cce Agata Murawska
  ) where
71 d4709cce Agata Murawska
72 9b09c0be Agata Murawska
import Control.Arrow (second)
73 319322a7 Bernardo Dal Seno
import qualified Data.Map as Map
74 319322a7 Bernardo Dal Seno
import Data.Maybe (fromMaybe)
75 d4709cce Agata Murawska
import qualified Text.JSON as J
76 9b09c0be Agata Murawska
import Text.JSON.Pretty (pp_value)
77 d4709cce Agata Murawska
78 eaed5f19 Agata Murawska
import Network.Curl
79 7766de33 Agata Murawska
import qualified Ganeti.Path as P
80 eaed5f19 Agata Murawska
81 8920fa09 Iustin Pop
import Ganeti.BasicTypes
82 eaed5f19 Agata Murawska
import qualified Ganeti.Constants as C
83 d4709cce Agata Murawska
import Ganeti.Objects
84 96dad12d Agata Murawska
import Ganeti.THH
85 22381768 Iustin Pop
import Ganeti.Types
86 8920fa09 Iustin Pop
import Ganeti.Curl.Multi
87 8920fa09 Iustin Pop
import Ganeti.Utils
88 eaed5f19 Agata Murawska
89 de2a5704 Iustin Pop
-- * Base RPC functionality and types
90 de2a5704 Iustin Pop
91 eaed5f19 Agata Murawska
-- | The curl options used for RPC.
92 eaed5f19 Agata Murawska
curlOpts :: [CurlOption]
93 eaed5f19 Agata Murawska
curlOpts = [ CurlFollowLocation False
94 eaed5f19 Agata Murawska
           , CurlSSLVerifyHost 0
95 eaed5f19 Agata Murawska
           , CurlSSLVerifyPeer True
96 eaed5f19 Agata Murawska
           , CurlSSLCertType "PEM"
97 eaed5f19 Agata Murawska
           , CurlSSLKeyType "PEM"
98 eaed5f19 Agata Murawska
           , CurlConnectTimeout (fromIntegral C.rpcConnectTimeout)
99 eaed5f19 Agata Murawska
           ]
100 d4709cce Agata Murawska
101 d4709cce Agata Murawska
-- | Data type for RPC error reporting.
102 d4709cce Agata Murawska
data RpcError
103 9c0a27d0 Iustin Pop
  = CurlLayerError String
104 d4709cce Agata Murawska
  | JsonDecodeError String
105 6fddde87 Agata Murawska
  | RpcResultError String
106 9c0a27d0 Iustin Pop
  | OfflineNodeError
107 60443f61 Agata Murawska
  deriving (Show, Eq)
108 d4709cce Agata Murawska
109 60443f61 Agata Murawska
-- | Provide explanation to RPC errors.
110 60443f61 Agata Murawska
explainRpcError :: RpcError -> String
111 9c0a27d0 Iustin Pop
explainRpcError (CurlLayerError code) =
112 9c0a27d0 Iustin Pop
    "Curl error:" ++ code
113 60443f61 Agata Murawska
explainRpcError (JsonDecodeError msg) =
114 6fddde87 Agata Murawska
    "Error while decoding JSON from HTTP response: " ++ msg
115 60443f61 Agata Murawska
explainRpcError (RpcResultError msg) =
116 6fddde87 Agata Murawska
    "Error reponse received from RPC server: " ++ msg
117 9c0a27d0 Iustin Pop
explainRpcError OfflineNodeError =
118 9c0a27d0 Iustin Pop
    "Node is marked offline"
119 d4709cce Agata Murawska
120 599239ad Agata Murawska
type ERpcError = Either RpcError
121 599239ad Agata Murawska
122 96dad12d Agata Murawska
-- | Basic timeouts for RPC calls.
123 96dad12d Agata Murawska
$(declareIADT "RpcTimeout"
124 96dad12d Agata Murawska
  [ ( "Urgent",    'C.rpcTmoUrgent )
125 96dad12d Agata Murawska
  , ( "Fast",      'C.rpcTmoFast )
126 96dad12d Agata Murawska
  , ( "Normal",    'C.rpcTmoNormal )
127 96dad12d Agata Murawska
  , ( "Slow",      'C.rpcTmoSlow )
128 96dad12d Agata Murawska
  , ( "FourHours", 'C.rpcTmo4hrs )
129 96dad12d Agata Murawska
  , ( "OneDay",    'C.rpcTmo1day )
130 96dad12d Agata Murawska
  ])
131 96dad12d Agata Murawska
132 d4709cce Agata Murawska
-- | A generic class for RPC calls.
133 d4709cce Agata Murawska
class (J.JSON a) => RpcCall a where
134 d4709cce Agata Murawska
  -- | Give the (Python) name of the procedure.
135 d4709cce Agata Murawska
  rpcCallName :: a -> String
136 d4709cce Agata Murawska
  -- | Calculate the timeout value for the call execution.
137 d4709cce Agata Murawska
  rpcCallTimeout :: a -> Int
138 d4709cce Agata Murawska
  -- | Prepare arguments of the call to be send as POST.
139 d4709cce Agata Murawska
  rpcCallData :: Node -> a -> String
140 d4709cce Agata Murawska
  -- | Whether we accept offline nodes when making a call.
141 d4709cce Agata Murawska
  rpcCallAcceptOffline :: a -> Bool
142 d4709cce Agata Murawska
143 d4709cce Agata Murawska
-- | Generic class that ensures matching RPC call with its respective
144 d4709cce Agata Murawska
-- result.
145 47163f0f Agata Murawska
class (RpcCall a, J.JSON b) => Rpc a b  | a -> b, b -> a where
146 47163f0f Agata Murawska
  -- | Create a result based on the received HTTP response.
147 a93b711b Agata Murawska
  rpcResultFill :: a -> J.JSValue -> ERpcError b
148 eaed5f19 Agata Murawska
149 eaed5f19 Agata Murawska
-- | Http Request definition.
150 eaed5f19 Agata Murawska
data HttpClientRequest = HttpClientRequest
151 85f6a869 Iustin Pop
  { requestUrl  :: String       -- ^ The actual URL for the node endpoint
152 85f6a869 Iustin Pop
  , requestData :: String       -- ^ The arguments for the call
153 85f6a869 Iustin Pop
  , requestOpts :: [CurlOption] -- ^ The various curl options
154 eaed5f19 Agata Murawska
  }
155 eaed5f19 Agata Murawska
156 eaed5f19 Agata Murawska
-- | Prepare url for the HTTP request.
157 eaed5f19 Agata Murawska
prepareUrl :: (RpcCall a) => Node -> a -> String
158 eaed5f19 Agata Murawska
prepareUrl node call =
159 eaed5f19 Agata Murawska
  let node_ip = nodePrimaryIp node
160 eaed5f19 Agata Murawska
      port = snd C.daemonsPortsGanetiNoded
161 5b11f8db Iustin Pop
      path_prefix = "https://" ++ node_ip ++ ":" ++ show port
162 5b11f8db Iustin Pop
  in path_prefix ++ "/" ++ rpcCallName call
163 eaed5f19 Agata Murawska
164 eaed5f19 Agata Murawska
-- | Create HTTP request for a given node provided it is online,
165 eaed5f19 Agata Murawska
-- otherwise create empty response.
166 85f6a869 Iustin Pop
prepareHttpRequest :: (RpcCall a) => [CurlOption] -> Node -> a
167 599239ad Agata Murawska
                   -> ERpcError HttpClientRequest
168 85f6a869 Iustin Pop
prepareHttpRequest opts node call
169 5b11f8db Iustin Pop
  | rpcCallAcceptOffline call || not (nodeOffline node) =
170 85f6a869 Iustin Pop
      Right HttpClientRequest { requestUrl  = prepareUrl node call
171 85f6a869 Iustin Pop
                              , requestData = rpcCallData node call
172 85f6a869 Iustin Pop
                              , requestOpts = opts ++ curlOpts
173 5b11f8db Iustin Pop
                              }
174 9c0a27d0 Iustin Pop
  | otherwise = Left OfflineNodeError
175 eaed5f19 Agata Murawska
176 8920fa09 Iustin Pop
-- | Parse an HTTP reply.
177 8920fa09 Iustin Pop
parseHttpReply :: (Rpc a b) =>
178 8920fa09 Iustin Pop
                  a -> ERpcError (CurlCode, String) -> ERpcError b
179 8920fa09 Iustin Pop
parseHttpReply _ (Left e) = Left e
180 8920fa09 Iustin Pop
parseHttpReply call (Right (CurlOK, body)) = parseHttpResponse call body
181 8920fa09 Iustin Pop
parseHttpReply _ (Right (code, err)) =
182 8920fa09 Iustin Pop
  Left . CurlLayerError $ "code: " ++ show code ++ ", explanation: " ++ err
183 8920fa09 Iustin Pop
184 9b09c0be Agata Murawska
-- | Parse a result based on the received HTTP response.
185 8920fa09 Iustin Pop
parseHttpResponse :: (Rpc a b) => a -> String -> ERpcError b
186 8920fa09 Iustin Pop
parseHttpResponse call res =
187 a93b711b Agata Murawska
  case J.decode res of
188 a93b711b Agata Murawska
    J.Error val -> Left $ JsonDecodeError val
189 a93b711b Agata Murawska
    J.Ok (True, res'') -> rpcResultFill call res''
190 a93b711b Agata Murawska
    J.Ok (False, jerr) -> case jerr of
191 a93b711b Agata Murawska
       J.JSString msg -> Left $ RpcResultError (J.fromJSString msg)
192 a93b711b Agata Murawska
       _ -> Left . JsonDecodeError $ show (pp_value jerr)
193 9b09c0be Agata Murawska
194 eaed5f19 Agata Murawska
-- | Execute RPC call for many nodes in parallel.
195 599239ad Agata Murawska
executeRpcCall :: (Rpc a b) => [Node] -> a -> IO [(Node, ERpcError b)]
196 85f6a869 Iustin Pop
executeRpcCall nodes call = do
197 85f6a869 Iustin Pop
  cert_file <- P.nodedCertFile
198 85f6a869 Iustin Pop
  let opts = [ CurlTimeout (fromIntegral $ rpcCallTimeout call)
199 85f6a869 Iustin Pop
             , CurlSSLCert cert_file
200 85f6a869 Iustin Pop
             , CurlSSLKey cert_file
201 85f6a869 Iustin Pop
             , CurlCAInfo cert_file
202 85f6a869 Iustin Pop
             ]
203 8920fa09 Iustin Pop
      opts_urls = map (\n ->
204 8920fa09 Iustin Pop
                         case prepareHttpRequest opts n call of
205 8920fa09 Iustin Pop
                           Left v -> Left v
206 8920fa09 Iustin Pop
                           Right request ->
207 8920fa09 Iustin Pop
                             Right (CurlPostFields [requestData request]:
208 8920fa09 Iustin Pop
                                    requestOpts request,
209 8920fa09 Iustin Pop
                                    requestUrl request)
210 8920fa09 Iustin Pop
                      ) nodes
211 8920fa09 Iustin Pop
  -- split the opts_urls list; we don't want to pass the
212 8920fa09 Iustin Pop
  -- failed-already nodes to Curl
213 8920fa09 Iustin Pop
  let (lefts, rights, trail) = splitEithers opts_urls
214 8920fa09 Iustin Pop
  results <- execMultiCall rights
215 8920fa09 Iustin Pop
  results' <- case recombineEithers lefts results trail of
216 8920fa09 Iustin Pop
                Bad msg -> error msg
217 8920fa09 Iustin Pop
                Ok r -> return r
218 8920fa09 Iustin Pop
  -- now parse the replies
219 8920fa09 Iustin Pop
  let results'' = map (parseHttpReply call) results'
220 8920fa09 Iustin Pop
  return $ zip nodes results''
221 96dad12d Agata Murawska
222 9b09c0be Agata Murawska
-- | Helper function that is used to read dictionaries of values.
223 9b09c0be Agata Murawska
sanitizeDictResults :: [(String, J.Result a)] -> ERpcError [(String, a)]
224 3d3f562b Agata Murawska
sanitizeDictResults =
225 3d3f562b Agata Murawska
  foldr sanitize1 (Right [])
226 3d3f562b Agata Murawska
  where
227 3d3f562b Agata Murawska
    sanitize1 _ (Left e) = Left e
228 3d3f562b Agata Murawska
    sanitize1 (_, J.Error e) _ = Left $ JsonDecodeError e
229 3d3f562b Agata Murawska
    sanitize1 (name, J.Ok v) (Right res) = Right $ (name, v) : res
230 9b09c0be Agata Murawska
231 7328a28c Agata Murawska
-- | Helper function to tranform JSON Result to Either RpcError b.
232 7328a28c Agata Murawska
-- Note: For now we really only use it for b s.t. Rpc c b for some c
233 7328a28c Agata Murawska
fromJResultToRes :: J.Result a -> (a -> b) -> ERpcError b
234 7328a28c Agata Murawska
fromJResultToRes (J.Error v) _ = Left $ JsonDecodeError v
235 7328a28c Agata Murawska
fromJResultToRes (J.Ok v) f = Right $ f v
236 7328a28c Agata Murawska
237 7328a28c Agata Murawska
-- | Helper function transforming JSValue to Rpc result type.
238 7328a28c Agata Murawska
fromJSValueToRes :: (J.JSON a) => J.JSValue -> (a -> b) -> ERpcError b
239 7328a28c Agata Murawska
fromJSValueToRes val = fromJResultToRes (J.readJSON val)
240 7328a28c Agata Murawska
241 96dad12d Agata Murawska
-- * RPC calls and results
242 96dad12d Agata Murawska
243 de2a5704 Iustin Pop
-- ** Instance info
244 de2a5704 Iustin Pop
245 5188fdb7 Agata Murawska
-- | InstanceInfo
246 5188fdb7 Agata Murawska
--   Returns information about a single instance.
247 5188fdb7 Agata Murawska
248 5188fdb7 Agata Murawska
$(buildObject "RpcCallInstanceInfo" "rpcCallInstInfo"
249 5188fdb7 Agata Murawska
  [ simpleField "instance" [t| String |]
250 5188fdb7 Agata Murawska
  , simpleField "hname" [t| Hypervisor |]
251 5188fdb7 Agata Murawska
  ])
252 96dad12d Agata Murawska
253 5b11f8db Iustin Pop
$(buildObject "InstanceInfo" "instInfo"
254 9b09c0be Agata Murawska
  [ simpleField "memory" [t| Int|]
255 9b09c0be Agata Murawska
  , simpleField "state"  [t| String |] -- It depends on hypervisor :(
256 96dad12d Agata Murawska
  , simpleField "vcpus"  [t| Int |]
257 96dad12d Agata Murawska
  , simpleField "time"   [t| Int |]
258 96dad12d Agata Murawska
  ])
259 96dad12d Agata Murawska
260 5188fdb7 Agata Murawska
-- This is optional here because the result may be empty if instance is
261 5188fdb7 Agata Murawska
-- not on a node - and this is not considered an error.
262 5188fdb7 Agata Murawska
$(buildObject "RpcResultInstanceInfo" "rpcResInstInfo"
263 5188fdb7 Agata Murawska
  [ optionalField $ simpleField "inst_info" [t| InstanceInfo |]])
264 5188fdb7 Agata Murawska
265 5188fdb7 Agata Murawska
instance RpcCall RpcCallInstanceInfo where
266 274366e5 Agata Murawska
  rpcCallName _          = "instance_info"
267 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
268 5188fdb7 Agata Murawska
  rpcCallAcceptOffline _ = False
269 274366e5 Agata Murawska
  rpcCallData _ call     = J.encode
270 5188fdb7 Agata Murawska
    ( rpcCallInstInfoInstance call
271 5188fdb7 Agata Murawska
    , rpcCallInstInfoHname call
272 5188fdb7 Agata Murawska
    )
273 5188fdb7 Agata Murawska
274 5188fdb7 Agata Murawska
instance Rpc RpcCallInstanceInfo RpcResultInstanceInfo where
275 5188fdb7 Agata Murawska
  rpcResultFill _ res =
276 a93b711b Agata Murawska
    case res of
277 5188fdb7 Agata Murawska
      J.JSObject res' ->
278 5188fdb7 Agata Murawska
        case J.fromJSObject res' of
279 5188fdb7 Agata Murawska
          [] -> Right $ RpcResultInstanceInfo Nothing
280 7328a28c Agata Murawska
          _ -> fromJSValueToRes res (RpcResultInstanceInfo . Just)
281 5188fdb7 Agata Murawska
      _ -> Left $ JsonDecodeError
282 70c2362e Agata Murawska
           ("Expected JSObject, got " ++ show (pp_value res))
283 5188fdb7 Agata Murawska
284 de2a5704 Iustin Pop
-- ** AllInstancesInfo
285 de2a5704 Iustin Pop
286 5188fdb7 Agata Murawska
-- | AllInstancesInfo
287 5188fdb7 Agata Murawska
--   Returns information about all running instances on the given nodes
288 5188fdb7 Agata Murawska
$(buildObject "RpcCallAllInstancesInfo" "rpcCallAllInstInfo"
289 5188fdb7 Agata Murawska
  [ simpleField "hypervisors" [t| [Hypervisor] |] ])
290 5188fdb7 Agata Murawska
291 5b11f8db Iustin Pop
$(buildObject "RpcResultAllInstancesInfo" "rpcResAllInstInfo"
292 9b09c0be Agata Murawska
  [ simpleField "instances" [t| [(String, InstanceInfo)] |] ])
293 96dad12d Agata Murawska
294 96dad12d Agata Murawska
instance RpcCall RpcCallAllInstancesInfo where
295 274366e5 Agata Murawska
  rpcCallName _          = "all_instances_info"
296 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
297 96dad12d Agata Murawska
  rpcCallAcceptOffline _ = False
298 274366e5 Agata Murawska
  rpcCallData _ call     = J.encode [rpcCallAllInstInfoHypervisors call]
299 9b09c0be Agata Murawska
300 47163f0f Agata Murawska
instance Rpc RpcCallAllInstancesInfo RpcResultAllInstancesInfo where
301 9b09c0be Agata Murawska
  -- FIXME: Is there a simpler way to do it?
302 47163f0f Agata Murawska
  rpcResultFill _ res =
303 a93b711b Agata Murawska
    case res of
304 a93b711b Agata Murawska
      J.JSObject res' ->
305 9b09c0be Agata Murawska
        let res'' = map (second J.readJSON) (J.fromJSObject res')
306 a93b711b Agata Murawska
                        :: [(String, J.Result InstanceInfo)] in
307 9b09c0be Agata Murawska
        case sanitizeDictResults res'' of
308 9b09c0be Agata Murawska
          Left err -> Left err
309 9b09c0be Agata Murawska
          Right insts -> Right $ RpcResultAllInstancesInfo insts
310 9b09c0be Agata Murawska
      _ -> Left $ JsonDecodeError
311 70c2362e Agata Murawska
           ("Expected JSObject, got " ++ show (pp_value res))
312 96dad12d Agata Murawska
313 de2a5704 Iustin Pop
-- ** InstanceList
314 de2a5704 Iustin Pop
315 c1c5aab1 Agata Murawska
-- | InstanceList
316 c1c5aab1 Agata Murawska
-- Returns the list of running instances on the given nodes.
317 5b11f8db Iustin Pop
$(buildObject "RpcCallInstanceList" "rpcCallInstList"
318 c1c5aab1 Agata Murawska
  [ simpleField "hypervisors" [t| [Hypervisor] |] ])
319 c1c5aab1 Agata Murawska
320 5b11f8db Iustin Pop
$(buildObject "RpcResultInstanceList" "rpcResInstList"
321 9b09c0be Agata Murawska
  [ simpleField "instances" [t| [String] |] ])
322 c1c5aab1 Agata Murawska
323 c1c5aab1 Agata Murawska
instance RpcCall RpcCallInstanceList where
324 274366e5 Agata Murawska
  rpcCallName _          = "instance_list"
325 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
326 c1c5aab1 Agata Murawska
  rpcCallAcceptOffline _ = False
327 274366e5 Agata Murawska
  rpcCallData _ call     = J.encode [rpcCallInstListHypervisors call]
328 c1c5aab1 Agata Murawska
329 47163f0f Agata Murawska
instance Rpc RpcCallInstanceList RpcResultInstanceList where
330 7328a28c Agata Murawska
  rpcResultFill _ res = fromJSValueToRes res RpcResultInstanceList
331 c1c5aab1 Agata Murawska
332 de2a5704 Iustin Pop
-- ** NodeInfo
333 de2a5704 Iustin Pop
334 dc623a95 Agata Murawska
-- | NodeInfo
335 dc623a95 Agata Murawska
-- Return node information.
336 5b11f8db Iustin Pop
$(buildObject "RpcCallNodeInfo" "rpcCallNodeInfo"
337 9b09c0be Agata Murawska
  [ simpleField "volume_groups" [t| [String] |]
338 9b09c0be Agata Murawska
  , simpleField "hypervisors" [t| [Hypervisor] |]
339 319322a7 Bernardo Dal Seno
  , simpleField "exclusive_storage" [t| Map.Map String Bool |]
340 dc623a95 Agata Murawska
  ])
341 dc623a95 Agata Murawska
342 5b11f8db Iustin Pop
$(buildObject "VgInfo" "vgInfo"
343 dc623a95 Agata Murawska
  [ simpleField "name" [t| String |]
344 9b09c0be Agata Murawska
  , optionalField $ simpleField "vg_free" [t| Int |]
345 9b09c0be Agata Murawska
  , optionalField $ simpleField "vg_size" [t| Int |]
346 dc623a95 Agata Murawska
  ])
347 dc623a95 Agata Murawska
348 dc623a95 Agata Murawska
-- | We only provide common fields as described in hv_base.py.
349 5b11f8db Iustin Pop
$(buildObject "HvInfo" "hvInfo"
350 dc623a95 Agata Murawska
  [ simpleField "memory_total" [t| Int |]
351 dc623a95 Agata Murawska
  , simpleField "memory_free" [t| Int |]
352 dc623a95 Agata Murawska
  , simpleField "memory_dom0" [t| Int |]
353 dc623a95 Agata Murawska
  , simpleField "cpu_total" [t| Int |]
354 dc623a95 Agata Murawska
  , simpleField "cpu_nodes" [t| Int |]
355 dc623a95 Agata Murawska
  , simpleField "cpu_sockets" [t| Int |]
356 dc623a95 Agata Murawska
  ])
357 dc623a95 Agata Murawska
358 5b11f8db Iustin Pop
$(buildObject "RpcResultNodeInfo" "rpcResNodeInfo"
359 dc623a95 Agata Murawska
  [ simpleField "boot_id" [t| String |]
360 dc623a95 Agata Murawska
  , simpleField "vg_info" [t| [VgInfo] |]
361 dc623a95 Agata Murawska
  , simpleField "hv_info" [t| [HvInfo] |]
362 dc623a95 Agata Murawska
  ])
363 dc623a95 Agata Murawska
364 dc623a95 Agata Murawska
instance RpcCall RpcCallNodeInfo where
365 274366e5 Agata Murawska
  rpcCallName _          = "node_info"
366 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
367 dc623a95 Agata Murawska
  rpcCallAcceptOffline _ = False
368 319322a7 Bernardo Dal Seno
  rpcCallData n call     = J.encode
369 274366e5 Agata Murawska
    ( rpcCallNodeInfoVolumeGroups call
370 274366e5 Agata Murawska
    , rpcCallNodeInfoHypervisors call
371 319322a7 Bernardo Dal Seno
    , fromMaybe (error $ "Programmer error: missing parameter for node named "
372 319322a7 Bernardo Dal Seno
                         ++ nodeName n)
373 319322a7 Bernardo Dal Seno
                $ Map.lookup (nodeName n) (rpcCallNodeInfoExclusiveStorage call)
374 274366e5 Agata Murawska
    )
375 9b09c0be Agata Murawska
376 47163f0f Agata Murawska
instance Rpc RpcCallNodeInfo RpcResultNodeInfo where
377 47163f0f Agata Murawska
  rpcResultFill _ res =
378 7328a28c Agata Murawska
    fromJSValueToRes res (\(b, vg, hv) -> RpcResultNodeInfo b vg hv)
379 dc623a95 Agata Murawska
380 de2a5704 Iustin Pop
-- ** Version
381 de2a5704 Iustin Pop
382 8779d21a Agata Murawska
-- | Version
383 8779d21a Agata Murawska
-- Query node version.
384 8779d21a Agata Murawska
-- Note: We can't use THH as it does not know what to do with empty dict
385 8779d21a Agata Murawska
data RpcCallVersion = RpcCallVersion {}
386 139c0683 Iustin Pop
  deriving (Show, Eq)
387 8779d21a Agata Murawska
388 8779d21a Agata Murawska
instance J.JSON RpcCallVersion where
389 8779d21a Agata Murawska
  showJSON _ = J.JSNull
390 8779d21a Agata Murawska
  readJSON J.JSNull = return RpcCallVersion
391 8779d21a Agata Murawska
  readJSON _ = fail "Unable to read RpcCallVersion"
392 8779d21a Agata Murawska
393 8779d21a Agata Murawska
$(buildObject "RpcResultVersion" "rpcResultVersion"
394 8779d21a Agata Murawska
  [ simpleField "version" [t| Int |]
395 8779d21a Agata Murawska
  ])
396 8779d21a Agata Murawska
397 8779d21a Agata Murawska
instance RpcCall RpcCallVersion where
398 274366e5 Agata Murawska
  rpcCallName _          = "version"
399 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
400 8779d21a Agata Murawska
  rpcCallAcceptOffline _ = True
401 ff8f0049 Iustin Pop
  rpcCallData _          = J.encode
402 8779d21a Agata Murawska
403 47163f0f Agata Murawska
instance Rpc RpcCallVersion RpcResultVersion where
404 7328a28c Agata Murawska
  rpcResultFill _ res = fromJSValueToRes res RpcResultVersion
405 8779d21a Agata Murawska
406 de2a5704 Iustin Pop
-- ** StorageList
407 de2a5704 Iustin Pop
408 47163f0f Agata Murawska
-- | StorageList
409 47163f0f Agata Murawska
410 47163f0f Agata Murawska
-- FIXME: This may be moved to Objects
411 47163f0f Agata Murawska
$(declareSADT "StorageField"
412 47163f0f Agata Murawska
  [ ( "SFUsed",        'C.sfUsed)
413 47163f0f Agata Murawska
  , ( "SFName",        'C.sfName)
414 47163f0f Agata Murawska
  , ( "SFAllocatable", 'C.sfAllocatable)
415 47163f0f Agata Murawska
  , ( "SFFree",        'C.sfFree)
416 47163f0f Agata Murawska
  , ( "SFSize",        'C.sfSize)
417 47163f0f Agata Murawska
  ])
418 47163f0f Agata Murawska
$(makeJSONInstance ''StorageField)
419 47163f0f Agata Murawska
420 47163f0f Agata Murawska
$(buildObject "RpcCallStorageList" "rpcCallStorageList"
421 47163f0f Agata Murawska
  [ simpleField "su_name" [t| StorageType |]
422 47163f0f Agata Murawska
  , simpleField "su_args" [t| [String] |]
423 47163f0f Agata Murawska
  , simpleField "name"    [t| String |]
424 47163f0f Agata Murawska
  , simpleField "fields"  [t| [StorageField] |]
425 47163f0f Agata Murawska
  ])
426 47163f0f Agata Murawska
427 47163f0f Agata Murawska
-- FIXME: The resulting JSValues should have types appropriate for their
428 47163f0f Agata Murawska
-- StorageField value: Used -> Bool, Name -> String etc
429 47163f0f Agata Murawska
$(buildObject "RpcResultStorageList" "rpcResStorageList"
430 47163f0f Agata Murawska
  [ simpleField "storage" [t| [[(StorageField, J.JSValue)]] |] ])
431 47163f0f Agata Murawska
432 47163f0f Agata Murawska
instance RpcCall RpcCallStorageList where
433 274366e5 Agata Murawska
  rpcCallName _          = "storage_list"
434 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Normal
435 47163f0f Agata Murawska
  rpcCallAcceptOffline _ = False
436 274366e5 Agata Murawska
  rpcCallData _ call     = J.encode
437 47163f0f Agata Murawska
    ( rpcCallStorageListSuName call
438 47163f0f Agata Murawska
    , rpcCallStorageListSuArgs call
439 47163f0f Agata Murawska
    , rpcCallStorageListName call
440 47163f0f Agata Murawska
    , rpcCallStorageListFields call
441 47163f0f Agata Murawska
    )
442 47163f0f Agata Murawska
443 47163f0f Agata Murawska
instance Rpc RpcCallStorageList RpcResultStorageList where
444 47163f0f Agata Murawska
  rpcResultFill call res =
445 47163f0f Agata Murawska
    let sfields = rpcCallStorageListFields call in
446 7328a28c Agata Murawska
    fromJSValueToRes res (RpcResultStorageList . map (zip sfields))
447 de2a5704 Iustin Pop
448 de2a5704 Iustin Pop
-- ** TestDelay
449 de2a5704 Iustin Pop
450 de2a5704 Iustin Pop
451 de2a5704 Iustin Pop
-- | Call definition for test delay.
452 de2a5704 Iustin Pop
$(buildObject "RpcCallTestDelay" "rpcCallTestDelay"
453 de2a5704 Iustin Pop
  [ simpleField "duration" [t| Double |]
454 de2a5704 Iustin Pop
  ])
455 de2a5704 Iustin Pop
456 de2a5704 Iustin Pop
-- | Result definition for test delay.
457 de2a5704 Iustin Pop
data RpcResultTestDelay = RpcResultTestDelay
458 de2a5704 Iustin Pop
                          deriving Show
459 de2a5704 Iustin Pop
460 de2a5704 Iustin Pop
-- | Custom JSON instance for null result.
461 de2a5704 Iustin Pop
instance J.JSON RpcResultTestDelay where
462 de2a5704 Iustin Pop
  showJSON _        = J.JSNull
463 de2a5704 Iustin Pop
  readJSON J.JSNull = return RpcResultTestDelay
464 de2a5704 Iustin Pop
  readJSON _        = fail "Unable to read RpcResultTestDelay"
465 de2a5704 Iustin Pop
466 de2a5704 Iustin Pop
instance RpcCall RpcCallTestDelay where
467 de2a5704 Iustin Pop
  rpcCallName _          = "test_delay"
468 de2a5704 Iustin Pop
  rpcCallTimeout         = ceiling . (+ 5) . rpcCallTestDelayDuration
469 de2a5704 Iustin Pop
  rpcCallAcceptOffline _ = False
470 de2a5704 Iustin Pop
  rpcCallData _ call     = J.encode [rpcCallTestDelayDuration call]
471 de2a5704 Iustin Pop
472 de2a5704 Iustin Pop
instance Rpc RpcCallTestDelay RpcResultTestDelay where
473 de2a5704 Iustin Pop
  rpcResultFill _ res = fromJSValueToRes res id