Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / WConfd / Monad.hs @ 13d26b66

History | View | Annotate | Download (6 kB)

1 13d26b66 Petr Pudlak
{-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleContexts #-}
2 9515a7d2 Petr Pudlak
3 9515a7d2 Petr Pudlak
{-| All RPC calls are run within this monad.
4 9515a7d2 Petr Pudlak
5 9515a7d2 Petr Pudlak
It encapsulates:
6 9515a7d2 Petr Pudlak
7 9515a7d2 Petr Pudlak
* IO operations,
8 9515a7d2 Petr Pudlak
* failures,
9 9515a7d2 Petr Pudlak
* working with the daemon state,
10 9515a7d2 Petr Pudlak
* working with the client state.
11 9515a7d2 Petr Pudlak
12 9515a7d2 Petr Pudlak
Code that is specific either to the configuration or the lock management, should
13 9515a7d2 Petr Pudlak
go into their corresponding dedicated modules.
14 9515a7d2 Petr Pudlak
-}
15 9515a7d2 Petr Pudlak
16 9515a7d2 Petr Pudlak
{-
17 9515a7d2 Petr Pudlak
18 9515a7d2 Petr Pudlak
Copyright (C) 2014 Google Inc.
19 9515a7d2 Petr Pudlak
20 9515a7d2 Petr Pudlak
This program is free software; you can redistribute it and/or modify
21 9515a7d2 Petr Pudlak
it under the terms of the GNU General Public License as published by
22 9515a7d2 Petr Pudlak
the Free Software Foundation; either version 2 of the License, or
23 9515a7d2 Petr Pudlak
(at your option) any later version.
24 9515a7d2 Petr Pudlak
25 9515a7d2 Petr Pudlak
This program is distributed in the hope that it will be useful, but
26 9515a7d2 Petr Pudlak
WITHOUT ANY WARRANTY; without even the implied warranty of
27 9515a7d2 Petr Pudlak
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28 9515a7d2 Petr Pudlak
General Public License for more details.
29 9515a7d2 Petr Pudlak
30 9515a7d2 Petr Pudlak
You should have received a copy of the GNU General Public License
31 9515a7d2 Petr Pudlak
along with this program; if not, write to the Free Software
32 9515a7d2 Petr Pudlak
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33 9515a7d2 Petr Pudlak
02110-1301, USA.
34 9515a7d2 Petr Pudlak
35 9515a7d2 Petr Pudlak
-}
36 9515a7d2 Petr Pudlak
37 9515a7d2 Petr Pudlak
module Ganeti.WConfd.Monad
38 9515a7d2 Petr Pudlak
  ( DaemonHandle
39 9515a7d2 Petr Pudlak
  , dhConfigPath
40 13d26b66 Petr Pudlak
  , dhSaveConfigWorker
41 9515a7d2 Petr Pudlak
  , mkDaemonHandle
42 9515a7d2 Petr Pudlak
  , ClientState(..)
43 9515a7d2 Petr Pudlak
  , WConfdMonadInt
44 9515a7d2 Petr Pudlak
  , runWConfdMonadInt
45 9515a7d2 Petr Pudlak
  , WConfdMonad
46 13d26b66 Petr Pudlak
  , daemonHandle
47 9515a7d2 Petr Pudlak
  , modifyConfigState
48 13d26b66 Petr Pudlak
  , readConfigState
49 a317d77a Klaus Aehlig
  , modifyLockAllocation
50 9515a7d2 Petr Pudlak
  ) where
51 9515a7d2 Petr Pudlak
52 9515a7d2 Petr Pudlak
import Control.Applicative
53 9515a7d2 Petr Pudlak
import Control.Monad
54 9515a7d2 Petr Pudlak
import Control.Monad.Base
55 9515a7d2 Petr Pudlak
import Control.Monad.Error
56 9515a7d2 Petr Pudlak
import Control.Monad.Trans.Control
57 9515a7d2 Petr Pudlak
import Control.Monad.Trans.RWS.Strict
58 13d26b66 Petr Pudlak
import Data.IORef.Lifted
59 9515a7d2 Petr Pudlak
60 9515a7d2 Petr Pudlak
import Ganeti.BasicTypes
61 9515a7d2 Petr Pudlak
import Ganeti.Errors
62 a317d77a Klaus Aehlig
import Ganeti.Locking.Locks
63 9515a7d2 Petr Pudlak
import Ganeti.Logging
64 9515a7d2 Petr Pudlak
import Ganeti.Types
65 13d26b66 Petr Pudlak
import Ganeti.Utils.AsyncWorker
66 9515a7d2 Petr Pudlak
import Ganeti.WConfd.ConfigState
67 9515a7d2 Petr Pudlak
68 9515a7d2 Petr Pudlak
-- * Pure data types used in the monad
69 9515a7d2 Petr Pudlak
70 9515a7d2 Petr Pudlak
-- | The state of the daemon, capturing both the configuration state and the
71 9515a7d2 Petr Pudlak
-- locking state.
72 9515a7d2 Petr Pudlak
data DaemonState = DaemonState
73 9515a7d2 Petr Pudlak
  { dsConfigState :: ConfigState
74 a317d77a Klaus Aehlig
  , dsLockAllocation :: GanetiLockAllocation
75 9515a7d2 Petr Pudlak
  }
76 9515a7d2 Petr Pudlak
77 9515a7d2 Petr Pudlak
data DaemonHandle = DaemonHandle
78 9515a7d2 Petr Pudlak
  { dhDaemonState :: IORef DaemonState -- ^ The current state of the daemon
79 9515a7d2 Petr Pudlak
  , dhConfigPath :: FilePath           -- ^ The configuration file path
80 9515a7d2 Petr Pudlak
  -- all static information that doesn't change during the life-time of the
81 9515a7d2 Petr Pudlak
  -- daemon should go here;
82 9515a7d2 Petr Pudlak
  -- all IDs of threads that do asynchronous work should probably also go here
83 13d26b66 Petr Pudlak
  , dhSaveConfigWorker :: AsyncWorker ()
84 9515a7d2 Petr Pudlak
  }
85 9515a7d2 Petr Pudlak
86 9515a7d2 Petr Pudlak
mkDaemonHandle :: FilePath
87 9515a7d2 Petr Pudlak
               -> ConfigState
88 a317d77a Klaus Aehlig
               -> GanetiLockAllocation
89 13d26b66 Petr Pudlak
               -> (IO ConfigState -> ResultG (AsyncWorker ()))
90 13d26b66 Petr Pudlak
                  -- ^ A function that creates a worker that asynchronously
91 13d26b66 Petr Pudlak
                  -- saves the configuration to the master file.
92 13d26b66 Petr Pudlak
               -> ResultG DaemonHandle
93 13d26b66 Petr Pudlak
mkDaemonHandle cpath cstat lstat saveWorkerFn = do
94 13d26b66 Petr Pudlak
  ds <- newIORef $ DaemonState cstat lstat
95 13d26b66 Petr Pudlak
  saveWorker <- saveWorkerFn $ dsConfigState `liftM` readIORef ds
96 13d26b66 Petr Pudlak
  return $ DaemonHandle ds cpath saveWorker
97 9515a7d2 Petr Pudlak
98 9515a7d2 Petr Pudlak
data ClientState = ClientState
99 9515a7d2 Petr Pudlak
  { clLiveFilePath :: FilePath
100 9515a7d2 Petr Pudlak
  , clJobId :: JobId
101 9515a7d2 Petr Pudlak
  }
102 9515a7d2 Petr Pudlak
103 9515a7d2 Petr Pudlak
-- * The monad and its instances
104 9515a7d2 Petr Pudlak
105 9515a7d2 Petr Pudlak
-- | A type alias for easier referring to the actual content of the monad
106 9515a7d2 Petr Pudlak
-- when implementing its instances.
107 9515a7d2 Petr Pudlak
type WConfdMonadIntType = RWST DaemonHandle () (Maybe ClientState) IO
108 9515a7d2 Petr Pudlak
109 9515a7d2 Petr Pudlak
-- | The internal part of the monad without error handling.
110 9515a7d2 Petr Pudlak
newtype WConfdMonadInt a = WConfdMonadInt
111 9515a7d2 Petr Pudlak
  { getWConfdMonadInt :: WConfdMonadIntType a }
112 9515a7d2 Petr Pudlak
113 9515a7d2 Petr Pudlak
instance Functor WConfdMonadInt where
114 9515a7d2 Petr Pudlak
  fmap f = WConfdMonadInt . fmap f . getWConfdMonadInt
115 9515a7d2 Petr Pudlak
116 9515a7d2 Petr Pudlak
instance Applicative WConfdMonadInt where
117 9515a7d2 Petr Pudlak
  pure = WConfdMonadInt . pure
118 9515a7d2 Petr Pudlak
  WConfdMonadInt f <*> WConfdMonadInt k = WConfdMonadInt $ f <*> k
119 9515a7d2 Petr Pudlak
120 9515a7d2 Petr Pudlak
instance Monad WConfdMonadInt where
121 9515a7d2 Petr Pudlak
  return = WConfdMonadInt . return
122 9515a7d2 Petr Pudlak
  (WConfdMonadInt k) >>= f = WConfdMonadInt $ k >>= getWConfdMonadInt . f
123 9515a7d2 Petr Pudlak
124 9515a7d2 Petr Pudlak
instance MonadIO WConfdMonadInt where
125 9515a7d2 Petr Pudlak
  liftIO = WConfdMonadInt . liftIO
126 9515a7d2 Petr Pudlak
127 9515a7d2 Petr Pudlak
instance MonadBase IO WConfdMonadInt where
128 9515a7d2 Petr Pudlak
  liftBase = WConfdMonadInt . liftBase
129 9515a7d2 Petr Pudlak
130 9515a7d2 Petr Pudlak
instance MonadBaseControl IO WConfdMonadInt where
131 9515a7d2 Petr Pudlak
  newtype StM WConfdMonadInt b = StMWConfdMonadInt
132 9515a7d2 Petr Pudlak
    { runStMWConfdMonadInt :: StM WConfdMonadIntType b }
133 9515a7d2 Petr Pudlak
  liftBaseWith f = WConfdMonadInt . liftBaseWith
134 9515a7d2 Petr Pudlak
                   $ \r -> f (liftM StMWConfdMonadInt . r . getWConfdMonadInt)
135 9515a7d2 Petr Pudlak
  restoreM = WConfdMonadInt . restoreM . runStMWConfdMonadInt
136 9515a7d2 Petr Pudlak
137 9515a7d2 Petr Pudlak
instance MonadLog WConfdMonadInt where
138 9515a7d2 Petr Pudlak
  logAt p = WConfdMonadInt . logAt p
139 9515a7d2 Petr Pudlak
140 9515a7d2 Petr Pudlak
-- | Runs the internal part of the WConfdMonad monad on a given daemon
141 9515a7d2 Petr Pudlak
-- handle.
142 9515a7d2 Petr Pudlak
runWConfdMonadInt :: WConfdMonadInt a -> DaemonHandle -> IO a
143 9515a7d2 Petr Pudlak
runWConfdMonadInt (WConfdMonadInt k) dhandle =
144 9515a7d2 Petr Pudlak
  liftM fst $ evalRWST k dhandle Nothing
145 9515a7d2 Petr Pudlak
146 9515a7d2 Petr Pudlak
-- | The complete monad with error handling.
147 9515a7d2 Petr Pudlak
type WConfdMonad = ResultT GanetiException WConfdMonadInt
148 9515a7d2 Petr Pudlak
149 9515a7d2 Petr Pudlak
-- * Basic functions in the monad
150 9515a7d2 Petr Pudlak
151 13d26b66 Petr Pudlak
-- | Returns the daemon handle.
152 13d26b66 Petr Pudlak
daemonHandle :: WConfdMonad DaemonHandle
153 13d26b66 Petr Pudlak
daemonHandle = lift . WConfdMonadInt $ ask
154 13d26b66 Petr Pudlak
155 13d26b66 Petr Pudlak
-- | Returns the current configuration, given a handle
156 13d26b66 Petr Pudlak
readConfigState :: WConfdMonad ConfigState
157 13d26b66 Petr Pudlak
readConfigState = liftM dsConfigState . readIORef . dhDaemonState
158 13d26b66 Petr Pudlak
                  =<< daemonHandle
159 13d26b66 Petr Pudlak
160 9515a7d2 Petr Pudlak
-- | Atomically modifies the configuration state in the WConfdMonad.
161 9515a7d2 Petr Pudlak
modifyConfigState :: (ConfigState -> (ConfigState, a)) -> WConfdMonad a
162 9515a7d2 Petr Pudlak
modifyConfigState f = do
163 13d26b66 Petr Pudlak
  dh <- daemonHandle
164 9515a7d2 Petr Pudlak
  -- TODO: Use lenses to modify the daemons state here
165 9515a7d2 Petr Pudlak
  let mf ds = let (cs', r) = f (dsConfigState ds)
166 9515a7d2 Petr Pudlak
              in (ds { dsConfigState = cs' }, r)
167 13d26b66 Petr Pudlak
  r <- atomicModifyIORef (dhDaemonState dh) mf
168 13d26b66 Petr Pudlak
  -- trigger the config. saving worker and wait for it
169 13d26b66 Petr Pudlak
  logDebug "Triggering config write"
170 13d26b66 Petr Pudlak
  liftBase . triggerAndWait . dhSaveConfigWorker $ dh
171 13d26b66 Petr Pudlak
  logDebug "Config write finished"
172 13d26b66 Petr Pudlak
  -- trigger the config. distribution worker asynchronously
173 13d26b66 Petr Pudlak
  -- TODO
174 13d26b66 Petr Pudlak
  return r
175 a317d77a Klaus Aehlig
176 a317d77a Klaus Aehlig
-- | Atomically modifies the lock allocation state in WConfdMonad.
177 a317d77a Klaus Aehlig
modifyLockAllocation :: (GanetiLockAllocation -> (GanetiLockAllocation, a))
178 a317d77a Klaus Aehlig
                     -> WConfdMonad a
179 a317d77a Klaus Aehlig
modifyLockAllocation f = do
180 a317d77a Klaus Aehlig
  dh <- lift . WConfdMonadInt $ ask
181 a317d77a Klaus Aehlig
  let mf ds = let (la', r) = f (dsLockAllocation ds)
182 a317d77a Klaus Aehlig
              in (ds { dsLockAllocation = la' }, r)
183 13d26b66 Petr Pudlak
  atomicModifyIORef (dhDaemonState dh) mf
184 13d26b66 Petr Pudlak
  -- TODO: Trigger the async. lock saving worker