Commit fcbcff1e authored by Klaus Aehlig's avatar Klaus Aehlig

Move master verification to utils collection

...so that it can be used by other daemons as well.
Signed-off-by: default avatarKlaus Aehlig <aehlig@google.com>
Reviewed-by: default avatarPetr Pudlak <pudlak@google.com>
parent 7ec53862
......@@ -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 \
......
{-| 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)
......@@ -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 =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment