From 85f6a86979cf5eb87c8d95a71506bc70255ebd80 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Fri, 30 Nov 2012 02:36:57 +0100
Subject: [PATCH] Reduce duplication of curl options computation

Some curl option are request-specific, but not node specific: e.g. rpc
timeout, etc. The patch changes the HttpClientRequest type so that we
can pre-seed such options, instead of rebuilding the list in each
individual request execution.

Note: this was sent before and LGTMed, but on a different codebase, so
resending an updated version.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Michele Tartara <mtartara@google.com>
---
 src/Ganeti/Rpc.hs | 43 +++++++++++++++++++++----------------------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/src/Ganeti/Rpc.hs b/src/Ganeti/Rpc.hs
index 2eabd3679..5aa240b1b 100644
--- a/src/Ganeti/Rpc.hs
+++ b/src/Ganeti/Rpc.hs
@@ -146,25 +146,18 @@ class (RpcCall a, J.JSON b) => Rpc a b  | a -> b, b -> a where
 
 -- | Http Request definition.
 data HttpClientRequest = HttpClientRequest
-  { requestTimeout :: Int
-  , requestUrl :: String
-  , requestPostData :: String
+  { requestUrl  :: String       -- ^ The actual URL for the node endpoint
+  , requestData :: String       -- ^ The arguments for the call
+  , requestOpts :: [CurlOption] -- ^ The various curl options
   }
 
 -- | Execute the request and return the result as a plain String. When
 -- curl reports an error, we propagate it.
 executeHttpRequest :: Node -> ERpcError HttpClientRequest
                    -> IO (ERpcError String)
-
 executeHttpRequest _ (Left rpc_err) = return $ Left rpc_err
 executeHttpRequest node (Right request) = do
-  cert_file <- P.nodedCertFile
-  let reqOpts = [ CurlTimeout (fromIntegral $ requestTimeout request)
-                , CurlPostFields [requestPostData request]
-                , CurlSSLCert cert_file
-                , CurlSSLKey cert_file
-                , CurlCAInfo cert_file
-                ]
+  let reqOpts = CurlPostFields [requestData request]:requestOpts request
       url = requestUrl request
   -- FIXME: This is very similar to getUrl in Htools/Rapi.hs
   (code, !body) <- curlGetString url $ curlOpts ++ reqOpts
@@ -182,13 +175,13 @@ prepareUrl node call =
 
 -- | Create HTTP request for a given node provided it is online,
 -- otherwise create empty response.
-prepareHttpRequest ::  (RpcCall a) => Node -> a
+prepareHttpRequest :: (RpcCall a) => [CurlOption] -> Node -> a
                    -> ERpcError HttpClientRequest
-prepareHttpRequest node call
+prepareHttpRequest opts node call
   | rpcCallAcceptOffline call || not (nodeOffline node) =
-      Right HttpClientRequest { requestTimeout = rpcCallTimeout call
-                              , requestUrl = prepareUrl node call
-                              , requestPostData = rpcCallData node call
+      Right HttpClientRequest { requestUrl  = prepareUrl node call
+                              , requestData = rpcCallData node call
+                              , requestOpts = opts ++ curlOpts
                               }
   | otherwise = Left $ OfflineNodeError node
 
@@ -204,18 +197,24 @@ parseHttpResponse call (Right res) =
        _ -> Left . JsonDecodeError $ show (pp_value jerr)
 
 -- | Execute RPC call for a sigle node.
-executeSingleRpcCall :: (Rpc a b) => Node -> a -> IO (Node, ERpcError b)
-executeSingleRpcCall node call = do
-  let request = prepareHttpRequest node call
+executeSingleRpcCall :: (Rpc a b) =>
+                        [CurlOption] -> Node -> a -> IO (Node, ERpcError b)
+executeSingleRpcCall opts node call = do
+  let request = prepareHttpRequest opts node call
   response <- executeHttpRequest node request
   let result = parseHttpResponse call response
   return (node, result)
 
 -- | Execute RPC call for many nodes in parallel.
 executeRpcCall :: (Rpc a b) => [Node] -> a -> IO [(Node, ERpcError b)]
-executeRpcCall nodes call =
-  sequence $ parMap rwhnf (uncurry executeSingleRpcCall)
-               (zip nodes $ repeat call)
+executeRpcCall nodes call = do
+  cert_file <- P.nodedCertFile
+  let opts = [ CurlTimeout (fromIntegral $ rpcCallTimeout call)
+             , CurlSSLCert cert_file
+             , CurlSSLKey cert_file
+             , CurlCAInfo cert_file
+             ]
+  sequence $ parMap rwhnf (\n -> executeSingleRpcCall opts n call) nodes
 
 -- | Helper function that is used to read dictionaries of values.
 sanitizeDictResults :: [(String, J.Result a)] -> ERpcError [(String, a)]
-- 
GitLab