Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Rpc.hs @ 557f5dad

History | View | Annotate | Download (19.4 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 ad56f735 Hrvoje Ribicic
  , executeRpcCalls
37 a246ce76 Michele Tartara
  , logRpcErrors
38 d4709cce Agata Murawska
39 d4709cce Agata Murawska
  , rpcCallName
40 d4709cce Agata Murawska
  , rpcCallTimeout
41 d4709cce Agata Murawska
  , rpcCallData
42 d4709cce Agata Murawska
  , rpcCallAcceptOffline
43 d4709cce Agata Murawska
44 d4709cce Agata Murawska
  , rpcResultFill
45 96dad12d Agata Murawska
46 5188fdb7 Agata Murawska
  , RpcCallInstanceInfo(..)
47 14933c17 Jose A. Lopes
  , InstanceState(..)
48 14933c17 Jose A. Lopes
  , InstanceInfo(..)
49 5188fdb7 Agata Murawska
  , RpcResultInstanceInfo(..)
50 5188fdb7 Agata Murawska
51 96dad12d Agata Murawska
  , RpcCallAllInstancesInfo(..)
52 96dad12d Agata Murawska
  , RpcResultAllInstancesInfo(..)
53 96dad12d Agata Murawska
54 b9e12624 Hrvoje Ribicic
  , InstanceConsoleInfoParams(..)
55 b9e12624 Hrvoje Ribicic
  , InstanceConsoleInfo(..)
56 b9e12624 Hrvoje Ribicic
  , RpcCallInstanceConsoleInfo(..)
57 b9e12624 Hrvoje Ribicic
  , RpcResultInstanceConsoleInfo(..)
58 b9e12624 Hrvoje Ribicic
59 c1c5aab1 Agata Murawska
  , RpcCallInstanceList(..)
60 c1c5aab1 Agata Murawska
  , RpcResultInstanceList(..)
61 c1c5aab1 Agata Murawska
62 dc623a95 Agata Murawska
  , HvInfo(..)
63 32389d91 Helga Velroyen
  , StorageInfo(..)
64 dc623a95 Agata Murawska
  , RpcCallNodeInfo(..)
65 dc623a95 Agata Murawska
  , RpcResultNodeInfo(..)
66 dc623a95 Agata Murawska
67 8779d21a Agata Murawska
  , RpcCallVersion(..)
68 8779d21a Agata Murawska
  , RpcResultVersion(..)
69 8779d21a Agata Murawska
70 47163f0f Agata Murawska
  , RpcCallStorageList(..)
71 47163f0f Agata Murawska
  , RpcResultStorageList(..)
72 47163f0f Agata Murawska
73 de2a5704 Iustin Pop
  , RpcCallTestDelay(..)
74 de2a5704 Iustin Pop
  , RpcResultTestDelay(..)
75 de2a5704 Iustin Pop
76 842515dd Iustin Pop
  , RpcCallExportList(..)
77 842515dd Iustin Pop
  , RpcResultExportList(..)
78 a716edba Klaus Aehlig
79 a716edba Klaus Aehlig
  , RpcCallJobqueueUpdate(..)
80 d4709cce Agata Murawska
  ) where
81 d4709cce Agata Murawska
82 9b09c0be Agata Murawska
import Control.Arrow (second)
83 835050f3 Klaus Aehlig
import qualified Codec.Compression.Zlib as Zlib
84 835050f3 Klaus Aehlig
import qualified Data.ByteString.Lazy.Char8 as BL
85 319322a7 Bernardo Dal Seno
import qualified Data.Map as Map
86 319322a7 Bernardo Dal Seno
import Data.Maybe (fromMaybe)
87 d4709cce Agata Murawska
import qualified Text.JSON as J
88 9b09c0be Agata Murawska
import Text.JSON.Pretty (pp_value)
89 835050f3 Klaus Aehlig
import qualified Data.ByteString.Base64.Lazy as Base64
90 d4709cce Agata Murawska
91 a716edba Klaus Aehlig
import Network.Curl hiding (content)
92 7766de33 Agata Murawska
import qualified Ganeti.Path as P
93 eaed5f19 Agata Murawska
94 8920fa09 Iustin Pop
import Ganeti.BasicTypes
95 eaed5f19 Agata Murawska
import qualified Ganeti.Constants as C
96 c14ba680 Hrvoje Ribicic
import Ganeti.JSON
97 a246ce76 Michele Tartara
import Ganeti.Logging
98 d4709cce Agata Murawska
import Ganeti.Objects
99 96dad12d Agata Murawska
import Ganeti.THH
100 22381768 Iustin Pop
import Ganeti.Types
101 8920fa09 Iustin Pop
import Ganeti.Curl.Multi
102 8920fa09 Iustin Pop
import Ganeti.Utils
103 eaed5f19 Agata Murawska
104 de2a5704 Iustin Pop
-- * Base RPC functionality and types
105 de2a5704 Iustin Pop
106 eaed5f19 Agata Murawska
-- | The curl options used for RPC.
107 eaed5f19 Agata Murawska
curlOpts :: [CurlOption]
108 eaed5f19 Agata Murawska
curlOpts = [ CurlFollowLocation False
109 eaed5f19 Agata Murawska
           , CurlSSLVerifyHost 0
110 eaed5f19 Agata Murawska
           , CurlSSLVerifyPeer True
111 eaed5f19 Agata Murawska
           , CurlSSLCertType "PEM"
112 eaed5f19 Agata Murawska
           , CurlSSLKeyType "PEM"
113 eaed5f19 Agata Murawska
           , CurlConnectTimeout (fromIntegral C.rpcConnectTimeout)
114 eaed5f19 Agata Murawska
           ]
115 d4709cce Agata Murawska
116 d4709cce Agata Murawska
-- | Data type for RPC error reporting.
117 d4709cce Agata Murawska
data RpcError
118 9c0a27d0 Iustin Pop
  = CurlLayerError String
119 d4709cce Agata Murawska
  | JsonDecodeError String
120 6fddde87 Agata Murawska
  | RpcResultError String
121 9c0a27d0 Iustin Pop
  | OfflineNodeError
122 60443f61 Agata Murawska
  deriving (Show, Eq)
123 d4709cce Agata Murawska
124 60443f61 Agata Murawska
-- | Provide explanation to RPC errors.
125 60443f61 Agata Murawska
explainRpcError :: RpcError -> String
126 9c0a27d0 Iustin Pop
explainRpcError (CurlLayerError code) =
127 9c0a27d0 Iustin Pop
    "Curl error:" ++ code
128 60443f61 Agata Murawska
explainRpcError (JsonDecodeError msg) =
129 6fddde87 Agata Murawska
    "Error while decoding JSON from HTTP response: " ++ msg
130 60443f61 Agata Murawska
explainRpcError (RpcResultError msg) =
131 6fddde87 Agata Murawska
    "Error reponse received from RPC server: " ++ msg
132 9c0a27d0 Iustin Pop
explainRpcError OfflineNodeError =
133 9c0a27d0 Iustin Pop
    "Node is marked offline"
134 d4709cce Agata Murawska
135 599239ad Agata Murawska
type ERpcError = Either RpcError
136 599239ad Agata Murawska
137 d4709cce Agata Murawska
-- | A generic class for RPC calls.
138 d4709cce Agata Murawska
class (J.JSON a) => RpcCall a where
139 d4709cce Agata Murawska
  -- | Give the (Python) name of the procedure.
140 d4709cce Agata Murawska
  rpcCallName :: a -> String
141 d4709cce Agata Murawska
  -- | Calculate the timeout value for the call execution.
142 d4709cce Agata Murawska
  rpcCallTimeout :: a -> Int
143 d4709cce Agata Murawska
  -- | Prepare arguments of the call to be send as POST.
144 d4709cce Agata Murawska
  rpcCallData :: Node -> a -> String
145 d4709cce Agata Murawska
  -- | Whether we accept offline nodes when making a call.
146 d4709cce Agata Murawska
  rpcCallAcceptOffline :: a -> Bool
147 d4709cce Agata Murawska
148 d4709cce Agata Murawska
-- | Generic class that ensures matching RPC call with its respective
149 d4709cce Agata Murawska
-- result.
150 47163f0f Agata Murawska
class (RpcCall a, J.JSON b) => Rpc a b  | a -> b, b -> a where
151 47163f0f Agata Murawska
  -- | Create a result based on the received HTTP response.
152 a93b711b Agata Murawska
  rpcResultFill :: a -> J.JSValue -> ERpcError b
153 eaed5f19 Agata Murawska
154 eaed5f19 Agata Murawska
-- | Http Request definition.
155 eaed5f19 Agata Murawska
data HttpClientRequest = HttpClientRequest
156 85f6a869 Iustin Pop
  { requestUrl  :: String       -- ^ The actual URL for the node endpoint
157 85f6a869 Iustin Pop
  , requestData :: String       -- ^ The arguments for the call
158 85f6a869 Iustin Pop
  , requestOpts :: [CurlOption] -- ^ The various curl options
159 eaed5f19 Agata Murawska
  }
160 eaed5f19 Agata Murawska
161 eaed5f19 Agata Murawska
-- | Prepare url for the HTTP request.
162 eaed5f19 Agata Murawska
prepareUrl :: (RpcCall a) => Node -> a -> String
163 eaed5f19 Agata Murawska
prepareUrl node call =
164 eaed5f19 Agata Murawska
  let node_ip = nodePrimaryIp node
165 6dc0cb59 Jose A. Lopes
      port = C.defaultNodedPort
166 5b11f8db Iustin Pop
      path_prefix = "https://" ++ node_ip ++ ":" ++ show port
167 5b11f8db Iustin Pop
  in path_prefix ++ "/" ++ rpcCallName call
168 eaed5f19 Agata Murawska
169 eaed5f19 Agata Murawska
-- | Create HTTP request for a given node provided it is online,
170 eaed5f19 Agata Murawska
-- otherwise create empty response.
171 85f6a869 Iustin Pop
prepareHttpRequest :: (RpcCall a) => [CurlOption] -> Node -> a
172 599239ad Agata Murawska
                   -> ERpcError HttpClientRequest
173 85f6a869 Iustin Pop
prepareHttpRequest opts node call
174 5b11f8db Iustin Pop
  | rpcCallAcceptOffline call || not (nodeOffline node) =
175 85f6a869 Iustin Pop
      Right HttpClientRequest { requestUrl  = prepareUrl node call
176 85f6a869 Iustin Pop
                              , requestData = rpcCallData node call
177 85f6a869 Iustin Pop
                              , requestOpts = opts ++ curlOpts
178 5b11f8db Iustin Pop
                              }
179 9c0a27d0 Iustin Pop
  | otherwise = Left OfflineNodeError
180 eaed5f19 Agata Murawska
181 8920fa09 Iustin Pop
-- | Parse an HTTP reply.
182 8920fa09 Iustin Pop
parseHttpReply :: (Rpc a b) =>
183 8920fa09 Iustin Pop
                  a -> ERpcError (CurlCode, String) -> ERpcError b
184 8920fa09 Iustin Pop
parseHttpReply _ (Left e) = Left e
185 8920fa09 Iustin Pop
parseHttpReply call (Right (CurlOK, body)) = parseHttpResponse call body
186 8920fa09 Iustin Pop
parseHttpReply _ (Right (code, err)) =
187 8920fa09 Iustin Pop
  Left . CurlLayerError $ "code: " ++ show code ++ ", explanation: " ++ err
188 8920fa09 Iustin Pop
189 9b09c0be Agata Murawska
-- | Parse a result based on the received HTTP response.
190 8920fa09 Iustin Pop
parseHttpResponse :: (Rpc a b) => a -> String -> ERpcError b
191 8920fa09 Iustin Pop
parseHttpResponse call res =
192 a93b711b Agata Murawska
  case J.decode res of
193 a93b711b Agata Murawska
    J.Error val -> Left $ JsonDecodeError val
194 a93b711b Agata Murawska
    J.Ok (True, res'') -> rpcResultFill call res''
195 a93b711b Agata Murawska
    J.Ok (False, jerr) -> case jerr of
196 a93b711b Agata Murawska
       J.JSString msg -> Left $ RpcResultError (J.fromJSString msg)
197 a93b711b Agata Murawska
       _ -> Left . JsonDecodeError $ show (pp_value jerr)
198 9b09c0be Agata Murawska
199 a246ce76 Michele Tartara
-- | Scan the list of results produced by executeRpcCall and log all the RPC
200 a246ce76 Michele Tartara
-- errors.
201 a246ce76 Michele Tartara
logRpcErrors :: [(a, ERpcError b)] -> IO ()
202 a246ce76 Michele Tartara
logRpcErrors allElems =
203 a246ce76 Michele Tartara
  let logOneRpcErr (_, Right _) = return ()
204 a246ce76 Michele Tartara
      logOneRpcErr (_, Left err) =
205 a246ce76 Michele Tartara
        logError $ "Error in the RPC HTTP reply: " ++ show err
206 a246ce76 Michele Tartara
  in mapM_ logOneRpcErr allElems
207 a246ce76 Michele Tartara
208 ad56f735 Hrvoje Ribicic
-- | Get options for RPC call
209 ad56f735 Hrvoje Ribicic
getOptionsForCall :: (Rpc a b) => FilePath -> a -> [CurlOption]
210 ad56f735 Hrvoje Ribicic
getOptionsForCall certPath call =
211 ad56f735 Hrvoje Ribicic
  [ CurlTimeout (fromIntegral $ rpcCallTimeout call)
212 ad56f735 Hrvoje Ribicic
  , CurlSSLCert certPath
213 ad56f735 Hrvoje Ribicic
  , CurlSSLKey certPath
214 ad56f735 Hrvoje Ribicic
  , CurlCAInfo certPath
215 ad56f735 Hrvoje Ribicic
  ]
216 ad56f735 Hrvoje Ribicic
217 ad56f735 Hrvoje Ribicic
-- | Execute multiple RPC calls in parallel
218 ad56f735 Hrvoje Ribicic
executeRpcCalls :: (Rpc a b) => [(Node, a)] -> IO [(Node, ERpcError b)]
219 ad56f735 Hrvoje Ribicic
executeRpcCalls nodeCalls = do
220 85f6a869 Iustin Pop
  cert_file <- P.nodedCertFile
221 ad56f735 Hrvoje Ribicic
  let (nodes, calls) = unzip nodeCalls
222 ad56f735 Hrvoje Ribicic
      opts = map (getOptionsForCall cert_file) calls
223 ad56f735 Hrvoje Ribicic
      opts_urls = zipWith3 (\n c o ->
224 ad56f735 Hrvoje Ribicic
                         case prepareHttpRequest o n c of
225 8920fa09 Iustin Pop
                           Left v -> Left v
226 8920fa09 Iustin Pop
                           Right request ->
227 8920fa09 Iustin Pop
                             Right (CurlPostFields [requestData request]:
228 8920fa09 Iustin Pop
                                    requestOpts request,
229 8920fa09 Iustin Pop
                                    requestUrl request)
230 ad56f735 Hrvoje Ribicic
                    ) nodes calls opts
231 8920fa09 Iustin Pop
  -- split the opts_urls list; we don't want to pass the
232 8920fa09 Iustin Pop
  -- failed-already nodes to Curl
233 8920fa09 Iustin Pop
  let (lefts, rights, trail) = splitEithers opts_urls
234 8920fa09 Iustin Pop
  results <- execMultiCall rights
235 8920fa09 Iustin Pop
  results' <- case recombineEithers lefts results trail of
236 8920fa09 Iustin Pop
                Bad msg -> error msg
237 8920fa09 Iustin Pop
                Ok r -> return r
238 8920fa09 Iustin Pop
  -- now parse the replies
239 ad56f735 Hrvoje Ribicic
  let results'' = zipWith parseHttpReply calls results'
240 c393abbf Michele Tartara
      pairedList = zip nodes results''
241 c393abbf Michele Tartara
  logRpcErrors pairedList
242 c393abbf Michele Tartara
  return pairedList
243 96dad12d Agata Murawska
244 ad56f735 Hrvoje Ribicic
-- | Execute an RPC call for many nodes in parallel.
245 ad56f735 Hrvoje Ribicic
executeRpcCall :: (Rpc a b) => [Node] -> a -> IO [(Node, ERpcError b)]
246 ad56f735 Hrvoje Ribicic
executeRpcCall nodes call = executeRpcCalls . zip nodes $ repeat call
247 ad56f735 Hrvoje Ribicic
248 9b09c0be Agata Murawska
-- | Helper function that is used to read dictionaries of values.
249 9b09c0be Agata Murawska
sanitizeDictResults :: [(String, J.Result a)] -> ERpcError [(String, a)]
250 3d3f562b Agata Murawska
sanitizeDictResults =
251 3d3f562b Agata Murawska
  foldr sanitize1 (Right [])
252 3d3f562b Agata Murawska
  where
253 3d3f562b Agata Murawska
    sanitize1 _ (Left e) = Left e
254 3d3f562b Agata Murawska
    sanitize1 (_, J.Error e) _ = Left $ JsonDecodeError e
255 3d3f562b Agata Murawska
    sanitize1 (name, J.Ok v) (Right res) = Right $ (name, v) : res
256 9b09c0be Agata Murawska
257 7328a28c Agata Murawska
-- | Helper function to tranform JSON Result to Either RpcError b.
258 7328a28c Agata Murawska
-- Note: For now we really only use it for b s.t. Rpc c b for some c
259 7328a28c Agata Murawska
fromJResultToRes :: J.Result a -> (a -> b) -> ERpcError b
260 7328a28c Agata Murawska
fromJResultToRes (J.Error v) _ = Left $ JsonDecodeError v
261 7328a28c Agata Murawska
fromJResultToRes (J.Ok v) f = Right $ f v
262 7328a28c Agata Murawska
263 7328a28c Agata Murawska
-- | Helper function transforming JSValue to Rpc result type.
264 7328a28c Agata Murawska
fromJSValueToRes :: (J.JSON a) => J.JSValue -> (a -> b) -> ERpcError b
265 7328a28c Agata Murawska
fromJSValueToRes val = fromJResultToRes (J.readJSON val)
266 7328a28c Agata Murawska
267 96dad12d Agata Murawska
-- * RPC calls and results
268 96dad12d Agata Murawska
269 de2a5704 Iustin Pop
-- ** Instance info
270 de2a5704 Iustin Pop
271 b9e12624 Hrvoje Ribicic
-- | Returns information about a single instance
272 5188fdb7 Agata Murawska
$(buildObject "RpcCallInstanceInfo" "rpcCallInstInfo"
273 5188fdb7 Agata Murawska
  [ simpleField "instance" [t| String |]
274 5188fdb7 Agata Murawska
  , simpleField "hname" [t| Hypervisor |]
275 5188fdb7 Agata Murawska
  ])
276 96dad12d Agata Murawska
277 14933c17 Jose A. Lopes
$(declareILADT "InstanceState"
278 14933c17 Jose A. Lopes
  [ ("InstanceStateRunning", 0)
279 14933c17 Jose A. Lopes
  , ("InstanceStateShutdown", 1)
280 14933c17 Jose A. Lopes
  ])
281 14933c17 Jose A. Lopes
282 14933c17 Jose A. Lopes
$(makeJSONInstance ''InstanceState)
283 14933c17 Jose A. Lopes
284 14933c17 Jose A. Lopes
instance PyValue InstanceState where
285 14933c17 Jose A. Lopes
  showValue = show . instanceStateToRaw
286 14933c17 Jose A. Lopes
287 5b11f8db Iustin Pop
$(buildObject "InstanceInfo" "instInfo"
288 9b09c0be Agata Murawska
  [ simpleField "memory" [t| Int|]
289 14933c17 Jose A. Lopes
  , simpleField "state"  [t| InstanceState |]
290 96dad12d Agata Murawska
  , simpleField "vcpus"  [t| Int |]
291 96dad12d Agata Murawska
  , simpleField "time"   [t| Int |]
292 96dad12d Agata Murawska
  ])
293 96dad12d Agata Murawska
294 5188fdb7 Agata Murawska
-- This is optional here because the result may be empty if instance is
295 5188fdb7 Agata Murawska
-- not on a node - and this is not considered an error.
296 5188fdb7 Agata Murawska
$(buildObject "RpcResultInstanceInfo" "rpcResInstInfo"
297 5188fdb7 Agata Murawska
  [ optionalField $ simpleField "inst_info" [t| InstanceInfo |]])
298 5188fdb7 Agata Murawska
299 5188fdb7 Agata Murawska
instance RpcCall RpcCallInstanceInfo where
300 274366e5 Agata Murawska
  rpcCallName _          = "instance_info"
301 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
302 5188fdb7 Agata Murawska
  rpcCallAcceptOffline _ = False
303 274366e5 Agata Murawska
  rpcCallData _ call     = J.encode
304 5188fdb7 Agata Murawska
    ( rpcCallInstInfoInstance call
305 5188fdb7 Agata Murawska
    , rpcCallInstInfoHname call
306 5188fdb7 Agata Murawska
    )
307 5188fdb7 Agata Murawska
308 5188fdb7 Agata Murawska
instance Rpc RpcCallInstanceInfo RpcResultInstanceInfo where
309 5188fdb7 Agata Murawska
  rpcResultFill _ res =
310 a93b711b Agata Murawska
    case res of
311 5188fdb7 Agata Murawska
      J.JSObject res' ->
312 5188fdb7 Agata Murawska
        case J.fromJSObject res' of
313 5188fdb7 Agata Murawska
          [] -> Right $ RpcResultInstanceInfo Nothing
314 7328a28c Agata Murawska
          _ -> fromJSValueToRes res (RpcResultInstanceInfo . Just)
315 5188fdb7 Agata Murawska
      _ -> Left $ JsonDecodeError
316 70c2362e Agata Murawska
           ("Expected JSObject, got " ++ show (pp_value res))
317 5188fdb7 Agata Murawska
318 de2a5704 Iustin Pop
-- ** AllInstancesInfo
319 de2a5704 Iustin Pop
320 b9e12624 Hrvoje Ribicic
-- | Returns information about all running instances on the given nodes
321 5188fdb7 Agata Murawska
$(buildObject "RpcCallAllInstancesInfo" "rpcCallAllInstInfo"
322 c14ba680 Hrvoje Ribicic
  [ simpleField "hypervisors" [t| [(Hypervisor, HvParams)] |] ])
323 5188fdb7 Agata Murawska
324 5b11f8db Iustin Pop
$(buildObject "RpcResultAllInstancesInfo" "rpcResAllInstInfo"
325 9b09c0be Agata Murawska
  [ simpleField "instances" [t| [(String, InstanceInfo)] |] ])
326 96dad12d Agata Murawska
327 96dad12d Agata Murawska
instance RpcCall RpcCallAllInstancesInfo where
328 274366e5 Agata Murawska
  rpcCallName _          = "all_instances_info"
329 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
330 96dad12d Agata Murawska
  rpcCallAcceptOffline _ = False
331 c14ba680 Hrvoje Ribicic
  rpcCallData _ call     = J.encode (
332 c14ba680 Hrvoje Ribicic
    map fst $ rpcCallAllInstInfoHypervisors call,
333 c14ba680 Hrvoje Ribicic
    GenericContainer . Map.fromList $ rpcCallAllInstInfoHypervisors call)
334 9b09c0be Agata Murawska
335 47163f0f Agata Murawska
instance Rpc RpcCallAllInstancesInfo RpcResultAllInstancesInfo where
336 9b09c0be Agata Murawska
  -- FIXME: Is there a simpler way to do it?
337 47163f0f Agata Murawska
  rpcResultFill _ res =
338 a93b711b Agata Murawska
    case res of
339 a93b711b Agata Murawska
      J.JSObject res' ->
340 9b09c0be Agata Murawska
        let res'' = map (second J.readJSON) (J.fromJSObject res')
341 a93b711b Agata Murawska
                        :: [(String, J.Result InstanceInfo)] in
342 9b09c0be Agata Murawska
        case sanitizeDictResults res'' of
343 9b09c0be Agata Murawska
          Left err -> Left err
344 9b09c0be Agata Murawska
          Right insts -> Right $ RpcResultAllInstancesInfo insts
345 9b09c0be Agata Murawska
      _ -> Left $ JsonDecodeError
346 70c2362e Agata Murawska
           ("Expected JSObject, got " ++ show (pp_value res))
347 96dad12d Agata Murawska
348 b9e12624 Hrvoje Ribicic
-- ** InstanceConsoleInfo
349 b9e12624 Hrvoje Ribicic
350 b9e12624 Hrvoje Ribicic
-- | Returns information about how to access instances on the given node
351 b9e12624 Hrvoje Ribicic
$(buildObject "InstanceConsoleInfoParams" "instConsInfoParams"
352 b9e12624 Hrvoje Ribicic
  [ simpleField "instance"    [t| Instance |]
353 b9e12624 Hrvoje Ribicic
  , simpleField "node"        [t| Node |]
354 0808e9d5 Petr Pudlak
  , simpleField "group"       [t| NodeGroup |]
355 b9e12624 Hrvoje Ribicic
  , simpleField "hvParams"    [t| HvParams |]
356 b9e12624 Hrvoje Ribicic
  , simpleField "beParams"    [t| FilledBeParams |]
357 b9e12624 Hrvoje Ribicic
  ])
358 b9e12624 Hrvoje Ribicic
359 b9e12624 Hrvoje Ribicic
$(buildObject "RpcCallInstanceConsoleInfo" "rpcCallInstConsInfo"
360 b9e12624 Hrvoje Ribicic
  [ simpleField "instanceInfo" [t| [(String, InstanceConsoleInfoParams)] |] ])
361 b9e12624 Hrvoje Ribicic
362 b9e12624 Hrvoje Ribicic
$(buildObject "InstanceConsoleInfo" "instConsInfo"
363 b9e12624 Hrvoje Ribicic
  [ simpleField "instance"    [t| String |]
364 b9e12624 Hrvoje Ribicic
  , simpleField "kind"        [t| String |]
365 b9e12624 Hrvoje Ribicic
  , optionalField $
366 b9e12624 Hrvoje Ribicic
    simpleField "message"     [t| String |]
367 b9e12624 Hrvoje Ribicic
  , optionalField $
368 b9e12624 Hrvoje Ribicic
    simpleField "host"        [t| String |]
369 b9e12624 Hrvoje Ribicic
  , optionalField $
370 b9e12624 Hrvoje Ribicic
    simpleField "port"        [t| Int |]
371 b9e12624 Hrvoje Ribicic
  , optionalField $
372 b9e12624 Hrvoje Ribicic
    simpleField "user"        [t| String |]
373 b9e12624 Hrvoje Ribicic
  , optionalField $
374 b9e12624 Hrvoje Ribicic
    simpleField "command"     [t| [String] |]
375 b9e12624 Hrvoje Ribicic
  , optionalField $
376 b9e12624 Hrvoje Ribicic
    simpleField "display"     [t| String |]
377 b9e12624 Hrvoje Ribicic
  ])
378 b9e12624 Hrvoje Ribicic
379 b9e12624 Hrvoje Ribicic
$(buildObject "RpcResultInstanceConsoleInfo" "rpcResInstConsInfo"
380 b9e12624 Hrvoje Ribicic
  [ simpleField "instancesInfo" [t| [(String, InstanceConsoleInfo)] |] ])
381 b9e12624 Hrvoje Ribicic
382 b9e12624 Hrvoje Ribicic
instance RpcCall RpcCallInstanceConsoleInfo where
383 b9e12624 Hrvoje Ribicic
  rpcCallName _          = "instance_console_info"
384 b9e12624 Hrvoje Ribicic
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
385 b9e12624 Hrvoje Ribicic
  rpcCallAcceptOffline _ = False
386 b9e12624 Hrvoje Ribicic
  rpcCallData _ call     = J.encode .
387 b9e12624 Hrvoje Ribicic
    GenericContainer $ Map.fromList (rpcCallInstConsInfoInstanceInfo call)
388 b9e12624 Hrvoje Ribicic
389 b9e12624 Hrvoje Ribicic
instance Rpc RpcCallInstanceConsoleInfo RpcResultInstanceConsoleInfo where
390 b9e12624 Hrvoje Ribicic
  rpcResultFill _ res =
391 b9e12624 Hrvoje Ribicic
    case res of
392 b9e12624 Hrvoje Ribicic
      J.JSObject res' ->
393 b9e12624 Hrvoje Ribicic
        let res'' = map (second J.readJSON) (J.fromJSObject res')
394 b9e12624 Hrvoje Ribicic
                        :: [(String, J.Result InstanceConsoleInfo)] in
395 b9e12624 Hrvoje Ribicic
        case sanitizeDictResults res'' of
396 b9e12624 Hrvoje Ribicic
          Left err -> Left err
397 b9e12624 Hrvoje Ribicic
          Right instInfos -> Right $ RpcResultInstanceConsoleInfo instInfos
398 b9e12624 Hrvoje Ribicic
      _ -> Left $ JsonDecodeError
399 b9e12624 Hrvoje Ribicic
           ("Expected JSObject, got " ++ show (pp_value res))
400 b9e12624 Hrvoje Ribicic
401 de2a5704 Iustin Pop
-- ** InstanceList
402 de2a5704 Iustin Pop
403 b9e12624 Hrvoje Ribicic
-- | Returns the list of running instances on the given nodes
404 5b11f8db Iustin Pop
$(buildObject "RpcCallInstanceList" "rpcCallInstList"
405 c1c5aab1 Agata Murawska
  [ simpleField "hypervisors" [t| [Hypervisor] |] ])
406 c1c5aab1 Agata Murawska
407 5b11f8db Iustin Pop
$(buildObject "RpcResultInstanceList" "rpcResInstList"
408 9b09c0be Agata Murawska
  [ simpleField "instances" [t| [String] |] ])
409 c1c5aab1 Agata Murawska
410 c1c5aab1 Agata Murawska
instance RpcCall RpcCallInstanceList where
411 274366e5 Agata Murawska
  rpcCallName _          = "instance_list"
412 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
413 c1c5aab1 Agata Murawska
  rpcCallAcceptOffline _ = False
414 274366e5 Agata Murawska
  rpcCallData _ call     = J.encode [rpcCallInstListHypervisors call]
415 c1c5aab1 Agata Murawska
416 47163f0f Agata Murawska
instance Rpc RpcCallInstanceList RpcResultInstanceList where
417 7328a28c Agata Murawska
  rpcResultFill _ res = fromJSValueToRes res RpcResultInstanceList
418 c1c5aab1 Agata Murawska
419 de2a5704 Iustin Pop
-- ** NodeInfo
420 de2a5704 Iustin Pop
421 b9e12624 Hrvoje Ribicic
-- | Returns node information
422 5b11f8db Iustin Pop
$(buildObject "RpcCallNodeInfo" "rpcCallNodeInfo"
423 212b66c3 Helga Velroyen
  [ simpleField "storage_units" [t| Map.Map String [StorageUnit] |]
424 030ab01a Helga Velroyen
  , simpleField "hypervisors" [t| [ (Hypervisor, HvParams) ] |]
425 dc623a95 Agata Murawska
  ])
426 dc623a95 Agata Murawska
427 32389d91 Helga Velroyen
$(buildObject "StorageInfo" "storageInfo"
428 dc623a95 Agata Murawska
  [ simpleField "name" [t| String |]
429 0f0f6d7d Helga Velroyen
  , simpleField "type" [t| String |]
430 32389d91 Helga Velroyen
  , optionalField $ simpleField "storage_free" [t| Int |]
431 32389d91 Helga Velroyen
  , optionalField $ simpleField "storage_size" [t| Int |]
432 dc623a95 Agata Murawska
  ])
433 dc623a95 Agata Murawska
434 dc623a95 Agata Murawska
-- | We only provide common fields as described in hv_base.py.
435 5b11f8db Iustin Pop
$(buildObject "HvInfo" "hvInfo"
436 dc623a95 Agata Murawska
  [ simpleField "memory_total" [t| Int |]
437 dc623a95 Agata Murawska
  , simpleField "memory_free" [t| Int |]
438 dc623a95 Agata Murawska
  , simpleField "memory_dom0" [t| Int |]
439 dc623a95 Agata Murawska
  , simpleField "cpu_total" [t| Int |]
440 dc623a95 Agata Murawska
  , simpleField "cpu_nodes" [t| Int |]
441 dc623a95 Agata Murawska
  , simpleField "cpu_sockets" [t| Int |]
442 f43c898d Bernardo Dal Seno
  , simpleField "cpu_dom0" [t| Int |]
443 dc623a95 Agata Murawska
  ])
444 dc623a95 Agata Murawska
445 5b11f8db Iustin Pop
$(buildObject "RpcResultNodeInfo" "rpcResNodeInfo"
446 dc623a95 Agata Murawska
  [ simpleField "boot_id" [t| String |]
447 32389d91 Helga Velroyen
  , simpleField "storage_info" [t| [StorageInfo] |]
448 dc623a95 Agata Murawska
  , simpleField "hv_info" [t| [HvInfo] |]
449 dc623a95 Agata Murawska
  ])
450 dc623a95 Agata Murawska
451 dc623a95 Agata Murawska
instance RpcCall RpcCallNodeInfo where
452 274366e5 Agata Murawska
  rpcCallName _          = "node_info"
453 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
454 dc623a95 Agata Murawska
  rpcCallAcceptOffline _ = False
455 319322a7 Bernardo Dal Seno
  rpcCallData n call     = J.encode
456 212b66c3 Helga Velroyen
    ( fromMaybe (error $ "Programmer error: missing parameter for node named "
457 319322a7 Bernardo Dal Seno
                         ++ nodeName n)
458 212b66c3 Helga Velroyen
          $ Map.lookup (nodeUuid n) (rpcCallNodeInfoStorageUnits call)
459 212b66c3 Helga Velroyen
    , rpcCallNodeInfoHypervisors call
460 274366e5 Agata Murawska
    )
461 9b09c0be Agata Murawska
462 47163f0f Agata Murawska
instance Rpc RpcCallNodeInfo RpcResultNodeInfo where
463 47163f0f Agata Murawska
  rpcResultFill _ res =
464 7328a28c Agata Murawska
    fromJSValueToRes res (\(b, vg, hv) -> RpcResultNodeInfo b vg hv)
465 dc623a95 Agata Murawska
466 de2a5704 Iustin Pop
-- ** Version
467 de2a5704 Iustin Pop
468 08f7d24d Iustin Pop
-- | Query node version.
469 08f7d24d Iustin Pop
$(buildObject "RpcCallVersion" "rpcCallVersion" [])
470 8779d21a Agata Murawska
471 08f7d24d Iustin Pop
-- | Query node reply.
472 8779d21a Agata Murawska
$(buildObject "RpcResultVersion" "rpcResultVersion"
473 8779d21a Agata Murawska
  [ simpleField "version" [t| Int |]
474 8779d21a Agata Murawska
  ])
475 8779d21a Agata Murawska
476 8779d21a Agata Murawska
instance RpcCall RpcCallVersion where
477 274366e5 Agata Murawska
  rpcCallName _          = "version"
478 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Urgent
479 8779d21a Agata Murawska
  rpcCallAcceptOffline _ = True
480 ff8f0049 Iustin Pop
  rpcCallData _          = J.encode
481 8779d21a Agata Murawska
482 47163f0f Agata Murawska
instance Rpc RpcCallVersion RpcResultVersion where
483 7328a28c Agata Murawska
  rpcResultFill _ res = fromJSValueToRes res RpcResultVersion
484 8779d21a Agata Murawska
485 de2a5704 Iustin Pop
-- ** StorageList
486 de2a5704 Iustin Pop
487 47163f0f Agata Murawska
$(buildObject "RpcCallStorageList" "rpcCallStorageList"
488 47163f0f Agata Murawska
  [ simpleField "su_name" [t| StorageType |]
489 47163f0f Agata Murawska
  , simpleField "su_args" [t| [String] |]
490 47163f0f Agata Murawska
  , simpleField "name"    [t| String |]
491 47163f0f Agata Murawska
  , simpleField "fields"  [t| [StorageField] |]
492 47163f0f Agata Murawska
  ])
493 47163f0f Agata Murawska
494 47163f0f Agata Murawska
-- FIXME: The resulting JSValues should have types appropriate for their
495 47163f0f Agata Murawska
-- StorageField value: Used -> Bool, Name -> String etc
496 47163f0f Agata Murawska
$(buildObject "RpcResultStorageList" "rpcResStorageList"
497 47163f0f Agata Murawska
  [ simpleField "storage" [t| [[(StorageField, J.JSValue)]] |] ])
498 47163f0f Agata Murawska
499 47163f0f Agata Murawska
instance RpcCall RpcCallStorageList where
500 274366e5 Agata Murawska
  rpcCallName _          = "storage_list"
501 274366e5 Agata Murawska
  rpcCallTimeout _       = rpcTimeoutToRaw Normal
502 47163f0f Agata Murawska
  rpcCallAcceptOffline _ = False
503 274366e5 Agata Murawska
  rpcCallData _ call     = J.encode
504 47163f0f Agata Murawska
    ( rpcCallStorageListSuName call
505 47163f0f Agata Murawska
    , rpcCallStorageListSuArgs call
506 47163f0f Agata Murawska
    , rpcCallStorageListName call
507 47163f0f Agata Murawska
    , rpcCallStorageListFields call
508 47163f0f Agata Murawska
    )
509 47163f0f Agata Murawska
510 47163f0f Agata Murawska
instance Rpc RpcCallStorageList RpcResultStorageList where
511 47163f0f Agata Murawska
  rpcResultFill call res =
512 47163f0f Agata Murawska
    let sfields = rpcCallStorageListFields call in
513 7328a28c Agata Murawska
    fromJSValueToRes res (RpcResultStorageList . map (zip sfields))
514 de2a5704 Iustin Pop
515 de2a5704 Iustin Pop
-- ** TestDelay
516 de2a5704 Iustin Pop
517 de2a5704 Iustin Pop
-- | Call definition for test delay.
518 de2a5704 Iustin Pop
$(buildObject "RpcCallTestDelay" "rpcCallTestDelay"
519 de2a5704 Iustin Pop
  [ simpleField "duration" [t| Double |]
520 de2a5704 Iustin Pop
  ])
521 de2a5704 Iustin Pop
522 de2a5704 Iustin Pop
-- | Result definition for test delay.
523 de2a5704 Iustin Pop
data RpcResultTestDelay = RpcResultTestDelay
524 de2a5704 Iustin Pop
                          deriving Show
525 de2a5704 Iustin Pop
526 de2a5704 Iustin Pop
-- | Custom JSON instance for null result.
527 de2a5704 Iustin Pop
instance J.JSON RpcResultTestDelay where
528 de2a5704 Iustin Pop
  showJSON _        = J.JSNull
529 de2a5704 Iustin Pop
  readJSON J.JSNull = return RpcResultTestDelay
530 de2a5704 Iustin Pop
  readJSON _        = fail "Unable to read RpcResultTestDelay"
531 de2a5704 Iustin Pop
532 de2a5704 Iustin Pop
instance RpcCall RpcCallTestDelay where
533 de2a5704 Iustin Pop
  rpcCallName _          = "test_delay"
534 de2a5704 Iustin Pop
  rpcCallTimeout         = ceiling . (+ 5) . rpcCallTestDelayDuration
535 de2a5704 Iustin Pop
  rpcCallAcceptOffline _ = False
536 de2a5704 Iustin Pop
  rpcCallData _ call     = J.encode [rpcCallTestDelayDuration call]
537 de2a5704 Iustin Pop
538 de2a5704 Iustin Pop
instance Rpc RpcCallTestDelay RpcResultTestDelay where
539 de2a5704 Iustin Pop
  rpcResultFill _ res = fromJSValueToRes res id
540 842515dd Iustin Pop
541 842515dd Iustin Pop
-- ** ExportList
542 842515dd Iustin Pop
543 842515dd Iustin Pop
-- | Call definition for export list.
544 842515dd Iustin Pop
545 842515dd Iustin Pop
$(buildObject "RpcCallExportList" "rpcCallExportList" [])
546 842515dd Iustin Pop
547 842515dd Iustin Pop
-- | Result definition for export list.
548 842515dd Iustin Pop
$(buildObject "RpcResultExportList" "rpcResExportList"
549 842515dd Iustin Pop
  [ simpleField "exports" [t| [String] |]
550 842515dd Iustin Pop
  ])
551 842515dd Iustin Pop
552 842515dd Iustin Pop
instance RpcCall RpcCallExportList where
553 842515dd Iustin Pop
  rpcCallName _          = "export_list"
554 842515dd Iustin Pop
  rpcCallTimeout _       = rpcTimeoutToRaw Fast
555 842515dd Iustin Pop
  rpcCallAcceptOffline _ = False
556 842515dd Iustin Pop
  rpcCallData _          = J.encode
557 842515dd Iustin Pop
558 842515dd Iustin Pop
instance Rpc RpcCallExportList RpcResultExportList where
559 842515dd Iustin Pop
  rpcResultFill _ res = fromJSValueToRes res RpcResultExportList
560 a716edba Klaus Aehlig
561 a716edba Klaus Aehlig
-- ** Job Queue Replication
562 a716edba Klaus Aehlig
  
563 a716edba Klaus Aehlig
-- | Update a job queue file
564 a716edba Klaus Aehlig
  
565 a716edba Klaus Aehlig
$(buildObject "RpcCallJobqueueUpdate" "rpcCallJobqueueUpdate"
566 a716edba Klaus Aehlig
  [ simpleField "file_name" [t| String |]
567 a716edba Klaus Aehlig
  , simpleField "content" [t| String |]
568 a716edba Klaus Aehlig
  ])
569 a716edba Klaus Aehlig
570 557f5dad Klaus Aehlig
$(buildObject "RpcResultJobQueueUpdate" "rpcResultJobQueueUpdate" [])
571 557f5dad Klaus Aehlig
572 a716edba Klaus Aehlig
instance RpcCall RpcCallJobqueueUpdate where
573 a716edba Klaus Aehlig
  rpcCallName _          = "jobqueue_update"
574 a716edba Klaus Aehlig
  rpcCallTimeout _       = rpcTimeoutToRaw Fast
575 a716edba Klaus Aehlig
  rpcCallAcceptOffline _ = False
576 a716edba Klaus Aehlig
  rpcCallData _ call     = J.encode
577 a716edba Klaus Aehlig
    ( rpcCallJobqueueUpdateFileName call
578 835050f3 Klaus Aehlig
    , ( C.rpcEncodingZlibBase64
579 835050f3 Klaus Aehlig
      , BL.unpack . Base64.encode . Zlib.compress . BL.pack
580 835050f3 Klaus Aehlig
          $ rpcCallJobqueueUpdateContent call
581 a716edba Klaus Aehlig
      )
582 a716edba Klaus Aehlig
    )
583 a716edba Klaus Aehlig
584 557f5dad Klaus Aehlig
instance Rpc RpcCallJobqueueUpdate RpcResultJobQueueUpdate where
585 a716edba Klaus Aehlig
  rpcResultFill _ res =
586 a716edba Klaus Aehlig
    case res of
587 557f5dad Klaus Aehlig
      J.JSNull ->  Right RpcResultJobQueueUpdate
588 a716edba Klaus Aehlig
      _ -> Left $ JsonDecodeError
589 a716edba Klaus Aehlig
           ("Expected JSNull, got " ++ show (pp_value res))