Revision 8920fa09

b/src/Ganeti/Rpc.hs
78 78
import Network.Curl
79 79
import qualified Ganeti.Path as P
80 80

  
81
import Ganeti.BasicTypes
81 82
import qualified Ganeti.Constants as C
82 83
import Ganeti.Objects
83 84
import Ganeti.THH
84 85
import Ganeti.Types
85
import Ganeti.Compat
86
import Ganeti.Curl.Multi
87
import Ganeti.Utils
86 88

  
87 89
-- * Base RPC functionality and types
88 90

  
......
151 153
  , requestOpts :: [CurlOption] -- ^ The various curl options
152 154
  }
153 155

  
154
-- | Execute the request and return the result as a plain String. When
155
-- curl reports an error, we propagate it.
156
executeHttpRequest :: ERpcError HttpClientRequest -> IO (ERpcError String)
157
executeHttpRequest (Left rpc_err) = return $ Left rpc_err
158
executeHttpRequest (Right request) = do
159
  let reqOpts = CurlPostFields [requestData request]:requestOpts request
160
      url = requestUrl request
161
  -- FIXME: This is very similar to getUrl in Htools/Rapi.hs
162
  (code, !body) <- curlGetString url $ curlOpts ++ reqOpts
163
  return $ case code of
164
             CurlOK -> Right body
165
             _ -> Left $ CurlLayerError (show code)
166

  
167 156
-- | Prepare url for the HTTP request.
168 157
prepareUrl :: (RpcCall a) => Node -> a -> String
169 158
prepareUrl node call =
......
184 173
                              }
185 174
  | otherwise = Left OfflineNodeError
186 175

  
176
-- | Parse an HTTP reply.
177
parseHttpReply :: (Rpc a b) =>
178
                  a -> ERpcError (CurlCode, String) -> ERpcError b
179
parseHttpReply _ (Left e) = Left e
180
parseHttpReply call (Right (CurlOK, body)) = parseHttpResponse call body
181
parseHttpReply _ (Right (code, err)) =
182
  Left . CurlLayerError $ "code: " ++ show code ++ ", explanation: " ++ err
183

  
187 184
-- | Parse a result based on the received HTTP response.
188
parseHttpResponse :: (Rpc a b) => a -> ERpcError String -> ERpcError b
189
parseHttpResponse _ (Left err) = Left err
190
parseHttpResponse call (Right res) =
185
parseHttpResponse :: (Rpc a b) => a -> String -> ERpcError b
186
parseHttpResponse call res =
191 187
  case J.decode res of
192 188
    J.Error val -> Left $ JsonDecodeError val
193 189
    J.Ok (True, res'') -> rpcResultFill call res''
......
195 191
       J.JSString msg -> Left $ RpcResultError (J.fromJSString msg)
196 192
       _ -> Left . JsonDecodeError $ show (pp_value jerr)
197 193

  
198
-- | Execute RPC call for a sigle node.
199
executeSingleRpcCall :: (Rpc a b) =>
200
                        [CurlOption] -> Node -> a -> IO (Node, ERpcError b)
201
executeSingleRpcCall opts node call = do
202
  let request = prepareHttpRequest opts node call
203
  response <- executeHttpRequest request
204
  let result = parseHttpResponse call response
205
  return (node, result)
206

  
207 194
-- | Execute RPC call for many nodes in parallel.
208 195
executeRpcCall :: (Rpc a b) => [Node] -> a -> IO [(Node, ERpcError b)]
209 196
executeRpcCall nodes call = do
......
213 200
             , CurlSSLKey cert_file
214 201
             , CurlCAInfo cert_file
215 202
             ]
216
  sequence $ parMap rwhnf (\n -> executeSingleRpcCall opts n call) nodes
203
      opts_urls = map (\n ->
204
                         case prepareHttpRequest opts n call of
205
                           Left v -> Left v
206
                           Right request ->
207
                             Right (CurlPostFields [requestData request]:
208
                                    requestOpts request,
209
                                    requestUrl request)
210
                      ) nodes
211
  -- split the opts_urls list; we don't want to pass the
212
  -- failed-already nodes to Curl
213
  let (lefts, rights, trail) = splitEithers opts_urls
214
  results <- execMultiCall rights
215
  results' <- case recombineEithers lefts results trail of
216
                Bad msg -> error msg
217
                Ok r -> return r
218
  -- now parse the replies
219
  let results'' = map (parseHttpReply call) results'
220
  return $ zip nodes results''
217 221

  
218 222
-- | Helper function that is used to read dictionaries of values.
219 223
sanitizeDictResults :: [(String, J.Result a)] -> ERpcError [(String, a)]

Also available in: Unified diff