Revision 9c0a27d0
b/src/Ganeti/Query/Common.hs | ||
---|---|---|
4 | 4 |
|
5 | 5 |
{- |
6 | 6 |
|
7 |
Copyright (C) 2012 Google Inc. |
|
7 |
Copyright (C) 2012, 2013 Google Inc.
|
|
8 | 8 |
|
9 | 9 |
This program is free software; you can redistribute it and/or modify |
10 | 10 |
it under the terms of the GNU General Public License as published by |
... | ... | |
104 | 104 |
|
105 | 105 |
-- | Convert RpcError to ResultStatus |
106 | 106 |
rpcErrorToStatus :: RpcError -> ResultStatus |
107 |
rpcErrorToStatus (OfflineNodeError _) = RSOffline
|
|
107 |
rpcErrorToStatus OfflineNodeError = RSOffline
|
|
108 | 108 |
rpcErrorToStatus _ = RSNoData |
109 | 109 |
|
110 | 110 |
-- * Common fields |
b/src/Ganeti/Rpc.hs | ||
---|---|---|
98 | 98 |
|
99 | 99 |
-- | Data type for RPC error reporting. |
100 | 100 |
data RpcError |
101 |
= CurlLayerError Node String
|
|
101 |
= CurlLayerError String |
|
102 | 102 |
| JsonDecodeError String |
103 | 103 |
| RpcResultError String |
104 |
| OfflineNodeError Node
|
|
104 |
| OfflineNodeError |
|
105 | 105 |
deriving (Show, Eq) |
106 | 106 |
|
107 | 107 |
-- | Provide explanation to RPC errors. |
108 | 108 |
explainRpcError :: RpcError -> String |
109 |
explainRpcError (CurlLayerError node code) =
|
|
110 |
"Curl error for " ++ nodeName node ++ ", " ++ code
|
|
109 |
explainRpcError (CurlLayerError code) = |
|
110 |
"Curl error:" ++ code
|
|
111 | 111 |
explainRpcError (JsonDecodeError msg) = |
112 | 112 |
"Error while decoding JSON from HTTP response: " ++ msg |
113 | 113 |
explainRpcError (RpcResultError msg) = |
114 | 114 |
"Error reponse received from RPC server: " ++ msg |
115 |
explainRpcError (OfflineNodeError node) =
|
|
116 |
"Node " ++ nodeName node ++ " is marked as offline"
|
|
115 |
explainRpcError OfflineNodeError =
|
|
116 |
"Node is marked offline"
|
|
117 | 117 |
|
118 | 118 |
type ERpcError = Either RpcError |
119 | 119 |
|
... | ... | |
153 | 153 |
|
154 | 154 |
-- | Execute the request and return the result as a plain String. When |
155 | 155 |
-- curl reports an error, we propagate it. |
156 |
executeHttpRequest :: Node -> ERpcError HttpClientRequest |
|
157 |
-> IO (ERpcError String) |
|
158 |
executeHttpRequest _ (Left rpc_err) = return $ Left rpc_err |
|
159 |
executeHttpRequest node (Right request) = do |
|
156 |
executeHttpRequest :: ERpcError HttpClientRequest -> IO (ERpcError String) |
|
157 |
executeHttpRequest (Left rpc_err) = return $ Left rpc_err |
|
158 |
executeHttpRequest (Right request) = do |
|
160 | 159 |
let reqOpts = CurlPostFields [requestData request]:requestOpts request |
161 | 160 |
url = requestUrl request |
162 | 161 |
-- FIXME: This is very similar to getUrl in Htools/Rapi.hs |
163 | 162 |
(code, !body) <- curlGetString url $ curlOpts ++ reqOpts |
164 | 163 |
return $ case code of |
165 | 164 |
CurlOK -> Right body |
166 |
_ -> Left $ CurlLayerError node (show code)
|
|
165 |
_ -> Left $ CurlLayerError (show code) |
|
167 | 166 |
|
168 | 167 |
-- | Prepare url for the HTTP request. |
169 | 168 |
prepareUrl :: (RpcCall a) => Node -> a -> String |
... | ... | |
183 | 182 |
, requestData = rpcCallData node call |
184 | 183 |
, requestOpts = opts ++ curlOpts |
185 | 184 |
} |
186 |
| otherwise = Left $ OfflineNodeError node
|
|
185 |
| otherwise = Left OfflineNodeError
|
|
187 | 186 |
|
188 | 187 |
-- | Parse a result based on the received HTTP response. |
189 | 188 |
parseHttpResponse :: (Rpc a b) => a -> ERpcError String -> ERpcError b |
... | ... | |
201 | 200 |
[CurlOption] -> Node -> a -> IO (Node, ERpcError b) |
202 | 201 |
executeSingleRpcCall opts node call = do |
203 | 202 |
let request = prepareHttpRequest opts node call |
204 |
response <- executeHttpRequest node request
|
|
203 |
response <- executeHttpRequest request |
|
205 | 204 |
let result = parseHttpResponse call response |
206 | 205 |
return (node, result) |
207 | 206 |
|
b/test/hs/Test/Ganeti/Rpc.hs | ||
---|---|---|
7 | 7 |
|
8 | 8 |
{- |
9 | 9 |
|
10 |
Copyright (C) 2009, 2010, 2011, 2012 Google Inc. |
|
10 |
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
|
|
11 | 11 |
|
12 | 12 |
This program is free software; you can redistribute it and/or modify |
13 | 13 |
it under the terms of the GNU General Public License as published by |
... | ... | |
59 | 59 |
prop_noffl_request_allinstinfo call = |
60 | 60 |
forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do |
61 | 61 |
res <- run $ Rpc.executeRpcCall [node] call |
62 |
stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
|
|
62 |
stop $ res ==? [(node, Left Rpc.OfflineNodeError)]
|
|
63 | 63 |
|
64 | 64 |
prop_noffl_request_instlist :: Rpc.RpcCallInstanceList -> Property |
65 | 65 |
prop_noffl_request_instlist call = |
66 | 66 |
forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do |
67 | 67 |
res <- run $ Rpc.executeRpcCall [node] call |
68 |
stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
|
|
68 |
stop $ res ==? [(node, Left Rpc.OfflineNodeError)]
|
|
69 | 69 |
|
70 | 70 |
prop_noffl_request_nodeinfo :: Rpc.RpcCallNodeInfo -> Property |
71 | 71 |
prop_noffl_request_nodeinfo call = |
72 | 72 |
forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do |
73 | 73 |
res <- run $ Rpc.executeRpcCall [node] call |
74 |
stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
|
|
74 |
stop $ res ==? [(node, Left Rpc.OfflineNodeError)]
|
|
75 | 75 |
|
76 | 76 |
testSuite "Rpc" |
77 | 77 |
[ 'prop_noffl_request_allinstinfo |
Also available in: Unified diff