LGTM

On Tue, Jun 03, 2014 at 12:33:31PM +0200, 'Klaus Aehlig' via ganeti-devel wrote:
> ...so that it can be used by other daemons as well.
> 
> Signed-off-by: Klaus Aehlig <[email protected]>
> ---
>  Makefile.am                |  2 ++
>  src/Ganeti/Daemon/Utils.hs | 85 
> ++++++++++++++++++++++++++++++++++++++++++++++
>  src/Ganeti/Query/Server.hs | 49 ++------------------------
>  3 files changed, 89 insertions(+), 47 deletions(-)
>  create mode 100644 src/Ganeti/Daemon/Utils.hs
> 
> diff --git a/Makefile.am b/Makefile.am
> index 10d8d27..ebd729b 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -122,6 +122,7 @@ HS_DIRS = \
>       src/Ganeti/Curl \
>       src/Ganeti/Cpu \
>       src/Ganeti/DataCollectors \
> +     src/Ganeti/Daemon \
>       src/Ganeti/Hs2Py \
>       src/Ganeti/HTools \
>       src/Ganeti/HTools/Backend \
> @@ -749,6 +750,7 @@ HS_LIB_SRCS = \
>       src/Ganeti/Cpu/Types.hs \
>       src/Ganeti/Curl/Multi.hs \
>       src/Ganeti/Daemon.hs \
> +     src/Ganeti/Daemon/Utils.hs \
>       src/Ganeti/DataCollectors/CLI.hs \
>       src/Ganeti/DataCollectors/CPUload.hs \
>       src/Ganeti/DataCollectors/Diskstats.hs \
> diff --git a/src/Ganeti/Daemon/Utils.hs b/src/Ganeti/Daemon/Utils.hs
> new file mode 100644
> index 0000000..1f86e51
> --- /dev/null
> +++ b/src/Ganeti/Daemon/Utils.hs
> @@ -0,0 +1,85 @@
> +{-| Utility functions for complex operations carried out by several daemons.
> +
> +-}
> +
> +{-
> +
> +Copyright (C) 2014 Google Inc.
> +
> +This program is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 2 of the License, or
> +(at your option) any later version.
> +
> +This program is distributed in the hope that it will be useful, but
> +WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with this program; if not, write to the Free Software
> +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> +02110-1301, USA.
> +
> +-}
> +
> +module Ganeti.Daemon.Utils
> +  ( verifyMaster
> +  ) where
> +
> +import Control.Concurrent (threadDelay)
> +import Control.Monad (unless)
> +import Data.Either (rights)
> +import qualified Data.Foldable as F
> +import Data.List (partition)
> +
> +import Ganeti.BasicTypes
> +import qualified Ganeti.Config as Config
> +import qualified Ganeti.Constants as C
> +import Ganeti.Daemon (getFQDN)
> +import Ganeti.Logging
> +import Ganeti.Objects
> +import qualified Ganeti.Path as Path
> +import Ganeti.Rpc
> +
> +-- | Gather votes from all nodes and verify that we we are
> +-- the master. Return True if the voting is won, False if
> +-- not enough
> +verifyMasterVotes :: IO (Result Bool)
> +verifyMasterVotes = runResultT $ do
> +  liftIO $ logDebug "Gathering votes for the master node"
> +  myName <- liftIO getFQDN
> +  liftIO . logDebug $ "My hostname is " ++ myName
> +  conf_file <- liftIO Path.clusterConfFile
> +  config <- mkResultT $ Config.loadConfig conf_file
> +  let nodes = F.toList $ configNodes config
> +  votes <- liftIO . executeRpcCall nodes $ RpcCallMasterNodeName
> +  let (missing, valid) = partition (isLeft . snd) votes
> +      noDataNodes = map (nodeName . fst) missing
> +      validVotes = map rpcResultMasterNodeNameMaster . rights $ map snd valid
> +      inFavor = length $ filter (== myName) validVotes
> +      voters = length nodes
> +      unknown = length missing
> +  liftIO . unless (null noDataNodes) . logWarning
> +    . (++) "No voting RPC result from " $ show noDataNodes
> +  liftIO . logDebug . (++) "Valid votes: " $ show validVotes
> +  if 2 * inFavor > voters
> +    then return True
> +    else if 2 * (inFavor + unknown) > voters
> +           then return False
> +           else fail $ "Voting cannot be won by " ++ myName
> +                       ++ ", valid votes of " ++ show voters
> +                       ++ " are " ++ show validVotes
> +
> +-- | Verify, by voting, that this node is the master. Bad if we're not.
> +-- Allow the given number of retries to wait for not available nodes.
> +verifyMaster :: Int -> IO (Result ())
> +verifyMaster retries = runResultT $ do
> +  won <- mkResultT verifyMasterVotes
> +  unless won $
> +    if retries <= 0
> +      then fail "Couldn't gather voting results of enough nodes"
> +      else do
> +        liftIO $ logDebug "Voting not final due to missing votes."
> +        liftIO . threadDelay $ C.masterVotingRetryIntervall * 1000000
> +        mkResultT $ verifyMaster (retries - 1)
> diff --git a/src/Ganeti/Query/Server.hs b/src/Ganeti/Query/Server.hs
> index bf7ee97..70b1574 100644
> --- a/src/Ganeti/Query/Server.hs
> +++ b/src/Ganeti/Query/Server.hs
> @@ -32,17 +32,13 @@ module Ganeti.Query.Server
>  import Control.Applicative
>  import Control.Concurrent
>  import Control.Exception
> -import Control.Monad (forever, when, mzero, guard, zipWithM, liftM, void,
> -                      unless)
> +import Control.Monad (forever, when, mzero, guard, zipWithM, liftM, void)
>  import Control.Monad.IO.Class
>  import Control.Monad.Trans (lift)
>  import Control.Monad.Trans.Maybe
>  import Data.Bits (bitSize)
> -import Data.Either (rights)
> -import qualified Data.Foldable as F
>  import qualified Data.Set as Set (toList)
>  import Data.IORef
> -import Data.List (partition)
>  import Data.Maybe (fromMaybe)
>  import qualified Text.JSON as J
>  import Text.JSON (encode, showJSON, JSValue(..))
> @@ -56,6 +52,7 @@ import qualified Ganeti.ConstantUtils as ConstantUtils 
> (unFrozenSet)
>  import Ganeti.Errors
>  import qualified Ganeti.Path as Path
>  import Ganeti.Daemon
> +import Ganeti.Daemon.Utils (verifyMaster)
>  import Ganeti.Objects
>  import qualified Ganeti.Config as Config
>  import Ganeti.ConfigReader
> @@ -450,48 +447,6 @@ activateMasterIP = runResultT $ do
>    liftIO $ logDebug "finished activating master IP address"
>    return ()
>  
> --- | Gather votes from all nodes and verify that we we are
> --- the master. Return True if the voting is won, False if
> --- not enough
> -verifyMasterVotes :: IO (Result Bool)
> -verifyMasterVotes = runResultT $ do
> -  liftIO $ logDebug "Gathering votes for the master node"
> -  myName <- liftIO getFQDN
> -  liftIO . logDebug $ "My hostname is " ++ myName
> -  conf_file <- liftIO Path.clusterConfFile
> -  config <- mkResultT $ Config.loadConfig conf_file
> -  let nodes = F.toList $ configNodes config
> -  votes <- liftIO . executeRpcCall nodes $ RpcCallMasterNodeName
> -  let (missing, valid) = partition (isLeft . snd) votes
> -      noDataNodes = map (nodeName . fst) missing
> -      validVotes = map rpcResultMasterNodeNameMaster . rights $ map snd valid
> -      inFavor = length $ filter (== myName) validVotes
> -      voters = length nodes
> -      unknown = length missing
> -  liftIO . unless (null noDataNodes) . logWarning
> -    . (++) "No voting RPC result from " $ show noDataNodes
> -  liftIO . logDebug . (++) "Valid votes: " $ show validVotes
> -  if 2 * inFavor > voters
> -    then return True
> -    else if 2 * (inFavor + unknown) > voters
> -           then return False
> -           else fail $ "Voting cannot be won by " ++ myName
> -                       ++ ", valid votes of " ++ show voters
> -                       ++ " are " ++ show validVotes
> -
> --- | Verify, by voting, that this node is the master. Bad if we're not.
> --- Allow the given number of retries to wait for not available nodes.
> -verifyMaster :: Int -> IO (Result ())
> -verifyMaster retries = runResultT $ do
> -  won <- mkResultT verifyMasterVotes
> -  unless won $
> -    if retries <= 0
> -      then fail "Couldn't gather voting results of enough nodes"
> -      else do
> -        liftIO $ logDebug "Voting not final due to missing votes."
> -        liftIO . threadDelay $ C.masterVotingRetryIntervall * 1000000
> -        mkResultT $ verifyMaster (retries - 1)
> -
>  -- | Check function for luxid.
>  checkMain :: CheckFn ()
>  checkMain opts =
> -- 
> 1.9.1.423.g4596e3a
> 

Reply via email to