[Pkg-ganeti-devel] [ganeti] 72/165: Create a monad in which all Metad operations run
Apollon Oikonomopoulos
apoikos at moszumanska.debian.org
Tue Aug 11 13:53:14 UTC 2015
This is an automated email from the git hooks/post-receive script.
apoikos pushed a commit to branch master
in repository ganeti.
commit 6e876afe6eacc9cbb7fd80b22de0145f6eb5bdf1
Author: Petr Pudlak <pudlak at google.com>
Date: Tue Jan 27 15:37:52 2015 +0100
Create a monad in which all Metad operations run
Put the monad, as well as move the current single Metad function into a
new module ConfigCore.
This is the first step towards using our generated RPC client/server
mechanism in Metad, just like we do it with WConfd.
The functionality is not changed.
Signed-off-by: Petr Pudlak <pudlak at google.com>
Reviewed-by: Klaus Aehlig <aehlig at google.com>
---
Makefile.am | 2 +
src/Ganeti/Metad/ConfigCore.hs | 123 +++++++++++++++++++++++++++++++++++++++
src/Ganeti/Metad/ConfigServer.hs | 55 ++++++-----------
3 files changed, 143 insertions(+), 37 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 2be3981..cab7e21 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1027,6 +1027,7 @@ endif
if ENABLE_METADATA
HS_LIB_SRCS += \
src/Ganeti/Metad/Config.hs \
+ src/Ganeti/Metad/ConfigCore.hs \
src/Ganeti/Metad/ConfigServer.hs \
src/Ganeti/Metad/Server.hs \
src/Ganeti/Metad/Types.hs \
@@ -1034,6 +1035,7 @@ HS_LIB_SRCS += \
else
EXTRA_DIST += \
src/Ganeti/Metad/Config.hs \
+ src/Ganeti/Metad/ConfigCore.hs \
src/Ganeti/Metad/ConfigServer.hs \
src/Ganeti/Metad/Server.hs \
src/Ganeti/Metad/Types.hs \
diff --git a/src/Ganeti/Metad/ConfigCore.hs b/src/Ganeti/Metad/ConfigCore.hs
new file mode 100644
index 0000000..6d3295e
--- /dev/null
+++ b/src/Ganeti/Metad/ConfigCore.hs
@@ -0,0 +1,123 @@
+{-# LANGUAGE TupleSections, TemplateHaskell,
+ MultiParamTypeClasses, TypeFamilies, GeneralizedNewtypeDeriving #-}
+{-| Functions of the metadata daemon exported for RPC
+
+-}
+
+{-
+
+Copyright (C) 2014 Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-}
+module Ganeti.Metad.ConfigCore where
+
+import Control.Applicative
+import Control.Concurrent.MVar.Lifted
+import Control.Monad
+import Control.Monad.Base
+import Control.Monad.IO.Class
+import Control.Monad.Reader
+import Control.Monad.Trans.Control
+import Language.Haskell.TH (Name)
+import qualified Text.JSON as J
+
+import Ganeti.BasicTypes
+import Ganeti.Errors
+import qualified Ganeti.JSON as J
+import Ganeti.Logging as L
+import Ganeti.Metad.Config as Config
+import Ganeti.Metad.Types (InstanceParams)
+
+-- * The monad in which all the Metad functions execute
+
+data MetadHandle = MetadHandle
+ { mhInstParams :: MVar InstanceParams
+ }
+
+-- | A type alias for easier referring to the actual content of the monad
+-- when implementing its instances.
+type MetadMonadIntType = ReaderT MetadHandle IO
+
+-- | The internal part of the monad without error handling.
+newtype MetadMonadInt a = MetadMonadInt
+ { getMetadMonadInt :: MetadMonadIntType a }
+ deriving ( Functor, Applicative, Monad, MonadIO, MonadBase IO
+ , L.MonadLog )
+
+instance MonadBaseControl IO MetadMonadInt where
+ newtype StM MetadMonadInt b = StMMetadMonadInt
+ { runStMMetadMonadInt :: StM MetadMonadIntType b }
+ liftBaseWith f = MetadMonadInt . liftBaseWith
+ $ \r -> f (liftM StMMetadMonadInt . r . getMetadMonadInt)
+ restoreM = MetadMonadInt . restoreM . runStMMetadMonadInt
+
+-- | Runs the internal part of the MetadMonad monad on a given daemon
+-- handle.
+runMetadMonadInt :: MetadMonadInt a -> MetadHandle -> IO a
+runMetadMonadInt (MetadMonadInt k) = runReaderT k
+
+-- | The complete monad with error handling.
+type MetadMonad = ResultT GanetiException MetadMonadInt
+
+-- * Basic functions in the monad
+
+metadHandle :: MetadMonad MetadHandle
+metadHandle = lift . MetadMonadInt $ ask
+
+instParams :: MetadMonad InstanceParams
+instParams = readMVar . mhInstParams =<< metadHandle
+
+modifyInstParams :: (InstanceParams -> MetadMonad (InstanceParams, a))
+ -> MetadMonad a
+modifyInstParams f = do
+ h <- metadHandle
+ modifyMVar (mhInstParams h) f
+
+-- * Functions available to the RPC module
+
+-- Just a debugging function
+echo :: String -> MetadMonad String
+echo = return
+
+-- | Update the configuration with the received instance parameters.
+updateConfig :: J.JSValue -> MetadMonad ()
+updateConfig input = do
+ (name, instanceParams) <- J.fromJResultE "Could not get instance parameters"
+ $ Config.getInstanceParams input
+ cfg' <- modifyInstParams $ \cfg ->
+ let cfg' = mergeConfig cfg instanceParams
+ in return (cfg', cfg')
+ L.logInfo $
+ "Updated instance " ++ show name ++ " configuration"
+ L.logDebug $ "Instance configuration: " ++ show cfg'
+
+-- * The list of all functions exported to RPC.
+
+exportedFunctions :: [Name]
+exportedFunctions = [ 'echo
+ , 'updateConfig
+ ]
diff --git a/src/Ganeti/Metad/ConfigServer.hs b/src/Ganeti/Metad/ConfigServer.hs
index fa492f1..1f1cbb3 100644
--- a/src/Ganeti/Metad/ConfigServer.hs
+++ b/src/Ganeti/Metad/ConfigServer.hs
@@ -34,57 +34,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-}
module Ganeti.Metad.ConfigServer where
-import Control.Concurrent
-import Control.Exception (try, finally)
-import Control.Monad (unless)
-import Text.JSON
-import System.IO.Error (isEOFError)
+import Control.Concurrent (forkIO)
+import Control.Concurrent.MVar (MVar)
+import Control.Exception (finally)
+import qualified Text.JSON as J
+import Ganeti.BasicTypes
import Ganeti.Path as Path
import Ganeti.Daemon (DaemonOptions, cleanupSocket, describeError)
+import qualified Ganeti.JSON as J
import qualified Ganeti.Logging as Logging
import Ganeti.Runtime (GanetiDaemon(..))
import Ganeti.UDSServer (Client, ConnectConfig(..), Server, ServerConfig(..))
import qualified Ganeti.UDSServer as UDSServer
-import Ganeti.Metad.Config as Config
+import Ganeti.Metad.ConfigCore
import Ganeti.Metad.Types (InstanceParams)
--- | Update the configuration with the received instance parameters.
-updateConfig :: MVar InstanceParams -> String -> IO ()
-updateConfig config str =
- case decode str of
- Error err ->
- Logging.logDebug $ show err
- Ok x ->
- case Config.getInstanceParams x of
- Error err ->
- Logging.logError $ "Could not get instance parameters: " ++ err
- Ok (name, instanceParams) -> do
- cfg <- takeMVar config
- let cfg' = mergeConfig cfg instanceParams
- putMVar config cfg'
- Logging.logInfo $
- "Updated instance " ++ show name ++ " configuration"
- Logging.logDebug $ "Instance configuration: " ++ show cfg'
-
-- | Reads messages from clients and update the configuration
-- according to these messages.
-acceptConfig :: MVar InstanceParams -> Client -> IO ()
-acceptConfig config client =
- do res <- try $ UDSServer.recvMsg client
- case res of
- Left err -> do
- unless (isEOFError err) .
- Logging.logDebug $ show err
- return ()
- Right str -> do
- Logging.logDebug $ "Received: " ++ str
- updateConfig config str
+acceptConfig :: MetadHandle -> Client -> IO ()
+acceptConfig config client = do
+ result <- runResultT $ do
+ msg <- liftIO $ UDSServer.recvMsg client
+ Logging.logDebug $ "Received: " ++ msg
+ instData <- toErrorStr . J.fromJResultE "Parsing instance data" . J.decode
+ $ msg
+ runMetadMonad (updateConfig instData) config
+ annotateResult "Updating Metad instance configuration" $ withError show result
-- | Loop that accepts clients and dispatches them to an isolated
-- thread that will handle the client's requests.
-acceptClients :: MVar InstanceParams -> Server -> IO ()
+acceptClients :: MetadHandle -> Server -> IO ()
acceptClients config server =
do client <- UDSServer.acceptClient server
_ <- forkIO $ acceptConfig config client
@@ -97,7 +78,7 @@ start _ config = do
server <- describeError "binding to the socket" Nothing (Just socket_path)
$ UDSServer.connectServer metadConfig True socket_path
finally
- (acceptClients config server)
+ (acceptClients (MetadHandle config) server)
(UDSServer.closeServer server)
where
metadConfig = ServerConfig GanetiMetad $ ConnectConfig 60 60
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ganeti/ganeti.git
More information about the Pkg-ganeti-devel
mailing list